Last active
April 20, 2016 20:30
-
-
Save toke/6f52bd0a035da110c6a3 to your computer and use it in GitHub Desktop.
Langtons Ant Processing 3.0 Script
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Langton's Ant implementation | |
* Written for Processing 3.0 | |
* "Do whatever you want with it - except Weapon stuff" - License | |
* Original Author: Thomas 'toke' Kerpe | |
**/ | |
// Yes, I do globals | |
int delay = 110; // Delay between updates | |
color border = color(127); | |
color border2 = color(210,190,160); | |
color black = color(124,95,31); | |
color white = color(214,200,168); | |
Ant ant; | |
Plane plane; | |
PlaneGrid planegrid; | |
int ctr; // Statistics Counter | |
void setup() { | |
size(421, 320); | |
ctr = 0; | |
// Plane is our universe aka antverse | |
plane = new Plane(84, 64); | |
// And we have a visual representation too | |
planegrid = new PlaneGrid(plane, 5); | |
// Place an lonely ant inside | |
ant = new Ant(35, 35, Ant.SOUTH); | |
planegrid.draw(); | |
} | |
void draw(){ | |
// Actually let the ant decide where to go | |
ant.decide(plane.getState(ant.getX(), ant.getY())); | |
// Before the ant will leave the cell, toggle its color | |
plane.toggleState(ant.getX(), ant.getY()); | |
// Let the ant leave | |
ant.step(); | |
if (! plane.isInside(ant.getX(), ant.getY())) { | |
println("The ant fell off the cliff"); | |
noLoop(); | |
} | |
// Update visual representation | |
planegrid.draw(); | |
// Basic Steps gone | |
// Display Ant as red dot on grid | |
planegrid.fillCell(ant.getX(), ant.getY(), color(255,0,0)); | |
// Display Statistics | |
displayStats(ctr++, 320, 0); | |
// Display Radar "sensation" | |
planegrid.radar(ant.getX(),ant.getY(),5,370,70); | |
stroke(255,0,0); | |
fill(200,0,0); | |
print(ant.getHeading()); | |
delay(delay); | |
} | |
void displayStats(int ctr, int x, int y) { | |
assert(x <= width - 100 && x >= 0); | |
assert(y <= height - 20 && y >= 0); | |
pushMatrix(); | |
translate(x,y); | |
fill(255); | |
stroke(black); | |
rect(0,0,100,20); | |
textSize(12); | |
fill(0); | |
text("n = " + ctr, 10,15); | |
popMatrix(); | |
} | |
class Plane { | |
boolean[][] space; // Antverse | |
public final int dimX, dimY; | |
public final static boolean BLACK = true; | |
public final static boolean WHITE = false; | |
Plane(int x, int y) { | |
dimX = x; | |
dimY = y; | |
space = new boolean[x][y]; | |
// Initialize plane | |
for (int i=0; i < x; i++) { | |
for (int j=0; j < y; j++) { | |
space[i][j] = WHITE; | |
} | |
} | |
} | |
boolean getState(int x, int y) { | |
assert(x <= dimX && x >= 0); | |
assert(y <= dimY && y >= 0); | |
return space[x][y]; | |
} | |
boolean setState(int x, int y, boolean newstate) { | |
assert(x <= dimX && x >= 0); | |
assert(y <= dimY && y >= 0); | |
boolean state = getState(x,y); | |
space[x][y] = newstate; | |
return state; | |
} | |
void toggleState(int x, int y) { | |
assert(x <= dimX && x >= 0); | |
assert(y <= dimY && y >= 0); | |
space[x][y] = ! space[x][y]; | |
} | |
boolean isInside(int x, int y) { | |
if ((x >= 0 && x < dimX) && (y >= 0 && y < dimY)) { | |
return true; | |
} else { | |
return false; | |
} | |
} | |
} | |
class PlaneGrid { | |
private final Plane plane; | |
private final int spacing; // Actual grid size | |
PlaneGrid(Plane p, int size){ | |
plane = p; | |
spacing = size; | |
assert(p.dimX * size <= width); | |
assert(p.dimY * size <= height); | |
} | |
void fillCell(int x, int y, color c) { | |
fill(c); | |
rect(x * spacing, y * spacing, spacing, spacing); | |
} | |
void draw(){ | |
for (int i=0; i < plane.dimX ; i++) { | |
for (int j=0; j < plane.dimY ; j++) { | |
stroke(border2); | |
fillCell(i, j, plane.getState(i,j)?black:white); | |
} | |
} | |
} | |
void radar(int focusX, int focusY, int context, int posX, int posY){ | |
int deltaX, deltaY; | |
int size = 10; | |
pushMatrix(); | |
translate(posX, posY); | |
deltaX = focusX + 1; | |
deltaX = constrain(deltaX, context, plane.dimX - context); | |
deltaY = focusY + 1; | |
deltaY = constrain(deltaY, context, plane.dimY - context); | |
// Difference of focus center because of border | |
int centerX = focusX - deltaX; | |
int centerY = focusY - deltaY; | |
// Draw the "radar" box | |
for (int i=0-context; i < context ; i++) { | |
for (int j=0-context; j < context ; j++) { | |
int newX = deltaX + i; | |
int newY = deltaY + j; | |
fill(plane.getState(newX, newY)?black:white); | |
rect(i * size, j * size, size, size); | |
} | |
} | |
noFill(); | |
stroke(0,0,0); | |
rect(centerX * size, centerY * size, 10, 10); | |
popMatrix(); | |
} | |
} | |
/** | |
* Ant | |
* Holds state of current position and allows | |
* movement (turnLeft, turnRight, step) | |
* heading 0 = North, 1 = East, 2 = South, 3 = West | |
**/ | |
class Ant { | |
private int xPos, yPos; | |
private int heading; | |
public final static int NORTH = 0; | |
public final static int EAST = 1; | |
public final static int SOUTH = 2; | |
public final static int WEST = 3; | |
Ant(int x, int y, int direction) { | |
xPos = x; | |
yPos = y; | |
assert(direction < 4); | |
assert(direction >= 0); | |
heading = direction; | |
} | |
// Turn the ant 90° | |
void turnRight() { | |
heading = turn(1); | |
} | |
// Turn the ant -90° | |
void turnLeft() { | |
heading = turn(-1); | |
} | |
// This is the crucial part, the decision | |
void decide(boolean col) { | |
if (col == Plane.BLACK) { | |
turnLeft(); | |
} else { | |
turnRight(); | |
} | |
} | |
void step(){ | |
// Transform heading to Grid direction | |
int[][] dir = {{0, -1}, {1, 0}, {0, 1}, {-1, 0}}; | |
xPos += dir[heading][0]; | |
yPos += dir[heading][1]; | |
} | |
int getX(){ | |
return xPos; | |
} | |
int getY(){ | |
return yPos; | |
} | |
int getHeading(){ | |
return heading; | |
} | |
private int turn(int dir) { | |
heading = heading + dir; | |
// Normalize heading from 0-3° | |
heading = heading - ((heading / 4) * 4); | |
while (heading < 0) { | |
heading += 4; | |
} | |
// Retrun new heading (0..3) | |
return heading; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment