π Exercism Research is now launched. Help Exercism, help science and have some fun at research.exercism.io π

# eferim's solution

## to Wordy in the Delphi Pascal Track

Published at Sep 20 2018 · 0 comments
Instructions
Test suite
Solution

#### Note:

This exercise has changed since this solution was written.

Parse and evaluate simple math word problems returning the answer as an integer.

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)

## Bonus β Exponentials

If you'd like, handle exponentials.

What is 2 raised to the 5th power?

32

## Testing

In order to run the tests for this track, you will need to install DUnitX. Please see the installation instructions for more information.

If Delphi is properly installed, and `*.dpr` file types have been associated with Delphi, then double clicking the supplied `*.dpr` file will start Delphi and load the exercise/project. `control + F9` is the keyboard shortcut to compile the project or pressing `F9` will compile and run the project.

Alternatively you may opt to start Delphi and load your project via. the `File` drop down menu.

### When Questions Come Up

We monitor the Pascal-Delphi support room on gitter.im to help you with any questions that might arise.

### Submitting Exercises

Note that, when trying to submit an exercise, make sure the exercise file you're submitting is in the `exercism/delphi/<exerciseName>` directory.

For example, if you're submitting `ubob.pas` for the Bob exercise, the submit command would be something like `exercism submit <path_to_exercism_dir>/delphi/bob/ubob.pas`.

## 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 may receive assistance from a mentor.

### uWordyTests.pas

``````unit uWordyTests;

interface
uses
DUnitX.TestFramework;

const
CanonicalVersion = '1.1.0';

type

[TestFixture]
WordyTests = class(TObject)
public
//   [Ignore('Comment the "[Ignore]" statement to run the test')]
[TestCase('addition', 'What is 1 plus 1?,2')]
procedure Addition(const aInput: string; const aExpected: integer);

[Ignore]
[TestCase('more addition', 'What is 53 plus 2?,55')]
procedure More_Addition(const aInput: string; const aExpected: integer);

[Ignore]
[TestCase('addition with negative numbers', 'What is -1 plus -10?,-11')]
procedure Addition_with_negative_numbers(const aInput: string; const aExpected: integer);

[Ignore]
[TestCase('large addition', 'What is 123 plus 45678?,45801')]
procedure Large_addition(const aInput: string; const aExpected: integer);

[Ignore]
[TestCase('subtraction', 'What is 4 minus -12?,16')]
procedure Subtraction(const aInput: string; aExpected: integer);

[Ignore]
[TestCase('multiplication', 'What is -3 multiplied by 25?,-75')]
procedure Multiplication(const aInput: string; aExpected: integer);

[Ignore]
[TestCase('division', 'What is 33 divided by -3?,-11')]
procedure Division(const aInput: string; aExpected: integer);

[Ignore]
[TestCase('multiple additions', 'What is 1 plus 1 plus 1?,3')]
procedure Multiple_additions(const aInput: string; aExpected: integer);

[Ignore]
[TestCase('addition and subtraction', 'What is 1 plus 5 minus -2?,8')]
procedure Addition_and_subtraction(const aInput: string; const aExpected: integer);

[Ignore]
[TestCase('multiple subtraction', 'What is 20 minus 4 minus 13?,3')]
procedure Multiple_subtraction(const aInput: string; const aExpected: integer);

[Ignore]
[TestCase('subtraction then addition', 'What is 17 minus 6 plus 3?,14')]
procedure Subtraction_then_addition(const aInput: string; const aExpected: integer);

[Ignore]
[TestCase('multiple multiplication', 'What is 2 multiplied by -2 multiplied by 3?,-12')]
procedure Multiple_multiplication(const aInput: string; aExpected: integer);

[Ignore]
[TestCase('addition and multiplication', 'What is -3 plus 7 multiplied by -2?,-8')]
procedure Addition_and_multiplication(const aInput: string; aExpected: integer);

[Ignore]
[TestCase('multiple division', 'What is -12 divided by 2 divided by -3?,2')]
procedure Multiple_division(const aInput: string; aExpected: integer);

[Ignore]
[TestCase('unknown operation', 'What is 52 cubed?,Invalid Problem')]
procedure Unknown_operation(const aInput: string; aExpected: string);

[Ignore]
[TestCase('Non math question', 'Who is the President of the United States?,Invalid Problem')]
procedure Non_math_question(const aInput: string; aExpected: string);
end;

implementation
uses uWordy;

procedure WordyTests.Addition(const aInput: string; const aExpected: integer);
begin
end;

aExpected: integer);
begin
end;

const aExpected: integer);
begin
end;

const aExpected: integer);
begin
end;

procedure WordyTests.Division(const aInput: string; aExpected: integer);
begin
end;

const aExpected: integer);
begin
end;

const aExpected: integer);
begin
end;

aExpected: integer);
begin
end;

procedure WordyTests.Multiple_division(const aInput: string;
aExpected: integer);
begin
end;

procedure WordyTests.Multiple_multiplication(const aInput: string;
aExpected: integer);
begin
end;

procedure WordyTests.Multiple_subtraction(const aInput: string;
const aExpected: integer);
begin
end;

procedure WordyTests.Multiplication(const aInput: string; aExpected: integer);
begin
end;

procedure WordyTests.Subtraction(const aInput: string; aExpected: integer);
begin
end;

const aExpected: integer);
begin
end;

procedure WordyTests.Unknown_operation(const aInput: string; aExpected: string);
var MyProc: TTestLocalMethod;
begin
MyProc := procedure
begin
end;

Assert.WillRaiseWithMessage(MyProc, EInvalidProblem, aExpected);
end;

procedure WordyTests.Non_math_question(const aInput: string; aExpected: string);
var MyProc: TTestLocalMethod;
begin
MyProc := procedure
begin
end;

Assert.WillRaiseWithMessage(MyProc, EInvalidProblem, aExpected);
end;

initialization
TDUnitX.RegisterTestFixture(WordyTests);
end.``````
``````unit uWordy;

interface

uses System.Generics.Collections, System.SysUtils;

type
EInvalidProblem = class(Exception);

TTokenType = (ttAny, ttNumber, ttOperator);

TState = (stBegin, stNumber, stOperator);

TWordy = class
private
class var FOps : TList<string>;
class function Recognize(AToken : string) : TTokenType;
class function Strip(AToken: string) : integer;
class function Calculate(AOpSt : string; AStack : TStack<integer>) : integer;
public
class function Answer(AInp : string) : integer;
end;

implementation

uses System.RegularExpressions, System.Math;

{ TWordy }

var Tokens : TArray<string>;
W: string;
Stack : TStack<integer>;
OpSt : string;
State : TState;
tt : TTokenType;
begin

Stack := TStack<integer>.Create;
Tokens := AInp.Split([' ', '?', 'power'], ExcludeEmpty);
state :=  stBegin;
Result := -1;
for W in Tokens do
begin
TT := Recognize(W);
case state of
stBegin:
case tt of
ttNumber: begin
Stack.Push(Strip(W));
State := stNumber;
end;
ttOperator: raise EInvalidProblem.Create('Missing operand before ' + W);
end;
stNumber:
case tt of
ttAny : raise EInvalidProblem.Create('Invalid Problem');
ttNumber: raise EInvalidProblem.Create('Operator expected, but ' + W + ' found');
ttOperator: begin
OpSt := W;
State := stOperator;
end;
end;
stOperator:
case tt of
ttNumber: begin
Stack.Push(Strip(W));
Result := Calculate(OpSt,Stack);
State := stNumber;
end;
ttOperator: raise EInvalidProblem.Create('Missing operand before ' + W);
end;
end;
end;
if State <> stNumber then raise EInvalidProblem.Create('Invalid Problem');
Stack.Free;
end;

class function TWordy.Calculate(AOpSt : string; AStack : TStack<integer>): integer;
var a, b : integer;
begin
a := AStack.Extract;
b := AStack.Extract;
result := -1;
case TWordy.FOps.IndexOf(AOpSt) of
0 : Result := b + a;
1 : Result := b - a;
2 : Result := b * a;
3 : Result := b div a;
4 : Result := trunc(Power(b, a));
end;
AStack.Push(Result);
end;

class function TWordy.Recognize(AToken: string): TTokenType;
begin
Result := ttAny;
if TRegEx.IsMatch(AToken,'(\d+)|(-\d+)|(\d+st\$)|(\d+nd\$)|(\d+rd\$)|(\d+th\$)') then
Result := ttNumber;
if TWordy.FOps.Contains(AToken) then
Result := ttOperator;
end;

class function TWordy.Strip(AToken: string): integer;
begin
Result := TRegEx.Replace(AToken,'[^-\d]', '', []).ToInteger;
end;

initialization

TWordy.FOps := TList<string>.Create;

finalization

TWordy.FOps.Free;

end.``````