diff --git a/config.json b/config.json index d44d165..10dfc4c 100644 --- a/config.json +++ b/config.json @@ -850,6 +850,14 @@ "prerequisites": [], "difficulty": 6 }, + { + "slug": "wordy", + "name": "Wordy", + "uuid": "c4112228-adec-4109-a9aa-5bd366c1e658", + "practices": [], + "prerequisites": [], + "difficulty": 6 + }, { "slug": "book-store", "name": "Book Store", diff --git a/exercises/practice/wordy/.busted b/exercises/practice/wordy/.busted new file mode 100644 index 0000000..86b84e7 --- /dev/null +++ b/exercises/practice/wordy/.busted @@ -0,0 +1,5 @@ +return { + default = { + ROOT = { '.' } + } +} diff --git a/exercises/practice/wordy/.docs/instructions.md b/exercises/practice/wordy/.docs/instructions.md new file mode 100644 index 0000000..aafb9ee --- /dev/null +++ b/exercises/practice/wordy/.docs/instructions.md @@ -0,0 +1,59 @@ +# Instructions + +Parse and evaluate simple math word problems returning the answer as an integer. + +## Iteration 0 — Numbers + +Problems with no operations simply evaluate to the number given. + +> What is 5? + +Evaluates to 5. + +## Iteration 1 — Addition + +Add two numbers together. + +> What is 5 plus 13? + +Evaluates to 18. + +Handle large numbers and negative numbers. + +## Iteration 2 — Subtraction, Multiplication and Division + +Now, perform the other three operations. + +> What is 7 minus 5? + +2 + +> What is 6 multiplied by 4? + +24 + +> What is 25 divided by 5? + +5 + +## Iteration 3 — Multiple Operations + +Handle a set of operations, in sequence. + +Since these are verbal word problems, evaluate the expression from left-to-right, _ignoring the typical order of operations._ + +> What is 5 plus 13 plus 6? + +24 + +> What is 3 plus 2 multiplied by 3? + +15 (i.e. not 9) + +## Iteration 4 — Errors + +The parser should reject: + +- Unsupported operations ("What is 52 cubed?") +- Non-math questions ("Who is the President of the United States") +- Word problems with invalid syntax ("What is 1 plus plus 2?") diff --git a/exercises/practice/wordy/.meta/config.json b/exercises/practice/wordy/.meta/config.json new file mode 100644 index 0000000..c70a154 --- /dev/null +++ b/exercises/practice/wordy/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "glennj" + ], + "files": { + "solution": [ + "wordy.moon" + ], + "test": [ + "wordy_spec.moon" + ], + "example": [ + ".meta/example.moon" + ] + }, + "blurb": "Parse and evaluate simple math word problems returning the answer as an integer.", + "source": "Inspired by one of the generated questions in the Extreme Startup game.", + "source_url": "https://github.com/rchatley/extreme_startup" +} diff --git a/exercises/practice/wordy/.meta/example.moon b/exercises/practice/wordy/.meta/example.moon new file mode 100644 index 0000000..b41c1fe --- /dev/null +++ b/exercises/practice/wordy/.meta/example.moon @@ -0,0 +1,49 @@ +re = require 're' -- https://www.inf.puc-rio.br/~roberto/lpeg/re.html + +local err, evaluate + +answer = (input) -> + wordy = re.compile [[ + wordy <- 'What is ' {| expr |} '?' + expr <- { num } (s {~ op ~} s { num })* + num <- '-'? %d+ + op <- 'plus' -> '+' + / 'minus' -> '-' + / 'multiplied by' -> '*' + / 'divided by' -> '/' + s <- %s+ + ]] + + tokens = re.match input, wordy + if tokens + evaluate tokens + else + err input + +evaluate = (tokens) -> + result = tonumber tokens[1] + for i = 2, #tokens, 2 + addend = tonumber tokens[i+1] + result = switch tokens[i] + when '+' then result + addend + when '-' then result - addend + when '*' then result * addend + when '/' then result // addend + result + +err = (input) -> + refute = (cond, msg) -> assert not cond, msg + + -- figure out the appropriate error message + refute input\match('^What is *%?$'), 'syntax error' + assert input\match('^What is .+%?$'), 'unknown operation' + syntax_errs = re.compile [[ + x <- s (op s op / num s num / op '?') + op <- 'plus' / 'minus' / 'multiplied by' / 'divided by' + num <- '-'? %d+ + s <- %s+ + ]] + refute re.find(input, syntax_errs), 'syntax error' + error 'unknown operation' + +{ :answer } diff --git a/exercises/practice/wordy/.meta/spec_generator.moon b/exercises/practice/wordy/.meta/spec_generator.moon new file mode 100644 index 0000000..6afbaca --- /dev/null +++ b/exercises/practice/wordy/.meta/spec_generator.moon @@ -0,0 +1,16 @@ +{ + module_name: 'Wordy', + + generate_test: (case, level) -> + lines = if type(case.expected) == 'table' + { + "fn = -> Wordy.#{case.property} #{quote case.input.question}", + "assert.has.error fn, #{quote case.expected.error}" + } + else + { + "result = Wordy.#{case.property} #{quote case.input.question}", + "assert.are.equal #{case.expected}, result" + } + table.concat [indent line, level for line in *lines], '\n' +} diff --git a/exercises/practice/wordy/.meta/tests.toml b/exercises/practice/wordy/.meta/tests.toml new file mode 100644 index 0000000..a0a83ed --- /dev/null +++ b/exercises/practice/wordy/.meta/tests.toml @@ -0,0 +1,91 @@ +# 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. + +[88bf4b28-0de3-4883-93c7-db1b14aa806e] +description = "just a number" + +[18983214-1dfc-4ebd-ac77-c110dde699ce] +description = "just a zero" + +[607c08ee-2241-4288-916d-dae5455c87e6] +description = "just a negative number" + +[bb8c655c-cf42-4dfc-90e0-152fcfd8d4e0] +description = "addition" + +[bb9f2082-171c-46ad-ad4e-c3f72087c1b5] +description = "addition with a left hand zero" + +[6fa05f17-405a-4742-80ae-5d1a8edb0d5d] +description = "addition with a right hand zero" + +[79e49e06-c5ae-40aa-a352-7a3a01f70015] +description = "more addition" + +[b345dbe0-f733-44e1-863c-5ae3568f3803] +description = "addition with negative numbers" + +[cd070f39-c4cc-45c4-97fb-1be5e5846f87] +description = "large addition" + +[0d86474a-cd93-4649-a4fa-f6109a011191] +description = "subtraction" + +[30bc8395-5500-4712-a0cf-1d788a529be5] +description = "multiplication" + +[34c36b08-8605-4217-bb57-9a01472c427f] +description = "division" + +[da6d2ce4-fb94-4d26-8f5f-b078adad0596] +description = "multiple additions" + +[7fd74c50-9911-4597-be09-8de7f2fea2bb] +description = "addition and subtraction" + +[b120ffd5-bad6-4e22-81c8-5512e8faf905] +description = "multiple subtraction" + +[4f4a5749-ef0c-4f60-841f-abcfaf05d2ae] +description = "subtraction then addition" + +[312d908c-f68f-42c9-aa75-961623cc033f] +description = "multiple multiplication" + +[38e33587-8940-4cc1-bc28-bfd7e3966276] +description = "addition and multiplication" + +[3c854f97-9311-46e8-b574-92b60d17d394] +description = "multiple division" + +[3ad3e433-8af7-41ec-aa9b-97b42ab49357] +description = "unknown operation" + +[8a7e85a8-9e7b-4d46-868f-6d759f4648f8] +description = "Non math question" + +[42d78b5f-dbd7-4cdb-8b30-00f794bb24cf] +description = "reject problem missing an operand" + +[c2c3cbfc-1a72-42f2-b597-246e617e66f5] +description = "reject problem with no operands or operators" + +[4b3df66d-6ed5-4c95-a0a1-d38891fbdab6] +description = "reject two operations in a row" + +[6abd7a50-75b4-4665-aa33-2030fd08bab1] +description = "reject two numbers in a row" + +[10a56c22-e0aa-405f-b1d2-c642d9c4c9de] +description = "reject postfix notation" + +[0035bc63-ac43-4bb5-ad6d-e8651b7d954e] +description = "reject prefix notation" diff --git a/exercises/practice/wordy/wordy.moon b/exercises/practice/wordy/wordy.moon new file mode 100644 index 0000000..0b96c88 --- /dev/null +++ b/exercises/practice/wordy/wordy.moon @@ -0,0 +1,4 @@ +{ + answer: (question) -> + error 'Implement me' +} diff --git a/exercises/practice/wordy/wordy_spec.moon b/exercises/practice/wordy/wordy_spec.moon new file mode 100644 index 0000000..9b64673 --- /dev/null +++ b/exercises/practice/wordy/wordy_spec.moon @@ -0,0 +1,110 @@ +Wordy = require 'wordy' + +describe 'wordy', -> + it 'just a number', -> + result = Wordy.answer 'What is 5?' + assert.are.equal 5, result + + pending 'just a zero', -> + result = Wordy.answer 'What is 0?' + assert.are.equal 0, result + + pending 'just a negative number', -> + result = Wordy.answer 'What is -123?' + assert.are.equal -123, result + + pending 'addition', -> + result = Wordy.answer 'What is 1 plus 1?' + assert.are.equal 2, result + + pending 'addition with a left hand zero', -> + result = Wordy.answer 'What is 0 plus 2?' + assert.are.equal 2, result + + pending 'addition with a right hand zero', -> + result = Wordy.answer 'What is 3 plus 0?' + assert.are.equal 3, result + + pending 'more addition', -> + result = Wordy.answer 'What is 53 plus 2?' + assert.are.equal 55, result + + pending 'addition with negative numbers', -> + result = Wordy.answer 'What is -1 plus -10?' + assert.are.equal -11, result + + pending 'large addition', -> + result = Wordy.answer 'What is 123 plus 45678?' + assert.are.equal 45801, result + + pending 'subtraction', -> + result = Wordy.answer 'What is 4 minus -12?' + assert.are.equal 16, result + + pending 'multiplication', -> + result = Wordy.answer 'What is -3 multiplied by 25?' + assert.are.equal -75, result + + pending 'division', -> + result = Wordy.answer 'What is 33 divided by -3?' + assert.are.equal -11, result + + pending 'multiple additions', -> + result = Wordy.answer 'What is 1 plus 1 plus 1?' + assert.are.equal 3, result + + pending 'addition and subtraction', -> + result = Wordy.answer 'What is 1 plus 5 minus -2?' + assert.are.equal 8, result + + pending 'multiple subtraction', -> + result = Wordy.answer 'What is 20 minus 4 minus 13?' + assert.are.equal 3, result + + pending 'subtraction then addition', -> + result = Wordy.answer 'What is 17 minus 6 plus 3?' + assert.are.equal 14, result + + pending 'multiple multiplication', -> + result = Wordy.answer 'What is 2 multiplied by -2 multiplied by 3?' + assert.are.equal -12, result + + pending 'addition and multiplication', -> + result = Wordy.answer 'What is -3 plus 7 multiplied by -2?' + assert.are.equal -8, result + + pending 'multiple division', -> + result = Wordy.answer 'What is -12 divided by 2 divided by -3?' + assert.are.equal 2, result + + pending 'unknown operation', -> + fn = -> Wordy.answer 'What is 52 cubed?' + assert.has.error fn, 'unknown operation' + + pending 'Non math question', -> + fn = -> Wordy.answer 'Who is the President of the United States?' + assert.has.error fn, 'unknown operation' + + pending 'reject problem missing an operand', -> + fn = -> Wordy.answer 'What is 1 plus?' + assert.has.error fn, 'syntax error' + + pending 'reject problem with no operands or operators', -> + fn = -> Wordy.answer 'What is?' + assert.has.error fn, 'syntax error' + + pending 'reject two operations in a row', -> + fn = -> Wordy.answer 'What is 1 plus plus 2?' + assert.has.error fn, 'syntax error' + + pending 'reject two numbers in a row', -> + fn = -> Wordy.answer 'What is 1 plus 2 1?' + assert.has.error fn, 'syntax error' + + pending 'reject postfix notation', -> + fn = -> Wordy.answer 'What is 1 2 plus?' + assert.has.error fn, 'syntax error' + + pending 'reject prefix notation', -> + fn = -> Wordy.answer 'What is plus 1 2?' + assert.has.error fn, 'syntax error'