Langton’s ant is a two-dimensional universal Turing machine with a very simple set of rules but complex emergent behavior. Langton’s Ant was invented by Chris Langton in 1986 and runs on a square lattice of black and white cells. In that tutorial, you are going to learn how to implement Langton’s Ant in Java with a Swing User Interface.
You can also watch this tutorial in video on YouTube:
Before implementing Langton’s Ant in Java, we need to define its rules. In Langton’s Ant, squares on a plane are colored variously either black or white. We arbitrarily identify one square as the “Ant”. The Ant can travel in any of the four cardinal directions at each step it takes. The Ant moves according to the rules below:
- 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.
Representing the World
First step is to represent the World of Langton’s Ant. Like said previously, the cells of our World can have two colors: white or black. So, we need to create a Color enum with WHITE and BLACK values. We add a method to the Color enum for getting the inverse color of the current one.
Cells of our World will be represented in a two-dimensional array of Color enum in a dedicated World class. Besides, we add a size property for storing the size of the square representing the World. In the constructor of the World class, we initialize the two-dimensional array and we init the cells with WHITE value from the Color enum.
Finally, we add two methods to the World class for getting the value of the cell with coordinates (x,y) of our World and for setting the value to a cell with coordinates (x,y).
It gives us the following code for the World class:
Representing the Direction followed by an Ant
In Langton’s Ant, the Ant is arbitrarily identified as a square of the World. Besides, an Ant follows a direction. For representing the direction followed by an Ant, we define a Direction enum. This enum will have four values for each direction an Ant can follow:
We associate a 2D Vector to each value of the Direction enum. Logically, NORTH value has the Vector with coordinates (0, -1) associated, EAST value is associated with the Vector (1, 0), SOUTH value with the Vector (0, 1) and WEST with the Vector (-1, 0).
We define two methods for the Direction enum. These methods let us to implement the two rules of Langton’s Ant. The left() method returns the Direction value that is 90° to the left of the current Direction value. And the right() method returns the Direction value that is 90° to the right of the current Direction value.
It gives us the following code for the Direction enum:
Representing an Ant
Next step is to represent an Ant. For that, we define an Ant class. This class has the following properties:
- x and y integers representing the coordinates of the Ant in the World
- steps integer representing the number of steps made by the Ant in the World
- direction representing the current direction followed by the Ant in the World
Then, we write a isInWorld method taking in parameter the World and returning true is the Ant is always in the World and false otherwise. It will let us to stop the evolution of the World when the Ant crosses the borders of the World.
Now, we need to write a step method representing a step of the Ant in the World passed as an input. In that method, we start by getting the Color enum associated to the cell of the World where the Ant is. Then, we apply the rules of Langton’s Ant. So, if current cell is white, we call the right() method of the Direction value associated to the Ant. Otherwise, we call the left() method. It gives us the new Direction value for the Ant.
Now, we set the new Color to the cell where the Ant was. This new Color is obtainted by inverting the current color with a call to the inverse() method defined previously in the Color enum. After that, we update the coordinates of the Ant by applying the coordinates of the 2D Vector associated to the new Direction value of the Ant.
Finally, we have just to increment the number of steps of the Ant by one. It gives us the following code for the Ant class:
Creating the UI with Swing
For creating the User Interface of our Langton’s Ant implementation, we use the Swing API. We define an AntPanel class extending the JPanel class from the Swing API. In the constructor, we pass as an input the size of a square. With that, we can calculate the size of a pixel representing a square.
We call the setPreferredSize method of the JPanel parent object with a size of pixels by pixels. Then, we define a white background. In the paintComponent method, we draw the cells. For that, we iterate on the cells of the World object. For each cell having a BLACK value, we draw a Black rectangle.
It gives us the following implementation for the AntPanel class:
Assembling all the Pieces of the Puzzle
Last step is to assemble all the pieces of the puzzle. For that, we define a LangtonAnt class. In the constructor, we create the World. We set the Ant at the center of the World and so, we set the Black color to that cell in our World.
Then, we create a JFrame instance and we set an instance of the AntPanel as the content pane. It remains a last important thing to code. Indeed, we need to write the code for making our World evolving. For that, we use a Timer object provided in standard with Java. We create our Timer instance in a dedicated run method in the LangtonAnt class.
As input, we take the following parameters:
- maxSteps representing the maximum number of steps a Ant can make in the World
- delay representing the delay before our TimerTask starts
- period representing the period at which the TimerTask is called
So, we pass a TimerTask instance in the schedule method of our Timer with the delay and period in parameters. Inside the run method of our TimerTask instance, we start by checking if the Ant is outside the boundaries of the World or if the Ant has reached the maximum number of steps we defined.
If so, we stop the evolution of the World by calling the cancel() method of our Timer instance. Otherwise, we update the World by calling the repaint() method of our AntPanel instance and then, we call the step() method of Ant instance with the World instance in parameter. This call represents a step of the Ant in the World.
Finally, we have just the instantiate the LangtonAnt class and calling its run method in the main entry point of our class. It gives the following code for the LangtonAnt class:
Our Langton’s Ant implementation in Action
Best part of the tutorial is there since we are going to put our Langton’s Ant implementation in action. Once the application, you should see the evolution of the world and at the end, the following display:
That’s all for that tutorial.
Feel free to use comments if you have some questions concerning this Langton’s Ant implementation in Java with a Swing UI.