diff --git a/config.json b/config.json index 8e4aa5a..c0956da 100644 --- a/config.json +++ b/config.json @@ -758,6 +758,14 @@ "prerequisites": [], "difficulty": 5 }, + { + "slug": "say", + "name": "Say", + "uuid": "fe349bef-fa91-439a-bed2-1ac12c4ad5d1", + "practices": [], + "prerequisites": [], + "difficulty": 5 + }, { "slug": "simple-linked-list", "name": "Simple Linked List", diff --git a/exercises/practice/say/.docs/instructions.md b/exercises/practice/say/.docs/instructions.md new file mode 100644 index 0000000..3251c51 --- /dev/null +++ b/exercises/practice/say/.docs/instructions.md @@ -0,0 +1,12 @@ +# Instructions + +Given a number, your task is to express it in English words exactly as your friend should say it out loud. +Yaʻqūb expects to use numbers from 0 up to 999,999,999,999. + +Examples: + +- 0 → zero +- 1 → one +- 12 → twelve +- 123 → one hundred twenty-three +- 1,234 → one thousand two hundred thirty-four diff --git a/exercises/practice/say/.docs/introduction.md b/exercises/practice/say/.docs/introduction.md new file mode 100644 index 0000000..abd2285 --- /dev/null +++ b/exercises/practice/say/.docs/introduction.md @@ -0,0 +1,6 @@ +# Introduction + +Your friend Yaʻqūb works the counter at the busiest deli in town, slicing, weighing, and wrapping orders for a never-ending line of hungry customers. +To keep things moving, each customer takes a numbered ticket when they arrive. + +When it’s time to call the next person, Yaʻqūb reads their number out loud, always in full English words to make sure everyone hears it clearly. diff --git a/exercises/practice/say/.meta/config.json b/exercises/practice/say/.meta/config.json new file mode 100644 index 0000000..18cdf25 --- /dev/null +++ b/exercises/practice/say/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "BNAndras" + ], + "files": { + "solution": [ + "say.vim" + ], + "test": [ + "say.vader" + ], + "example": [ + ".meta/example.vim" + ] + }, + "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://web.archive.org/web/20240907035912/https://coderanch.com/wiki/718804" +} diff --git a/exercises/practice/say/.meta/example.vim b/exercises/practice/say/.meta/example.vim new file mode 100644 index 0000000..cbf5112 --- /dev/null +++ b/exercises/practice/say/.meta/example.vim @@ -0,0 +1,78 @@ +function! Say(number) abort + if a:number < 0 || a:number > 999999999999 + throw 'input out of range' + endif + + if a:number == 0 + return 'zero' + endif + + let l:chunks = s:ChunksReversed(a:number) + let l:fragments = map(l:chunks, function('s:ToWords')) + let l:fragments = map(l:fragments, function('s:ApplyScale')) + let l:fragments = filter(l:fragments, '!empty(v:val)') + call reverse(l:fragments) + return join(l:fragments, ' ') +endfunction + +function! s:ApplyScale(index, value) abort + if empty(a:value) + return + endif + + if !a:index + return a:value + elseif a:index == 1 + return a:value . ' thousand' + elseif a:index == 2 + return a:value . ' million' + elseif a:index == 3 + return a:value . ' billion' + endif +endfunction + +function! s:ChunksReversed(str) abort + let l:result = [] + let l:working = a:str + + while len(l:working) > 0 + call add(l:result, l:working[-3:]) + let l:working = l:working[:-4] + endwhile + + return l:result +endfunction + +function! s:ToWords(index, chunk) + let l:words = [] + if a:chunk < 20 + call add(l:words, s:FirstTwentyNumbers[a:chunk]) + elseif a:chunk < 100 + let l:tens = s:WordsForTens[a:chunk / 10] + let l:ones = s:FirstTwentyNumbers[a:chunk % 10] + if !empty(l:ones) + call add(l:words, l:tens . '-' . l:ones) + else + call add(l:words, l:tens) + endif + else + let l:hundreds = s:FirstTwentyNumbers[a:chunk / 100] + let l:rest = s:ToWords(a:index, a:chunk % 100) + if !empty(l:rest) + call add(l:words, l:hundreds . ' hundred ' . l:rest) + else + call add(l:words, l:hundreds . ' hundred') + endif + endif + + return join(l:words, ' ') +endfunction + +let s:FirstTwentyNumbers = [ +\ '','one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'ten', +\ 'eleven', 'twelve', 'thirteen', 'fourteen', 'fifteen', 'sixteen', 'seventeen', 'eighteen', 'nineteen' +\ ] + +let s:WordsForTens = [ +\ '', 'tens', 'twenty', 'thirty', 'forty', 'fifty', 'sixty', 'seventy', 'eighty', 'ninety' +\ ] 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.vader b/exercises/practice/say/say.vader new file mode 100644 index 0000000..61b7f28 --- /dev/null +++ b/exercises/practice/say/say.vader @@ -0,0 +1,96 @@ +Execute (zero): + let g:number = 0 + let g:expected = "zero" + AssertEqual g:expected, Say(g:number) + +Execute (one): + let g:number = 1 + let g:expected = "one" + AssertEqual g:expected, Say(g:number) + +Execute (fourteen): + let g:number = 14 + let g:expected = "fourteen" + AssertEqual g:expected, Say(g:number) + +Execute (twenty): + let g:number = 20 + let g:expected = "twenty" + AssertEqual g:expected, Say(g:number) + +Execute (twenty-two): + let g:number = 22 + let g:expected = "twenty-two" + AssertEqual g:expected, Say(g:number) + +Execute (thirty): + let g:number = 30 + let g:expected = "thirty" + AssertEqual g:expected, Say(g:number) + +Execute (ninety-nine): + let g:number = 99 + let g:expected = "ninety-nine" + AssertEqual g:expected, Say(g:number) + +Execute (one hundred): + let g:number = 100 + let g:expected = "one hundred" + AssertEqual g:expected, Say(g:number) + +Execute (one hundred twenty-three): + let g:number = 123 + let g:expected = "one hundred twenty-three" + AssertEqual g:expected, Say(g:number) + +Execute (two hundred): + let g:number = 200 + let g:expected = "two hundred" + AssertEqual g:expected, Say(g:number) + +Execute (nine hundred ninety-nine): + let g:number = 999 + let g:expected = "nine hundred ninety-nine" + AssertEqual g:expected, Say(g:number) + +Execute (one thousand): + let g:number = 1000 + let g:expected = "one thousand" + AssertEqual g:expected, Say(g:number) + +Execute (one thousand two hundred thirty-four): + let g:number = 1234 + let g:expected = "one thousand two hundred thirty-four" + AssertEqual g:expected, Say(g:number) + +Execute (one million): + let g:number = 1000000 + let g:expected = "one million" + AssertEqual g:expected, Say(g:number) + +Execute (one million two thousand three hundred forty-five): + let g:number = 1002345 + let g:expected = "one million two thousand three hundred forty-five" + AssertEqual g:expected, Say(g:number) + +Execute (one billion): + let g:number = 1000000000 + let g:expected = "one billion" + AssertEqual g:expected, Say(g:number) + +Execute (a big number): + let g:number = 987654321123 + let g:expected = "nine hundred eighty-seven billion six hundred fifty-four million three hundred twenty-one thousand one hundred twenty-three" + AssertEqual g:expected, Say(g:number) + +Execute (numbers below zero are out of range): + let g:number = -1 + let g:expected = "input out of range" + AssertThrows call Say(g:number) + AssertEqual g:expected, g:vader_exception + +Execute (numbers above 999,999,999,999 are out of range): + let g:number = 1000000000000 + let g:expected = "input out of range" + AssertThrows call Say(g:number) + AssertEqual g:expected, g:vader_exception diff --git a/exercises/practice/say/say.vim b/exercises/practice/say/say.vim new file mode 100644 index 0000000..162e7a6 --- /dev/null +++ b/exercises/practice/say/say.vim @@ -0,0 +1,14 @@ +" +" Say converts a numeric value between 0 and 999,999,999,999 into its spoken +" English equivalent. +" +" Examples: +" :echo Say(0) +" zero +" +" :echo Say(123) +" one hundred twenty-three +" +function! Say(number) abort + " your code goes here +endfunction