Skip to content

Commit

Permalink
add say exercise (#425)
Browse files Browse the repository at this point in the history
  • Loading branch information
kmarker1101 authored Jun 28, 2024
1 parent 03bbe90 commit 0bd76f9
Show file tree
Hide file tree
Showing 7 changed files with 304 additions and 1 deletion.
10 changes: 9 additions & 1 deletion config.json
Original file line number Diff line number Diff line change
Expand Up @@ -902,6 +902,14 @@
"practices": [],
"prerequisites": [],
"difficulty": 2
},
{
"slug": "say",
"name": "Say",
"uuid": "7a6c586a-c8fa-4313-8036-5ff21097702c",
"practices": [],
"prerequisites": [],
"difficulty": 5
}
]
},
Expand Down Expand Up @@ -948,4 +956,4 @@
"typing/strong",
"used_for/scripts"
]
}
}
48 changes: 48 additions & 0 deletions exercises/practice/say/.docs/instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Instructions

Given a number from 0 to 999,999,999,999, spell out that number in English.

## Step 1

Handle the basic case of 0 through 99.

If the input to the program is `22`, then the output should be `'twenty-two'`.

Your program should complain loudly if given a number outside the blessed range.

Some good test cases for this program are:

- 0
- 14
- 50
- 98
- -1
- 100

### Extension

If you're on a Mac, shell out to Mac OS X's `say` program to talk out loud.
If you're on Linux or Windows, eSpeakNG may be available with the command `espeak`.

## Step 2

Implement breaking a number up into chunks of thousands.

So `1234567890` should yield a list like 1, 234, 567, and 890, while the far simpler `1000` should yield just 1 and 0.

## Step 3

Now handle inserting the appropriate scale word between those chunks.

So `1234567890` should yield `'1 billion 234 million 567 thousand 890'`

The program must also report any values that are out of range.
It's fine to stop at "trillion".

## Step 4

Put it all together to get nothing but plain English.

`12345` should give `twelve thousand three hundred forty-five`.

The program must also report any values that are out of range.
19 changes: 19 additions & 0 deletions exercises/practice/say/.meta/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"authors": [
"kmarker1101"
],
"files": {
"solution": [
"say.el"
],
"test": [
"say-test.el"
],
"example": [
".meta/example.el"
]
},
"blurb": "Given a number from 0 to 999,999,999,999, spell out that number in English.",
"source": "A variation on the JavaRanch CattleDrive, Assignment 4",
"source_url": "https://coderanch.com/wiki/718804"
}
54 changes: 54 additions & 0 deletions exercises/practice/say/.meta/example.el
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
;;; say.el --- Say (exercism) -*- lexical-binding: t; -*-

;;; Commentary:

;;; Code:

(define-error 'out-of-range "input out of range")

(defun say (number)
(when (or (< number 0) (>= number (expt 10 12)))
(signal 'out-of-range 'nil))
(let ((ones '("zero" "one" "two" "three" "four" "five" "six" "seven" "eight" "nine"))
(teens '("ten" "eleven" "twelve" "thirteen" "fourteen" "fifteen" "sixteen" "seventeen" "eighteen" "nineteen"))
(tens '("" "" "twenty" "thirty" "forty" "fifty" "sixty" "seventy" "eighty" "ninety"))
(powers '("" "thousand" "million" "billion")))

(defun number-to-words (n)
(let ((parts '()))
(while (> n 0)
(let* ((power (if (> n 999999999) 3 (if (> n 999999) 2 (if (> n 999) 1 0))))
(unit (expt 1000 power))
(quotient (/ n unit))
(remainder (% n unit)))
(if (> quotient 0)
(push (concat (number-to-words-1000 quotient) (if (> power 0) (concat " " (nth power powers)) "")) parts))
(setq n remainder)))
(string-join (reverse parts) " ")))

(defun number-to-words-1000 (n)
(cond
((< n 10) (nth n ones))
((< n 20) (nth (- n 10) teens))
((< n 100)
(let ((ten (nth (/ n 10) tens))
(one (nth (% n 10) ones)))
(if (= (% n 10) 0)
ten
(concat ten "-" one))))
((< n 1000)
(let ((hundred (nth (/ n 100) ones))
(remainder (% n 100)))
(if (= remainder 0)
(concat hundred " hundred")
(concat hundred " hundred " (number-to-words-1000 remainder)))))))

(when (and (>= number 0) (< number (expt 10 12)))
(if (= number 0)
"zero"
(string-trim (number-to-words number))))))


(provide 'say)
;;; say.el ends here

67 changes: 67 additions & 0 deletions exercises/practice/say/.meta/tests.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# This is an auto-generated file.
#
# Regenerating this file via `configlet sync` will:
# - Recreate every `description` key/value pair
# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications
# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion)
# - Preserve any other key/value pair
#
# As user-added comments (using the # character) will be removed when this file
# is regenerated, comments can be added via a `comment` key.

[5d22a120-ba0c-428c-bd25-8682235d83e8]
description = "zero"

[9b5eed77-dbf6-439d-b920-3f7eb58928f6]
description = "one"

[7c499be1-612e-4096-a5e1-43b2f719406d]
description = "fourteen"

[f541dd8e-f070-4329-92b4-b7ce2fcf06b4]
description = "twenty"

[d78601eb-4a84-4bfa-bf0e-665aeb8abe94]
description = "twenty-two"

[f010d4ca-12c9-44e9-803a-27789841adb1]
description = "thirty"

[738ce12d-ee5c-4dfb-ad26-534753a98327]
description = "ninety-nine"

[e417d452-129e-4056-bd5b-6eb1df334dce]
description = "one hundred"

[d6924f30-80ba-4597-acf6-ea3f16269da8]
description = "one hundred twenty-three"

[2f061132-54bc-4fd4-b5df-0a3b778959b9]
description = "two hundred"

[feed6627-5387-4d38-9692-87c0dbc55c33]
description = "nine hundred ninety-nine"

[3d83da89-a372-46d3-b10d-de0c792432b3]
description = "one thousand"

[865af898-1d5b-495f-8ff0-2f06d3c73709]
description = "one thousand two hundred thirty-four"

[b6a3f442-266e-47a3-835d-7f8a35f6cf7f]
description = "one million"

[2cea9303-e77e-4212-b8ff-c39f1978fc70]
description = "one million two thousand three hundred forty-five"

[3e240eeb-f564-4b80-9421-db123f66a38f]
description = "one billion"

[9a43fed1-c875-4710-8286-5065d73b8a9e]
description = "a big number"

[49a6a17b-084e-423e-994d-a87c0ecc05ef]
description = "numbers below zero are out of range"

[4d6492eb-5853-4d16-9d34-b0f61b261fd9]
description = "numbers above 999,999,999,999 are out of range"
89 changes: 89 additions & 0 deletions exercises/practice/say/say-test.el
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
;;; say-test.el --- Say (exercism) -*- lexical-binding: t; -*-

;;; Commentary:

;;; Code:


(load-file "say.el")
(declare-function say "say.el" (number))


(ert-deftest zero ()
(should (string= (say 0) "zero")))


(ert-deftest one ()
(should (string= (say 1) "one")))


(ert-deftest fourteen ()
(should (string= (say 14) "fourteen")))


(ert-deftest twenty ()
(should (string= (say 20) "twenty")))


(ert-deftest twenty-two ()
(should (string= (say 22) "twenty-two")))


(ert-deftest thirty ()
(should (string= (say 30) "thirty")))


(ert-deftest ninety-nine ()
(should (string= (say 99) "ninety-nine")))


(ert-deftest one-hundred ()
(should (string= (say 100) "one hundred")))


(ert-deftest one-hundred-twenty-three ()
(should (string= (say 123) "one hundred twenty-three")))


(ert-deftest two-hundred ()
(should (string= (say 200) "two hundred")))


(ert-deftest nine-hundred-ninety-nine ()
(should (string= (say 999) "nine hundred ninety-nine")))


(ert-deftest one-thousand ()
(should (string= (say 1000) "one thousand")))


(ert-deftest one-thousand-two-hundred-thirty-four ()
(should (string= (say 1234) "one thousand two hundred thirty-four")))


(ert-deftest one-million ()
(should (string= (say 1000000) "one million")))


(ert-deftest one-million-two-thousand-three-hundred-forty-five ()
(should (string= (say 1002345) "one million two thousand three hundred forty-five")))


(ert-deftest one-billion ()
(should (string= (say 1000000000) "one billion")))


(ert-deftest a-big-number ()
(should (string= (say 987654321123) "nine hundred eighty-seven billion six hundred fifty-four million three hundred twenty-one thousand one hundred twenty-three")))


(ert-deftest numbers-below-zero-are-out-of-range ()
(should-error (say -1) :type 'out-of-range))


(ert-deftest numbers-above-999999999999-are-out-of-range ()
(should-error (say 1000000000000) :type 'out-of-range))


(provide 'say-test)
;;; say-test.el ends here
18 changes: 18 additions & 0 deletions exercises/practice/say/say.el
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
;;; say.el --- Say (exercism) -*- lexical-binding: t; -*-

;;; Commentary:

;;; Code:


(define-error 'out-of-range
(error "Delete this S-Expression and write your own implementation"))


(defun say (number)
(error "Delete this S-Expression and write your own implementation"))


(provide 'say)
;;; say.el ends here

0 comments on commit 0bd76f9

Please sign in to comment.