 # 23phy's solution

## to Wordy in the TypeScript Track

Published at Aug 26 2019 · 0 comments
Instructions
Test suite
Solution

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.

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?")

## Bonus — Exponentials

If you'd like, handle exponentials.

What is 2 raised to the 5th power?

32

## Setup

Go through the setup instructions for TypeScript to install the necessary dependencies:

https://exercism.io/tracks/typescript/installation

## Requirements

Install assignment dependencies:

``````\$ yarn install
``````

## Making the test suite pass

Execute the tests with:

``````\$ yarn test
``````

In the test suites all tests but the first have been skipped.

Once you get a test passing, you can enable the next one by changing `xit` to `it`.

## Source

Inspired by one of the generated questions in the Extreme Startup game. https://github.com/rchatley/extreme_startup

## Submitting Incomplete Solutions

It's possible to submit an incomplete solution so you can see how others have completed the exercise.

### wordy.test.ts

``````import { WordProblem, ArgumentError } from './wordy'

describe('Word Problem', () => {

const question = 'What is 1 plus 1?'
})

const question = 'What is 53 plus 2?'
})

xit('add negative numbers', () => {
const question = 'What is -1 plus -10?'
})

xit('add more digits', () => {
const question = 'What is 123 plus 45678?'
})

xit('subtract', () => {
const question = 'What is 4 minus -12?'
})

xit('multiply', () => {
const question = 'What is -3 multiplied by 25?'
})

xit('divide', () => {
const question = 'What is 33 divided by -3?'
})

const question = 'What is 1 plus 1 plus 1?'
})

xit('add then subtract', () => {
const question = 'What is 1 plus 5 minus -2?'
})

xit('subtract twice', () => {
const question = 'What is 20 minus 4 minus 13?'
})

xit('subtract then add', () => {
const question = 'What is 17 minus 6 plus 3?'
})

xit('multiply twice', () => {
const question = 'What is 2 multiplied by -2 multiplied by 3?'
})

xit('add then multiply', () => {
const question = 'What is -3 plus 7 multiplied by -2?'
})

xit('divide twice', () => {
const question = 'What is -12 divided by 2 divided by -3?'
})

const question = 'What is 53 cubed?'
const problem  = new WordProblem(question)

})

xit('irrelevant', () => {
const question = 'Who is the president of the United States?'
const problem  = new WordProblem(question)

})

})``````

### wordy.ts

``````import { Parser, Grammar } from "nearley";
// @ts-ignore - No declaration file for module './wordy-nec.js'
import { default as grammar } from "./wordy-nec.js";

export class WordProblem {
private m_parser: Parser;

constructor(private question: string) {
this.m_parser = new Parser(Grammar.fromCompiled(grammar));
}

try {
this.m_parser.feed(this.question);
} catch (error) {
throw new ArgumentError(error);
}

return this.m_parser.results;
}
}

export class ArgumentError extends Error {
constructor(message: string) {
super(message)
}
}``````

### wordy.ne

``````@{%
const plus      = (a, b) => parseInt(a) + parseInt(b);
const minus     = (a, b) => parseInt(a) - parseInt(b);
const multiply  = (a, b) => parseInt(a) * parseInt(b);
const divide    = (a, b) => parseInt(a) / parseInt(b);
const cube      = (a) => Math.pow(parseInt(a), 3);
%}

start ->
"What is" _ Expression "?" {% d => d %}

Expression ->
Integer                                 {% d => parseInt(d) %}
| Expression _ "plus"          _ Integer  {% d => plus(d, d) %}
| Expression _ "minus"         _ Integer  {% d => minus(d, d) %}
| Expression _ "multiplied by" _ Integer  {% d => multiply(d, d) %}
| Expression _ "divided by"    _ Integer  {% d => divide(d, d) %}
| Expression _ "cubed"                    {% d => cube(d) %}

Integer ->
null
| "-" Integer   {% d => d.join('') %}
| [0-9] Integer {% d => d.join('') %}

_ -> " "  {% d => d %}``````

### wordy-nec.js

``````// Generated automatically by nearley, version 2.18.0
// http://github.com/Hardmath123/nearley
(function () {
function id(x) { return x; }

const plus      = (a, b) => parseInt(a) + parseInt(b);
const minus     = (a, b) => parseInt(a) - parseInt(b);
const multiply  = (a, b) => parseInt(a) * parseInt(b);
const divide    = (a, b) => parseInt(a) / parseInt(b);
const cube      = (a) => Math.pow(parseInt(a), 3);
var grammar = {
Lexer: undefined,
ParserRules: [
{"name": "start\$string\$1", "symbols": [{"literal":"W"}, {"literal":"h"}, {"literal":"a"}, {"literal":"t"}, {"literal":" "}, {"literal":"i"}, {"literal":"s"}], "postprocess": function joiner(d) {return d.join('');}},
{"name": "start", "symbols": ["start\$string\$1", "_", "Expression", {"literal":"?"}], "postprocess": d => d},
{"name": "Expression", "symbols": ["Integer"], "postprocess": d => parseInt(d)},
{"name": "Expression\$string\$1", "symbols": [{"literal":"p"}, {"literal":"l"}, {"literal":"u"}, {"literal":"s"}], "postprocess": function joiner(d) {return d.join('');}},
{"name": "Expression", "symbols": ["Expression", "_", "Expression\$string\$1", "_", "Integer"], "postprocess": d => plus(d, d)},
{"name": "Expression\$string\$2", "symbols": [{"literal":"m"}, {"literal":"i"}, {"literal":"n"}, {"literal":"u"}, {"literal":"s"}], "postprocess": function joiner(d) {return d.join('');}},
{"name": "Expression", "symbols": ["Expression", "_", "Expression\$string\$2", "_", "Integer"], "postprocess": d => minus(d, d)},
{"name": "Expression\$string\$3", "symbols": [{"literal":"m"}, {"literal":"u"}, {"literal":"l"}, {"literal":"t"}, {"literal":"i"}, {"literal":"p"}, {"literal":"l"}, {"literal":"i"}, {"literal":"e"}, {"literal":"d"}, {"literal":" "}, {"literal":"b"}, {"literal":"y"}], "postprocess": function joiner(d) {return d.join('');}},
{"name": "Expression", "symbols": ["Expression", "_", "Expression\$string\$3", "_", "Integer"], "postprocess": d => multiply(d, d)},
{"name": "Expression\$string\$4", "symbols": [{"literal":"d"}, {"literal":"i"}, {"literal":"v"}, {"literal":"i"}, {"literal":"d"}, {"literal":"e"}, {"literal":"d"}, {"literal":" "}, {"literal":"b"}, {"literal":"y"}], "postprocess": function joiner(d) {return d.join('');}},
{"name": "Expression", "symbols": ["Expression", "_", "Expression\$string\$4", "_", "Integer"], "postprocess": d => divide(d, d)},
{"name": "Expression\$string\$5", "symbols": [{"literal":"c"}, {"literal":"u"}, {"literal":"b"}, {"literal":"e"}, {"literal":"d"}], "postprocess": function joiner(d) {return d.join('');}},
{"name": "Expression", "symbols": ["Expression", "_", "Expression\$string\$5"], "postprocess": d => cube(d)},
{"name": "Integer", "symbols": []},
{"name": "Integer", "symbols": [{"literal":"-"}, "Integer"], "postprocess": d => d.join('')},
{"name": "Integer", "symbols": [/[0-9]/, "Integer"], "postprocess": d => d.join('')},
{"name": "_", "symbols": [{"literal":" "}], "postprocess": d => d}
]
, ParserStart: "start"
}
if (typeof module !== 'undefined'&& typeof module.exports !== 'undefined') {
module.exports = grammar;
} else {
window.grammar = grammar;
}
})();``````