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

# Greycoat21's solution

## to Wordy in the Delphi Pascal Track

Published at Feb 03 2020 · 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

## 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 request help from a mentor.

### uWordyTests.pas

``````unit uWordyTests;

interface
uses
DUnitX.TestFramework;

const
CanonicalVersion = '1.5.0';

type

[TestFixture]
WordyTests = class(TObject)
public
//   [Ignore('Comment the "[Ignore]" statement to run the test')]
[TestCase('a number', 'What is 5?,5')]
procedure just_a_number(const aInput: string; const aExpected: integer);

[Ignore]
[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?,unknown operation')]
procedure Unknown_operation(const aInput: string; aExpected: string);

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

[Ignore]
[TestCase('reject problem missing an operand', 'What is 1 plus?,syntax error')]
procedure problem_missing_an_operand(const aInput: string; aExpected: string);

[Ignore]
[TestCase('reject problem with no operands or operators', 'What is?,syntax error')]
procedure problem_with_no_operands_or_operators(const aInput: string; aExpected: string);

[Ignore]
[TestCase('reject two operations in a row', 'What is 1 plus plus 2?,syntax error')]
procedure reject_two_operations_in_a_row(const aInput: string; aExpected: string);

[Ignore]
[TestCase('reject two numbers in a row', 'What is 1 plus 2 1?,syntax error')]
procedure reject_two_numbers_in_a_row(const aInput: string; aExpected: string);

[Ignore]
[TestCase('reject postfix notation', 'What is 1 2 plus?,syntax error')]
procedure reject_postfix_notation(const aInput: string; aExpected: string);

[Ignore]
[TestCase('reject prefix notation', 'What is plus 1 2?,syntax error')]
procedure reject_prefix_notation(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;

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

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

procedure WordyTests.just_a_number(const aInput: string;
const 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.problem_with_no_operands_or_operators(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;

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

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

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

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

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

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

procedure WordyTests.reject_two_operations_in_a_row(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
SysUtils;

type
//------------------------------------------------------------------------------
EInvalidProblem = class(Exception);
//------------------------------------------------------------------------------
TWordy = class
end;
//------------------------------------------------------------------------------

implementation

uses
StrUtils;

//------------------------------------------------------------------------------
type
TOperation = (oAddition, oSubtraction, oMultiplication, oDivision);
TOp = function (Val1, Val2: Integer): Integer;

// TOp functions
begin Result := Val1 + Val2; end;
function Subtract(Val1, Val2: Integer): Integer;
begin Result := Val1 - Val2; end;
function Multiply(Val1, Val2: Integer): Integer;
begin Result := Val1 * Val2; end;
function Divide(Val1, Val2: Integer): Integer;
begin Result := Val1 div Val2; end;

const
Op: array [TOperation] of TOp = (Add, Subtract, Multiply, Divide);

function TryStrToOperation(Str: string; out Operation: TOperation): Boolean;
begin
Result := True;
if SameText(Str, 'plus') then
else if SameText(Str, 'minus') then
Operation := oSubtraction
else if SameText(Str, 'multiplied') then
Operation := oMultiplication
else if SameText(Str, 'divided') then
Operation := oDivision
else
Result := False;
end;
//------------------------------------------------------------------------------
type
ErrorDescr = class
const UnkonwnOp = 'unknown operation';
const SyntaxError = 'syntax error';
end;
//------------------------------------------------------------------------------
type
TWordType = (wtInteger, wtOperation);

// Cycle Through TWordType Enumeration Values
function Cycle(WordType: TWordType): TWordType;
begin
Result := TWordType((Ord(WordType) + 1) mod (1 + Integer(High(TWordType))));
end;
//------------------------------------------------------------------------------

{ TWordy }

var
Value: Integer;
Values: TArray<Integer>;
Operation: TOperation;
Oper: TOp;
Word: string;
Words: TArray<string>;
WordType, ExpectedWordType: TWordType;
begin
Words := Question
.Replace('What is', '')
.Replace(' by', '')
.Replace('?', '')
.Trim
.Split([' ']);

Values := [];
Oper := nil;
Result := 0;
ExpectedWordType := wtInteger;
for Word in Words do begin

if TryStrToInt(Word, Value) then begin
Values := Values + [Value];
WordType := wtInteger;
end else if TryStrToOperation(Word, Operation) then begin
Oper := Op[Operation];
WordType := wtOperation;
end else begin
raise EInvalidProblem.Create(ErrorDescr.UnkonwnOp);
end;

if WordType <> ExpectedWordType then
raise EInvalidProblem.Create(ErrorDescr.SyntaxError);

ExpectedWordType := Cycle(ExpectedWordType);

if Length(Values) = 1 then begin
Result := Values[0];
end else if Length(Values) = 2 then begin
Result := Oper(Values[0], Values[1]);
Values := [Result];
Oper := nil;
end;

end;

// Unused Operation
if Assigned(Oper)
// Unused Value
or (Length(Values) = 2)
// No values provided
or (Length(Values) = 0) then
raise EInvalidProblem.Create(ErrorDescr.SyntaxError);
end;

end.``````