Using the State Pattern to solve the Mars Rover Kata – Part 1

If you have not come across this kata before, this is it:

A Mars Rover has been developed to map out the landscape. It’s a small robot which can move on a grid, controlled by simple commands.

In this example, it will move on a 5×5 grid with a simple co-ordinate system – 0,0 is the bottom left, 4,4 is the top right.

We can control the Rover by sending it a string consisting of commands, such as the following:

RFLFFRF

R means rotate right 90 degrees, L rotate left 90 degrees, and F means move forward one square in the direction the Rover is currently facing. The Rover starts at 0,0 facing North (“up” the grid).

We need a program which will accept strings of commands at the command line, and return the grid position of the Rover after those commands

The objective of this kata is to use two patterns to solve this problem. The State pattern and the Command Pattern

In this post we will only be looking at the state pattern.

Head First Design Patterns

I have read of lot of literature on the the GoF patterns. I am sad to say that in nearly every case I have hated how the GoF patterns have been described. So theoretical. Very dry to read. If you are like me, then go any buy Head First Design Patterns. Its Java but its easy to do the examples in C#. This was the first pattern book that I read that I actually enjoyed reading.

The State Pattern

The state patterns is a behavioral software design pattern. The state pattern allows an object to alter its behaviour when its internal state changes. The object will appear to change its class.

The state pattern is an alternative to putting lots of conditionals in your context by encapsulating the behaviours within state objects, you can simple change the state object in context to change its behaviour.

Landscape

The starting point for the kata is to create the landscape that the rover will move in. First step is to create the interface

public interface ILandscape
{

}

No properties or methods now as I don’t know how I will use it.

Then next to look at is setting the direction of the rover. Create the interface to be used

public interface IDirection
{

}

For each direction we need to test turning left and turning right.

Original Direction Direction after turning left Direction after turning right
North West East
East North South
South East West
West South North

Now that we have the we have the interface, its time to start with the first direction. For no other reason, we will start with North

public class North : IDirection
{

}

The first test we want to right is turn left.

[Test]
public void When_North_And_Turn_Left_Direction_Should_Be_West()
{
    var direction = new North(_landscape);
    var newdirection = direction.TurnLeft();
    Assert.That(newdirection, Is.TypeOf(typeof (West)));
}

The code wont even compile, as we need to make a few changes to the interfaces already in use

public interface IDirection
{
    IDirection TurnLeft();
    IDirection TurnRight();
}

Now need to update the North class

public class North : IDirection
{
    private readonly ILandscape _landscape;

    public North(ILandscape landscape)
    {
        _landscape = landscape;
    }

    public IDirection TurnLeft()
    {
        return new West(_landscape);
    }

    public IDirection TurnRight()
    {
        return new East(_landscape);
    }

    public override string ToString()
    {
        return "North";
    }

}

Run the test again. Passes.

Now to write the next test. When North turn right

[Test]
public void When_North_And_Turn_Right_Direction_Should_Be_East()
{
    var direction = new North(_landscape);
    var newdirection = direction.TurnRight();
    Assert.That(newdirection, Is.TypeOf(typeof(East)));
}

All good. Now we just repeat for all the directions.

Here are all the completed tests

[Test]
public void When_East_And_Turn_Left_Direction_Should_Be_North()
{
    var direction = new East(_landscape);
    var newdirection = direction.TurnLeft();
    Assert.That(newdirection, Is.TypeOf(typeof(North)));
}

[Test]
public void When_East_And_Turn_Right_Direction_Should_Be_South()
{
    var direction = new East(_landscape);
    var newdirection = direction.TurnRight();
    Assert.That(newdirection, Is.TypeOf(typeof(South)));
}

[Test]
public void When_South_And_Turn_Left_Direction_Should_Be_East()
{
    var direction = new South(_landscape);
    var newdirection = direction.TurnLeft();
    Assert.That(newdirection, Is.TypeOf(typeof(East)));
}

[Test]
public void When_South_And_Turn_Right_Direction_Should_Be_West()
{
    var direction = new South(_landscape);
    var newdirection = direction.TurnRight();
    Assert.That(newdirection, Is.TypeOf(typeof(West)));
}

[Test]
public void When_West_And_Turn_Left_Direction_Should_Be_South()
{
    var direction = new West(_landscape);
    var newdirection = direction.TurnLeft();
    Assert.That(newdirection, Is.TypeOf(typeof(South)));
}

[Test]
public void When_West_And_Turn_Right_Direction_Should_Be_North()
{
    var direction = new West(_landscape);
    var newdirection = direction.TurnRight();
    Assert.That(newdirection, Is.TypeOf(typeof(North)));
}

And all the completed classes for each direction

public class East : IDirection
{
    private readonly ILandscape _landscape;

    public East(ILandscape landscape)
    {
        _landscape = landscape;
    }

    public IDirection TurnLeft()
    {
        return new North(_landscape);
    }

    public IDirection TurnRight()
    {
        return new South(_landscape);
    }

    public override string ToString()
    {
        return "East";
    }
}

public class South : IDirection
{
    private readonly ILandscape _landscape;

    public South(ILandscape landscape)
    {
        _landscape = landscape;
    }

    public IDirection TurnLeft()
    {
        return new East(_landscape);
    }

    public IDirection TurnRight()
    {
        return new West(_landscape);
    }

    public override string ToString()
    {
        return "South";
    }
}

public class West : IDirection
{
    private readonly ILandscape _landscape;

    public West(ILandscape landscape)
    {
        _landscape = landscape;
    }

    public IDirection TurnLeft()
    {
        return new South(_landscape);
    }

    public IDirection TurnRight()
    {
        return new North(_landscape);
    }

    public override string ToString()
    {
        return "West";
    }
}

In the next post, we will work on the rover.

Advertisement
About

My musing about anything and everything

Tagged with: , , , , ,
Posted in Kata, Mars Rover, TDD
3 comments on “Using the State Pattern to solve the Mars Rover Kata – Part 1
  1. […] This is the next part of the Mars Rover Kata. Part 1 can be found here. […]

  2. […] is the third and final part to solve the Mars Rover kata. Part 1 and Part 2 to view what has been done […]

  3. Andrew Gunn says:

    Great blog series and solid code 🙂

    Whilst I agree with using the State Pattern, I’m not comfortable with `Direction` having a dependency of `ILandscape`. `IDirection` has two methods that don’t this dependency (`TurnLeft` and `TurnRight`). There is only one method that uses it (`Move`), but that’s not enough for it to make it a dependency. After all, a dependency is something a class cannot live without, which is why it’s needed in the ctor. The fact that any of the direction classes don’t make use of this dependency strengthens my point – it’s only in the second blog post that `Move` is added to `IDirection`.

    Instead, I’d suggest changing the signature of `Move` to accept an argument of type `ILandscape`. Similar to how the commands work.

    Assuming a change was made to `Landscape` to allow the start position to be set, and a similar one to `Rover` for the start direction, `Rover` could simply accept a single dependency of `IDirection` IF we continue to have a dependency of `ILandscape` on `Direction`. This doesn’t make much sense, but `Rover` only needs to move, turn left, and turn right, and it can do all these things from `IDirection`. Although if we adopt my approach, `Rover` would still need both `IDirection` AND `ILandscape` dependencies because `ILandscape` will be passed to `IDirection.Move(…)`.

    I like that each direction class can dictate how to move forward, but I’d consider the dependency graph a little bit.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Enter your email address to subscribe to this blog and receive notifications of new posts by email.

Join 13 other subscribers
%d bloggers like this: