I am trying to get my Langton's Ant program working, but it has some odd behavior that I can't quite understand. For each new iteration, I don't see the chain of events mentioned in the wikipedia article:
Simplicity. During the first few hundred moves it creates very simple patterns which are often symmetric.
Chaos. After a few hundred moves, a large, irregular pattern of black and white squares appears. The ant traces a pseudo-random path until around 10,000 steps.
Emergent order. Finally the ant starts building a recurrent "highway" pattern of 104 steps that repeats indefinitely.
I generate an ant with a random y, x, and direction each time. Why is it the case then that this is my order of events:
- Builds a semi-scrambled pattern
- Makes a small staircase
- Shifts down and left, and repeats the same small structure
It seems like it is making a sort of highway, but this one is definitely not 104 steps, and it only creates one unique pattern per time that the program is run. And there is no occurrence of grand chaos that I typically see in Langton's Ant demos. I have looked at my code very closely and I cannot find out why it is performing so oddly. Perhaps I should initialize some squares as black when I begin? I am not sure. Please let me know if you know what I am doing wrong.
Here is how I am compiling (on macOS): clang -O3 -lncurses -o langton langton.c
#include <curses.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
typedef enum {Left, Down, Right, Up} Orientation;
typedef struct {int y, x; Orientation o;} Ant;
int rand_num(int lower, int upper) {return (rand() % (upper - lower + 1)) + lower;}
int main() {
initscr();
cbreak();
noecho();
int max_y, max_x;
getmaxyx(stdscr, max_y, max_x);
start_color();
use_default_colors();
init_pair(1, COLOR_BLACK, COLOR_BLACK);
init_pair(2, COLOR_RED, COLOR_RED);
srand(time(NULL));
int** grid = malloc(max_y * sizeof(int*));
for (int y = 0; y < max_y; y++) {
int* row = malloc(max_x * sizeof(int));
memset(row, 0, max_x);
grid[y] = row;
}
Ant ant = {rand_num(0, max_y - 1), rand_num(0, max_x - 1), rand_num(0, 3)};
for (int i = 0; i < 10000; i++) {
int cell = grid[ant.y][ant.x];
ant.o += !cell ? 1 : -1; // turn ant
if (ant.o < Left) ant.o = Up;
else if (ant.o > Up) ant.o = Left;
grid[ant.y][ant.x] = !cell; // invert cell
switch (ant.o) { // move forward
case Up: ant.y--; break;
case Down: ant.y++; break;
case Left: ant.x--; break;
case Right: ant.x++; break;
}
if (ant.y == max_y || ant.y < 0 || ant.x == max_x || ant.x < 0) break; // break if outside bounds
}
clear();
for (int y = 0; y < max_y; y++) {
for (int x = 0; x < max_x; x++) {
if (grid[y][x]) {
attron(COLOR_PAIR(1));
mvprintw(y, x, " ");
attroff(COLOR_PAIR(1));
}
}
}
attron(COLOR_PAIR(2));
mvprintw(ant.y, ant.x, " ");
attroff(COLOR_PAIR(2));
getch();
for (int y = 0; y < max_y; y++) free(grid[y]);
free(grid);
endwin();
}