diff --git a/config.json b/config.json index bc26cbe..1a6f661 100644 --- a/config.json +++ b/config.json @@ -902,6 +902,14 @@ "practices": [], "prerequisites": [], "difficulty": 2 + }, + { + "slug": "say", + "name": "Say", + "uuid": "7a6c586a-c8fa-4313-8036-5ff21097702c", + "practices": [], + "prerequisites": [], + "difficulty": 5 } ] }, @@ -948,4 +956,4 @@ "typing/strong", "used_for/scripts" ] -} +} \ No newline at end of file diff --git a/exercises/practice/say/.docs/instructions.md b/exercises/practice/say/.docs/instructions.md new file mode 100644 index 0000000..ad3d347 --- /dev/null +++ b/exercises/practice/say/.docs/instructions.md @@ -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. diff --git a/exercises/practice/say/.meta/config.json b/exercises/practice/say/.meta/config.json new file mode 100644 index 0000000..2a649de --- /dev/null +++ b/exercises/practice/say/.meta/config.json @@ -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" +} diff --git a/exercises/practice/say/.meta/example.el b/exercises/practice/say/.meta/example.el new file mode 100644 index 0000000..8b560a9 --- /dev/null +++ b/exercises/practice/say/.meta/example.el @@ -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 + diff --git a/exercises/practice/say/.meta/tests.toml b/exercises/practice/say/.meta/tests.toml new file mode 100644 index 0000000..a5532e9 --- /dev/null +++ b/exercises/practice/say/.meta/tests.toml @@ -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" diff --git a/exercises/practice/say/say-test.el b/exercises/practice/say/say-test.el new file mode 100644 index 0000000..3677082 --- /dev/null +++ b/exercises/practice/say/say-test.el @@ -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 diff --git a/exercises/practice/say/say.el b/exercises/practice/say/say.el new file mode 100644 index 0000000..8c8e316 --- /dev/null +++ b/exercises/practice/say/say.el @@ -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 +