There is a working example of the Langton's ant on github:
https://github.com/douma/langtons-ant-java
Use value objects to separate concerns and to make the code more readable
This implementation uses value objects for the ant's degree rotation and the position. Using value objects will improve the readability of your code.
Instead of writing
public Ant(int positionX, int positionY, Direction direction) {
this.positionX = positionX;
this.positionY = positionY;
this.direction = direction;
}
You could write:
public Ant(Position position, Direction direction) {
this.position = position;
this.direction = direction;
}
Where Position is simply an immutable value object:
public class Position
{
int x, y;
Position(int x, int y)
{
this.x = x;
this.y = y;
}
public Position left()
{
return new Position(this.x - 1, this.y);
}
public Position right()
{
return new Position(this.x + 1, this.y);
}
public Position up()
{
return new Position(this.x, this.y + 1);
}
public Position down()
{
return new Position(this.x, this.y - 1);
}
public int x()
{
return this.x;
}
public int y()
{
return this.y;
}
public String toString()
{
return "["+this.x+","+this.y+"]";
}
}
My advice is to also write some tests if you have not done so. Creating smaller classes makes your implementation easier to test and testing is really beneficial for this specific logic.
Code is hard to read, encapsulate logic and use clear names
By encapsulating the logic more into separate classes, your code becomes more readable. Code like this is hard to read:
public void step(World w) {
World.Color c = w.getCellColor(this.getX(), this.getY());
this.direction = (World.Color.WHITE == c) ? this.direction.right()
: this.direction.left();
w.setCellColor(this.getX(), this.getY(), c.inverse());
this.x += this.direction.deltaX;
this.y += this.direction.deltaY;
this.steps++;
}
Instead, look at the code below from the example it is almost the same as the business rules written in words:
public void moveAnt() throws Exception
{
for(int x = 0; x < this.length; x++) {
Position position = this.ant.position();
if(this.isMarked(position)) {
this.ant.forwardLeft();
this.unmark(position);
} else {
this.ant.forwardRight();
this.mark(position);
}
}
}
Business rules:
At a white square, turn 90° right, flip the color of the square,
move forward one unit
At a black square, turn 90° left, flip the
color of the square, move forward one unit
Avoid using rendering logic in the code.
Completely move this to the JFrame view implementation.