/*
Processing source for displaying evolved ants navigating through their
mazes
*/
// representation of the world
int[][][] world;
int dx, dy;
int finish_x, finish_y;
int[] pathx;
int[] pathy;
int w, h;
// view-port configuration
int window_width = 800;
int window_height = 600;
int border = 25;
int ant_frame_delay = 2; // no of frames to skip when moving the ant
int framecounter = 0;
// ant path variables
boolean maze_complete = false;
boolean ant_finished = false;
int ant_step = 0;
int ant_x = 0;
int ant_y = 0;
// data paths
String mazeDir = "/Users/richard/snapr-workspace/dev8d/am/data/mazes";
String antDir = "/Users/richard/snapr-workspace/dev8d/am/data/ants";
// history of what's been displayed so far
long lastAnt = 0;
ArrayList oldAnts = new ArrayList();
// metadata holding variables
String antName = "";
String nextMaze = "";
String credits = "";
String antDna = "";
void setup()
{
size(window_width, window_height);
frameRate(25);
colorMode(RGB, 255);
// load base grid
load_next_path();
load_maze();
// set up the fonts
PFont font = createFont("Monospaced", 10);
textFont(font);
}
void draw()
{
drawcycle();
framecounter++;
if (framecounter == ant_frame_delay)
{
// print(ant_x + " " + ant_y + "\n");
fade_old();
world[ant_x][invert_y(ant_y)][1] = 8;
move_ant();
framecounter = 0;
}
if (maze_complete || ant_finished)
{
load_next_path();
load_maze();
}
}
File[] listFiles(String dir)
{
File file = new File(dir);
if (file.isDirectory())
{
File[] files = file.listFiles();
return files;
}
else
{
// If it's not a directory
return null;
}
}
File nextAnt()
{
File next = null;
File[] files = listFiles(antDir);
for (int i = 0; i < files.length; i++)
{
long lm = files[i].lastModified();
// is it eligible for display?
if (!contains(oldAnts, files[i].getName()))
{
// if so, is it sufficiently new and sufficiently old?
if (next == null && lm >= lastAnt)
{
next = files[i];
}
else if (next != null && lm >= lastAnt && lm <= next.lastModified())
{
next = files[i];
}
}
}
return next;
}
boolean contains(ArrayList arr, String value)
{
for (int i = 0; i < arr.size(); i++)
{
// print(arr.get(i) + " = " + value);
if (arr.get(i).equals(value))
{
return true;
}
}
return false;
}
void print_world()
{
for (int x = 0; x < w; x++)
{
for (int y = 0; y < h; y++)
{
print(world[x][y][1]);
}
print("\n");
}
print("\n\n");
}
void load_maze()
{
w = 0;
h = 0;
int sx = 0;
int sy = 0;
int ex = 0;
int ey = 0;
// print ("maze: " + nextMaze + "\n");
String lines[] = loadStrings(mazeDir + "/" + nextMaze);
for (int y = -1; y < lines.length - 1; y++)
{
if (y == -1)
{
String[] starts = split(lines[0], ' ');
sx = int(starts[0]);
sy = int(starts[1]);
ex = int(starts[2]);
ey = int(starts[3]);
h = lines.length - 1;
finish_x = ex;
finish_y = invert_y(ey);
}
else
{
String[] bits = split(lines[y + 1], " ");
if (y == 0)
{
w = bits.length - 1; // strip the newline
dx = (width - (border * 2))/w;
dy = (height - (border * 2))/h;
world = new int[w][h][2]; // x, y and layer - 0 = background and 1 = foreground
}
for (int x = 0; x < w; x++)
{
if (int(bits[x]) == 0)
{
world[x][y][0] = 0; // open space
world[x][y][1] = 0;
}
else
{
world[x][y][0] = 1; // wall
world[x][y][1] = 1;
}
}
}
}
// now set the start and finish points
int start_y = invert_y(sy);
int end_y = invert_y(ey);
world[sx][start_y][0] = 2; // start
world[sx][start_y][1] = 2;
world[ex][end_y][0] = 3; // finish
world[ex][end_y][1] = 3;
}
int invert_y(int original_y)
{
int new_y = h - original_y;
if (new_y < 0)
{
new_y *= -1;
}
return new_y - 1;
}
void load_next_path()
{
maze_complete = false;
ant_finished = false;
ant_step = 0;
File next = nextAnt();
if (next != null)
{
antName = next.getName();
oldAnts.add(antName);
}
// if there's no more ants, start again
else
{
lastAnt = 0;
oldAnts = new ArrayList();
next = nextAnt();
}
// print ("ant: " + antName + " | ");
String lines[] = loadStrings(next.getPath());
pathx = new int[lines.length - 3];
pathy = new int[lines.length - 3];
nextMaze = lines[0];
antDna = lines[1];
credits = lines[2];
for (int i = 3; i < lines.length; i++)
{
String[] coords = split(lines[i], ' ');
// print(coords[0] + coords[1]);
pathx[i - 3] = int(coords[0]);
pathy[i - 3] = int(coords[1]);
}
ant_x = pathx[0];
ant_y = pathy[0];
}
void drawcycle()
{
background(0);
for (int x = 0; x != w; x++)
{
for (int y = 0; y != h; y++)
{
if (world[x][y][1] > 3) // if the world is displaying an ant in the foreground
{
fill(ant_colour(world[x][y][1]));
}
else if (world[x][y][0] == 3) // the end
{
fill(color(255, 0, 0));
}
else if (world[x][y][0] == 2) // the start
{
fill(color(0, 255, 0));
}
else if (world[x][y][0] == 1) // a wall
{
fill(255);
}
else if (world[x][y][0] == 0) // background
{
fill(0);
}
rect(x*dx + border, y*dy + border, dx, dy);
}
}
// add the ant's name to the screen
fill(255);
text(credits, 15, 5, 700, 20);
text(antName + ": " + antDna, 15, 580, 700, 695);
}
color ant_colour(int stage)
{
switch(stage)
{
case 4:
return color(30, 30, 60);
case 5:
return color(60, 60, 105);
case 6:
return color(90, 90, 150);
case 7:
return color(120, 120, 195);
case 8:
return color(150, 150, 240);
}
return color(0, 0, 0);
}
void fade_old()
{
for (int x = 0 ; x != w; x++)
{
for (int y = 0; y != h; y++)
{
if (world[x][y][1] > 3) // is there an ant in the foreground?
{
if (world[x][y][1] == 4) // if it is the most faded allowed
{
// set it back to the background
world[x][y][1] = world[x][y][0];
}
else
{
// reduce the path by one level
world[x][y][1] = world[x][y][1] - 1;
}
}
}
}
}
void move_ant()
{
ant_step++;
if (ant_step > pathx.length - 1)
{
ant_finished = true;
}
else
{
ant_x = pathx[ant_step];
ant_y = pathy[ant_step];
}
if (ant_x == finish_x && ant_y == finish_y)
{
maze_complete = true;
}
}