I've wrote a simulation of Langton's Ant in Java, and hope you have some suggestions to improve the code.
The class Control.java contains just the main
:
import java.io.IOException;
public class Control {
static boolean exit = false;
public static void main(String[] args) throws InterruptedException, IOException {
LangtonsAnt langtonsAnt = new LangtonsAnt(71, 71);
Gui gui = new Gui(langtonsAnt);
gui.setVisible(true);
while(!exit) {
gui.render();
Thread.sleep(10);
}
}
}
The class Gui.java has the task to create and run the GUI:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Gui extends JFrame {
LangtonsAnt langtonsAnt;
JPanel panel;
JButton button;
private final int BOX_DIM = 10;
public Gui(LangtonsAnt langtonsAnt) {
this.langtonsAnt = langtonsAnt;
setSize(830, 740);
setDefaultCloseOperation(EXIT_ON_CLOSE);
panel = new JPanel();
JPanel subPanel = new JPanel();
subPanel.setLayout(new java.awt.GridLayout(3, 1));
panel.setPreferredSize(new Dimension(710, 710));
button = new JButton("Start / Stop");
button.addActionListener(
new ActionListener() {
public void actionPerformed(ActionEvent e) {
onButtonClick();
}
});
JButton button2 = new JButton("Faster");
button2.addActionListener(
new ActionListener() {
public void actionPerformed(ActionEvent e) {
langtonsAnt.faster();
}
});
JButton button3 = new JButton("Slower");
button3.addActionListener(
new ActionListener() {
public void actionPerformed(ActionEvent e) {
langtonsAnt.slower();
}
});
add(panel, BorderLayout.WEST);
subPanel.add(button);
subPanel.add(button2);
subPanel.add(button3);
add(subPanel, BorderLayout.EAST);
setVisible(true);
}
private void onClose() {
Control.exit = true;
}
private void onButtonClick() {
isRunning = !isRunning;
}
private int countedFrames = 1;
boolean isRunning = false;
public void render() {
countedFrames++;
if(isRunning && countedFrames % langtonsAnt.speed == 0) {
langtonsAnt.tick();
countedFrames = 1;
}
Graphics graphic = panel.getGraphics();
for (int i = 0; i < langtonsAnt.getWidth(); i++) {
for (int j = 0; j < langtonsAnt.getHeight(); j++) {
if(langtonsAnt.get(i, j) == 0) {
graphic.setColor(Color.WHITE);
}
else if(langtonsAnt.get(i, j) == 1) {
graphic.setColor(Color.BLACK);
}
else if(langtonsAnt.get(i, j) == 2) {
graphic.setColor(Color.RED);
}
else if(langtonsAnt.get(i, j) == 3) {
graphic.setColor(Color.GREEN);
}
graphic.fillRect(i * BOX_DIM, j * BOX_DIM, BOX_DIM, BOX_DIM);
}
}
}
public static void antDied() {
JOptionPane.showMessageDialog(null,"Ant died.");
}
}
And finally, the class LangtonsAnt.java is responsible for the logic:
public class LangtonsAnt {
private int[][] world;
private int width;
private int height;
public int speed = 10;
public LangtonsAnt(int width, int height) {
this.width = width;
this.height = height;
world = new int[width][height];
//Field edge is getting filled up with '2'
for(int i = 0; i < world.length; i++){
for(int j = 0; j < world.length; j++){
world[i][j] = 2;
}
}
//Field gets filled up with '0' = white cells; '1' will be used for black cells; '3' for the ant
for(int i = 1; i < world.length - 1; i++){
for(int j = 1; j < world.length - 1; j++){
world[i][j] = 0;
}
}
world[35][35] = 3;
}
public void tick() {
applyRules();
}
public int get(int x, int y) {
return world[x][y];
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
public void clear() {
for(int i = 1; i < world.length - 1; i++){
for(int j = 1; j < world.length - 1; j++){
world[i][j] = 0;
}
}
}
public void faster() {
if(speed - 5 > 0) {
speed = speed - 5;
}
}
public void slower() {
speed = speed + 5;
}
private String color = "WHITE";
private String direction = "DOWN";
private void applyRules() {
int length = world.length;
int x = 0;
int y = 0;
for(int i = 0; i < length; i++) {
for(int j = 0; j < length; j++) {
if(world[i][j] == 3) {
x = i;
y = j;
}
}
}
if(color.equals("BLACK")) {
if(direction.equals("UP")) {
direction = "LEFT";
}
else if(direction.equals("DOWN")) {
direction = "RIGHT";
}
else if(direction.equals("RIGHT")) {
direction = "UP";
}
else if(direction.equals("LEFT")) {
direction = "DOWN";
}
}
else if(color.equals("WHITE")) {
if(direction.equals("UP")) {
direction = "RIGHT";
}
else if(direction.equals("DOWN")) {
direction = "LEFT";
}
else if(direction.equals("RIGHT")) {
direction = "DOWN";
}
else if(direction.equals("LEFT")) {
direction = "UP";
}
}
int xDirection = 0;
int yDirection = 0;
if(direction.equals("UP")) {
xDirection = 0;
yDirection = -1;
}
else if(direction.equals("DOWN")) {
xDirection = 0;
yDirection = 1;
}
else if(direction.equals("RIGHT")) {
xDirection = 1;
yDirection = 0;
}
else if(direction.equals("LEFT")) {
xDirection = -1;
yDirection = 0;
}
if(color.equals("WHITE")) {
world[x][y] = 1;
}
else if(color.equals("BLACK")) {
world[x][y] = 0;
}
if(x + xDirection < 69 && y + yDirection < 69) {
if(world[x + xDirection][y + yDirection] == 0) {
color = "WHITE";
}
else if(world[x + xDirection][y + yDirection] == 1) {
color = "BLACK";
}
world[x + xDirection][y + yDirection] = 3;
}
else {
Gui.antDied();
world[x][y] = 1;
Control.exit = true;
}
}
}
```