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

# dgeiger's solution

## to Robot Simulator in the Delphi Pascal Track

Published at Sep 01 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

type

TDirection = (North, East, South, West);

TCoordinate = record
private
FX: Integer;
FY: Integer;

public
constructor Create(X, Y: Integer);

end;

TRobotSimulator = class
private
procedure ProcessMovement(Movement: String);
procedure TurnLeft;
procedure TurnRight;

public
Coordinate: TCoordinate;
Direction: TDirection;

constructor Create(InitialDirection: TDirection; InitialCoordinates: TCoordinate);

procedure move(Instructions: String);

end;

implementation

{ TCoordinate }

constructor TCoordinate.Create(X, Y: Integer);
begin
// Save the passed coordinates
FX := X;
FY := Y;
end;

{ TRobotSimulator }

begin
// Move one step in the direction we're facing

// Since the grid defined in the specifications is in quadrant one,
case Direction of
North:
// moving North adds one to the X coordinate
Inc(Coordinate.FY);

East:
// moving East adds one to the Y coordinate
Inc(Coordinate.FX);

South:
// moving South subtracts one from the X coordinate
Dec(Coordinate.FY);

West:
// moving West subtracts one from the Y coordinate
Dec(Coordinate.FX);
end;

end;

constructor TRobotSimulator.Create(InitialDirection: TDirection;
InitialCoordinates: TCoordinate);
begin
// Save the passed direction and coordinates
Direction := InitialDirection;
Coordinate := InitialCoordinates;
end;

procedure TRobotSimulator.move(Instructions: String);
var
Index: Integer;
begin
// Process the instructions one step at a time
for Index := 1 to Length(Instructions) do
ProcessMovement(Instructions[Index]);
end;

procedure TRobotSimulator.ProcessMovement(Movement: String);
begin
// Interpre the movement
if Movement = 'A' then
// A dvance
else
if Movement = 'L' then
// L eft
TurnLeft
else
if Movement = 'R' then
// Right
TurnRight;
end;

procedure TRobotSimulator.TurnLeft;
begin
// When turning, we can use Pred() and Succ() for part of the turn, since we
// are using an enumerated TDirection.
if Direction = North then
// Since North is the first direction in the enumeration, we can't use
// Pred(), so we need to hard-code that West is left of North
Direction := West
else
// Otherwise, use the next direction in the enumeration
Direction := Pred(Direction);
end;

procedure TRobotSimulator.TurnRight;
begin
// When turning, we can use Pred() and Succ() for part of the turn, since we
// are using an enumerated TDirection.
if Direction = West then
// Since West is the last direction in the enumeration, we can't use
// Succ(), so we need to hard-code that North is right of West
Direction := North
else
// Otherwise, use the next direction in the enumeration
Direction := Succ(Direction);
end;

end.``````