ðŸŽ‰ Exercism Research is now launched. Help Exercism, help science and have some fun at research.exercism.io ðŸŽ‰

# Neftali's solution

## to Robot Simulator in the Delphi Pascal Track

Published at Jul 31 2020 · 0 comments
Instructions
Test suite
Solution

Write a robot simulator.

A robot factory's test facility needs a program to verify robot movements.

The robots have three possible movements:

• turn right
• turn left

Robots are placed on a hypothetical infinite grid, facing a particular direction (north, east, south, or west) at a set of {x,y} coordinates, e.g., {3,8}, with coordinates increasing to the north and east.

The robot then receives a number of instructions, at which point the testing facility verifies the robot's new position, and in which direction it is pointing.

• The letter-string "RAALAL" means:
• Turn right
• Turn left
• Turn left yet again
• Say a robot starts at {7, 3} facing north. Then running this stream of instructions should leave it at {9, 4} facing west.

## 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 an interview question at a famous company.

## Submitting Incomplete Solutions

It's possible to submit an incomplete solution so you may request help from a mentor.

### uRobotSimulatorTests.pas

``````unit uRobotSimulatorTests;

interface
uses
DUnitX.TestFramework;

const
CanonicalVersion = '3.1.0.1';

type
[TestFixture]
TRobotSimTest = class(TObject)
public
[Test]
//    [Ignore('Comment the "[Ignore]" statement to run the test')]
procedure Robots_are_created_with_a_position_and_direction;

[Test]
[Ignore]
procedure Negative_positions_are_allowed;

[Test]
[Ignore]
procedure changes_the_direction_from_north_to_east;

[Test]
[Ignore]
procedure changes_the_direction_from_east_to_south;

[Test]
[Ignore]
procedure changes_the_direction_from_south_to_west;

[Test]
[Ignore]
procedure changes_the_direction_from_west_to_north;

[Test]
[Ignore]
procedure changes_the_direction_from_north_to_west;

[Test]
[Ignore]
procedure changes_the_direction_from_west_to_south;

[Test]
[Ignore]
procedure changes_the_direction_from_south_to_east;

[Test]
[Ignore]
procedure changes_the_direction_from_east_to_north;

[Test]
[Ignore]
procedure increases_the_y_coordinate_one_when_facing_north;

[Test]
[Ignore]
procedure decreases_the_y_coordinate_by_one_when_facing_south;

[Test]
[Ignore]
procedure increases_the_x_coordinate_by_one_when_facing_east;

[Test]
[Ignore]
procedure decreases_the_x_coordinate_by_one_when_facing_west;

[Test]
[Ignore]

[Test]
[Ignore]
procedure instructions_to_move_west_and_north;

[Test]
[Ignore]
procedure instructions_to_move_west_and_south;

[Test]
[Ignore]
procedure instructions_to_move_east_and_north;
end;

implementation
uses uRobotSimulator;

procedure TRobotSimTest.Negative_positions_are_allowed;
var
Actual : TRobotSimulator;
ExpectedCoord: TCoordinate;
begin
ExpectedCoord := TCoordinate.Create(-1, -1);
Actual := TRobotSimulator.Create(TDirection.south, TCoordinate.Create(-1, -1));
Assert.AreEqual(ExpectedCoord, Actual.Coordinate);
Assert.AreEqual(TDirection.south, Actual.Direction);
Actual.DisposeOf;
end;

procedure TRobotSimTest.Robots_are_created_with_a_position_and_direction;
var
Actual : TRobotSimulator;
ExpectedCoord: TCoordinate;
begin
ExpectedCoord := TCoordinate.Create(0, 0);
Actual := TRobotSimulator.Create(TDirection.north, TCoordinate.Create(0, 0));
Assert.AreEqual(ExpectedCoord, Actual.Coordinate);
Assert.AreEqual(TDirection.north, Actual.Direction);
Actual.DisposeOf;
end;

procedure TRobotSimTest.decreases_the_x_coordinate_by_one_when_facing_west;
var
Actual : TRobotSimulator;
ExpectedCoord: TCoordinate;
begin
ExpectedCoord := TCoordinate.Create(-1, 0);
Actual := TRobotSimulator.Create(TDirection.west, TCoordinate.Create(0, 0));
Actual.move('A');
Assert.AreEqual(ExpectedCoord, Actual.Coordinate);
Assert.AreEqual(TDirection.west, Actual.Direction);
Actual.DisposeOf;
end;

procedure TRobotSimTest.decreases_the_y_coordinate_by_one_when_facing_south;
var
Actual : TRobotSimulator;
ExpectedCoord: TCoordinate;
begin
ExpectedCoord := TCoordinate.Create(0, -1);
Actual := TRobotSimulator.Create(TDirection.south, TCoordinate.Create(0, 0));
Actual.move('A');
Assert.AreEqual(ExpectedCoord, Actual.Coordinate);
Assert.AreEqual(TDirection.south, Actual.Direction);
Actual.DisposeOf;
end;

procedure TRobotSimTest.increases_the_x_coordinate_by_one_when_facing_east;
var
Actual : TRobotSimulator;
ExpectedCoord: TCoordinate;
begin
ExpectedCoord := TCoordinate.Create(1, 0);
Actual := TRobotSimulator.Create(TDirection.east, TCoordinate.Create(0, 0));
Actual.move('A');
Assert.AreEqual(ExpectedCoord, Actual.Coordinate);
Assert.AreEqual(TDirection.east, Actual.Direction);
Actual.DisposeOf;
end;

procedure TRobotSimTest.increases_the_y_coordinate_one_when_facing_north;
var
Actual : TRobotSimulator;
ExpectedCoord: TCoordinate;
begin
ExpectedCoord := TCoordinate.Create(0, 1);
Actual := TRobotSimulator.Create(TDirection.north, TCoordinate.Create(0, 0));
Actual.move('A');
Assert.AreEqual(ExpectedCoord, Actual.Coordinate);
Assert.AreEqual(TDirection.north, Actual.Direction);
Actual.DisposeOf;
end;

procedure TRobotSimTest.changes_the_direction_from_east_to_south;
var
Actual : TRobotSimulator;
ExpectedCoord: TCoordinate;
begin
ExpectedCoord := TCoordinate.Create(0, 0);
Actual := TRobotSimulator.Create(TDirection.east, TCoordinate.Create(0, 0));
Actual.move('R');
Assert.AreEqual(ExpectedCoord, Actual.Coordinate);
Assert.AreEqual(TDirection.south, Actual.Direction);
Actual.DisposeOf;
end;

procedure TRobotSimTest.changes_the_direction_from_north_to_east;
var
Actual : TRobotSimulator;
ExpectedCoord: TCoordinate;
begin
ExpectedCoord := TCoordinate.Create(0, 0);
Actual := TRobotSimulator.Create(TDirection.north, TCoordinate.Create(0, 0));
Actual.move('R');
Assert.AreEqual(ExpectedCoord, Actual.Coordinate);
Assert.AreEqual(TDirection.east, Actual.Direction);
Actual.DisposeOf;
end;

procedure TRobotSimTest.changes_the_direction_from_south_to_west;
var
Actual : TRobotSimulator;
ExpectedCoord: TCoordinate;
begin
ExpectedCoord := TCoordinate.Create(0, 0);
Actual := TRobotSimulator.Create(TDirection.south, TCoordinate.Create(0, 0));
Actual.move('R');
Assert.AreEqual(ExpectedCoord, Actual.Coordinate);
Assert.AreEqual(TDirection.west, Actual.Direction);
Actual.DisposeOf;
end;

procedure TRobotSimTest.changes_the_direction_from_west_to_north;
var
Actual : TRobotSimulator;
ExpectedCoord: TCoordinate;
begin
ExpectedCoord := TCoordinate.Create(0, 0);
Actual := TRobotSimulator.Create(TDirection.west, TCoordinate.Create(0, 0));
Actual.move('R');
Assert.AreEqual(ExpectedCoord, Actual.Coordinate);
Assert.AreEqual(TDirection.north, Actual.Direction);
Actual.DisposeOf;
end;

procedure TRobotSimTest.changes_the_direction_from_east_to_north;
var
Actual : TRobotSimulator;
ExpectedCoord: TCoordinate;
begin
ExpectedCoord := TCoordinate.Create(0, 0);
Actual := TRobotSimulator.Create(TDirection.east, TCoordinate.Create(0, 0));
Actual.move('L');
Assert.AreEqual(ExpectedCoord, Actual.Coordinate);
Assert.AreEqual(TDirection.north, Actual.Direction);
Actual.DisposeOf;
end;

procedure TRobotSimTest.changes_the_direction_from_north_to_west;
var
Actual : TRobotSimulator;
ExpectedCoord: TCoordinate;
begin
ExpectedCoord := TCoordinate.Create(0, 0);
Actual := TRobotSimulator.Create(TDirection.north, TCoordinate.Create(0, 0));
Actual.move('L');
Assert.AreEqual(ExpectedCoord, Actual.Coordinate);
Assert.AreEqual(TDirection.west, Actual.Direction);
Actual.DisposeOf;
end;

procedure TRobotSimTest.changes_the_direction_from_south_to_east;
var
Actual : TRobotSimulator;
ExpectedCoord: TCoordinate;
begin
ExpectedCoord := TCoordinate.Create(0, 0);
Actual := TRobotSimulator.Create(TDirection.south, TCoordinate.Create(0, 0));
Actual.move('L');
Assert.AreEqual(ExpectedCoord, Actual.Coordinate);
Assert.AreEqual(TDirection.east, Actual.Direction);
Actual.DisposeOf;
end;

procedure TRobotSimTest.changes_the_direction_from_west_to_south;
var
Actual : TRobotSimulator;
ExpectedCoord: TCoordinate;
begin
ExpectedCoord := TCoordinate.Create(0, 0);
Actual := TRobotSimulator.Create(TDirection.west, TCoordinate.Create(0, 0));
Actual.move('L');
Assert.AreEqual(ExpectedCoord, Actual.Coordinate);
Assert.AreEqual(TDirection.south, Actual.Direction);
Actual.DisposeOf;
end;

procedure TRobotSimTest.instructions_to_move_east_and_north;
var
Actual : TRobotSimulator;
ExpectedCoord: TCoordinate;
begin
ExpectedCoord := TCoordinate.Create(11, 5);
Actual := TRobotSimulator.Create(TDirection.south, TCoordinate.Create(8, 4));
Actual.move('LAAARRRALLLL');
Assert.AreEqual(ExpectedCoord, Actual.Coordinate);
Assert.AreEqual(TDirection.north, Actual.Direction);
Actual.DisposeOf;
end;

var
Actual : TRobotSimulator;
ExpectedCoord: TCoordinate;
begin
ExpectedCoord := TCoordinate.Create(9, 4);
Actual := TRobotSimulator.Create(TDirection.North, TCoordinate.Create(7, 3));
Actual.move('RAALAL');
Assert.AreEqual(ExpectedCoord, Actual.Coordinate);
Assert.AreEqual(TDirection.west, Actual.Direction);
Actual.DisposeOf;
end;

procedure TRobotSimTest.instructions_to_move_west_and_north;
var
Actual : TRobotSimulator;
ExpectedCoord: TCoordinate;
begin
ExpectedCoord := TCoordinate.Create(-4, 1);
Actual := TRobotSimulator.Create(TDirection.North, TCoordinate.Create(0, 0));
Actual.move('LAAARALA');
Assert.AreEqual(ExpectedCoord, Actual.Coordinate);
Assert.AreEqual(TDirection.west, Actual.Direction);
Actual.DisposeOf;
end;

procedure TRobotSimTest.instructions_to_move_west_and_south;
var
Actual : TRobotSimulator;
ExpectedCoord: TCoordinate;
begin
ExpectedCoord := TCoordinate.Create(-3, -8);
Actual := TRobotSimulator.Create(TDirection.east, TCoordinate.Create(2, -7));
Actual.move('RRAAAAALA');
Assert.AreEqual(ExpectedCoord, Actual.Coordinate);
Assert.AreEqual(TDirection.south, Actual.Direction);
Actual.DisposeOf;
end;

initialization
TDUnitX.RegisterTestFixture(TRobotSimTest);
end.``````
``````unit uRobotSimulator;

interface

uses
System.Types, System.StrUtils;

type
TDirection = (north, east, south, west);

TCoordinate = record
x:integer;
y:integer;
constructor Create(const aX, aY:integer);
end;

TRobotSimulator = class
private
FCoordinate: TCoordinate;
FDirection: TDirection;

procedure TurnLeft;
procedure TurnRight;
public
procedure Move(const aMovement:string);
destructor Destroy; override;

property Coordinate:TCoordinate read FCoordinate;
property Direction:TDirection read FDirection;
end;

implementation

uses
System.SysUtils;

constructor TCoordinate.Create(const aX, aY:integer);
begin
x := aX;
y := aY;
end;

{ TRobotSimulator }

constructor TRobotSimulator.Create(aDirection: TDirection; aCoordinate: TCoordinate);
begin
inherited Create;
FCoordinate := TCoordinate.Create(aCoordinate.x, aCoordinate.y);
end;

destructor TRobotSimulator.Destroy;
begin
inherited;
end;

procedure TRobotSimulator.Move(const aMovement: string);
var
ch:char;
begin
for ch in aMovement do
case AnsiIndexStr(ch, ['L', 'R', 'A']) of
0: TurnLeft;
1: TurnRight;
end;
end;

procedure TRobotSimulator.TurnLeft;
begin
//   TDirection = (north, east, south, west);
if (FDirection = north) then
FDirection := west
else
FDirection := TDirection( (Ord(FDirection) - 1) MOD 4);
end;

procedure TRobotSimulator.TurnRight;
begin
//   TDirection = (north, east, south, west);
if (FDirection = west) then
FDirection := north
else
FDirection := TDirection( (Ord(FDirection) + 1) MOD 4);
end;

begin
case FDirection of
north: Inc(FCoordinate.y);
east:  Inc(FCoordinate.x);
south: Dec(FCoordinate.y);
west:  Dec(FCoordinate.x);
end;
end;

end.``````