Monday, September 20, 2010

Mars Rover Solution in Java 5

Mars Rover Solution in Java 5

Mars Rover Problem

A squad of robotic rovers are to be landed by NASA on a plateau on Mars.

This plateau, which is curiously rectangular, must be navigated by the rovers so that their on-board cameras can get a complete view of the surrounding terrain to send back to Earth.

A rover’s position and location is represented by a combination of x and y co-ordinates and a letter representing one of the four cardinal compass points. The plateau is divided up into a grid to simplify navigation. An example position might be 0, 0, N, which means the rover is in the bottom left corner and facing North.

In order to control a rover , NASA sends a simple string of letters. The possible letters are ‘L’, ‘R’ and ‘M’. ‘L’ and ‘R’ makes the rover spin 90 degrees left or right respectively, without moving from its current spot. ‘M’ means move forward one grid point, and maintain the same heading.

Assume that the square directly North from (x, y) is (x, y+1).

INPUT:

The first line of input is the upper-right coordinates of the plateau, the lower-left coordinates are assumed to be 0,0.

The rest of the input is information pertaining to the rovers that have been deployed. Each rover has two lines of input. The first line gives the rover’s position, and the second line is a series of instructions telling the rover how to explore the plateau.

The position is made up of two integers and a letter separated by spaces, corresponding to the x and y co-ordinates and the rover’s orientation.

Each rover will be finished sequentially, which means that the second rover won’t start to move until the first one has finished moving.

OUTPUT

The output for each rover should be its final co-ordinates and heading.

INPUT AND OUTPUT

Test Input:

5 5
1 2 N
LMLMLMLMM
3 3 E
MMRMMRMRRM

Expected Output:

1 3 N
5 1 E


Java 5 Solution:
PositionIF.java
package rover;

/**
 * Represents a location within a planet. 
 * It is intended to abstract away implementation details.
 * @author rrosary
 */
public interface PositionIF {
 
 public static final class Axis {
  int axis = 0;
  
  public Axis(int axis) {
   this.axis = axis;
  }
  protected void increment() {
   axis++;
  }
  protected void decrement() {
   axis--;
  }
  public int getAxis() {
   return axis;
  }
 }
  
 public enum Direction {

  NORTH {
   @Override
   public Direction right() {
    return EAST;
   }
   @Override
   public Direction left() {
    return WEST;
   }
  },

  EAST {
   @Override
   public Direction right() {
    return SOUTH;
   }
   @Override
   public Direction left() {
    return NORTH;
   }
  },

  SOUTH {
   @Override
   public Direction right() {
    return WEST;
   }
   @Override
   public Direction left() {
    return EAST;
   }
  },

  WEST {
   @Override
   public Direction right() {
    return NORTH;
   }
   @Override
   public Direction left() {
    return SOUTH;
   }
  };

  public abstract Direction right();

  public abstract Direction left();
 }
 
 public Axis getX();
 public Axis getY();
 public Direction getDirection();
 @Override
 public String toString();
 
}
Position.java
package rover;

public class Position implements PositionIF {
 
 private Axis x = null;
 private Axis y = null;
 private Direction direction = null;
  
 public Position(Axis x, Axis y, Direction direction) {
  if (x == null || y == null || direction == null) {
   throw new IllegalArgumentException("Position's attributes can't be null");
  }
  this.direction = direction;
  this.x = x;
  this.y = y;
 }
  
 protected void setDirectionRight() {
  direction = direction.right();
 }
 
 protected void setDirectionLeft() {
  direction = direction.left();
 }
 
 @Override
 public Axis getX() {
  return x;
 }

 @Override
 public Axis getY() {
  return y;
 }

 @Override
 public Direction getDirection() {
  return direction;
 }

 @Override
 public String toString() {
  return getX().getAxis() + " : " + getY().getAxis() + " : " 
  + getDirection().name();
 }
 
}
Rover.java
package rover;

import rover.PositionIF.Axis;
import rover.PositionIF.Direction;

/**
 * Object represents the Mars Rover.
 * @author rrosary
 */
public class Rover {
 private Position position = null;
 
 public enum Command {
  RIGHT, LEFT, MOVE;
  private void process(Position position) {
   switch (this) {
    case RIGHT:
     position.setDirectionRight();
     break;
    case LEFT:
     position.setDirectionLeft();
     break;
    case MOVE:
     switch (position.getDirection()) {
      case NORTH:
       position.getY().increment();
       break;
      case EAST:
       position.getX().increment();
       break;
      case SOUTH:
       position.getY().decrement();
       break;
      case WEST:
       position.getX().decrement();
     }
   }
  }
 };
 
 public Rover(Axis x, Axis y, Direction direction) {
  this.position = new Position(x, y, direction);
 }
 
 public void processCommands(Command[] commands) {
  for (int i = 0; i < commands.length; i++) {
   commands[i].process(position);
  }
 }
 
 public PositionIF getPosition() {
  return position;
 }
}

RoverTest.java
package test;

import rover.PositionIF;
import rover.Rover;
import rover.PositionIF.Direction;
import rover.Rover.Command;

/**
 * Test Class.
 * @author rrosary
 */
public class RoverTest {

 /**
  * @param args
  */
 public static void main(String[] args) {
  // Test 1 LMLMLMLMM
  Rover rover1 = new Rover(new PositionIF.Axis(1),
   new PositionIF.Axis(2), rover.PositionIF.Direction.NORTH);
  rover1.processCommands(new Command[] { Command.LEFT, Command.MOVE,
   Command.LEFT, Command.MOVE, Command.LEFT, Command.MOVE,
   Command.LEFT, Command.MOVE, Command.MOVE });
  System.out.println(rover1.getPosition());
  // Test 2 MMRMMRMRRM
  Rover rover2 = new Rover(new PositionIF.Axis(3),
   new PositionIF.Axis(3), Direction.EAST);
  rover2.processCommands(new Command[] { Command.MOVE, Command.MOVE,
   Command.RIGHT, Command.MOVE, Command.MOVE, Command.RIGHT,
   Command.MOVE, Command.RIGHT, Command.RIGHT, Command.MOVE });
  System.out.println(rover2.getPosition());
 }

}