static final int side = 8;
static final char[][] lookup = makeLookup();
// creates a lookup table mapping rows/columns to their sums
static char[][] makeLookup() {
char[][] lookup = new char[(int) pow(2, side)][side];
for(int i = 0; i < lookup.length; i++) {
char[] bits = new char[side];
for(int b = 0; b < side; b++)
bits[b] = (char) ((i & (1 << b)) != 0 ? 1 : 0);
char[] sum = new char[side];
for(int b = 0; b < side; b++) {
sum[b] += bits[b == 0 ? side - 1 : b - 1]; // left
sum[b] += bits[b]; // center
sum[b] += bits[b == side - 1 ? 0 : b + 1]; // right
}
lookup[i] = sum;
}
return lookup;
}
class Game {
// duplicate data
boolean[][] board = new boolean[side][side];
Game() {
for(int x = 0; x < side; x++)
for(int y = 0; y < side; y++)
board[x][y] = random(1) > .5;
}
Game(long game) {
for(int x = 0; x < side; x++)
for(int y = 0; y < side; y++)
board[x][y] = (game & ((long) 1 << (y * side + x))) != 0;
}
int totalSum;
void step() {
// make rows for lookup
char[] rows = new char[side];
for(int x = 0; x < side; x++)
for(int y = 0; y < side; y++)
if(board[x][y])
rows[y] |= 1 << x;
// lookup sums for rows
char[][] rowSums = new char[side][side];
for(int i = 0; i < side; i++)
rowSums[i] = lookup[rows[i]];
// recalculate life
char curSum;
boolean cur;
totalSum = 0;
for(int x = 0; x < side; x++) {
for(int y = 0; y < side; y++) {
curSum = rowSums[y == 0 ? side - 1 : y - 1][x];
curSum += rowSums[y][x];
curSum += rowSums[y == side - 1 ? 0 : y + 1][x];
cur = board[x][y];
if(cur) {
// self is counted, so 3/4 instead of 2/3
if(curSum < 3 || curSum > 4)
board[x][y] = false;
} else {
if(curSum == 3)
board[x][y] = true;
}
totalSum += curSum; // non-essential
}
}
}
int size() {
int size = 0;
for(int x = 0; x < side; x++)
for(int y = 0; y < side; y++)
if(board[x][y])
size++;
return size;
}
void draw(float rectSize) {
for(int x = 0; x < side; x++)
for(int y = 0; y < side; y++)
if(board[x][y])
rect(rectSize * x, rectSize * y, rectSize, rectSize);
}
}
int[] samplePoints = {3, 3, 3};
int zoom = 4;
float offsetStep;
int zoomLevel, systemZoom;
void setup() {
size(640, 360, P3D);
frameRate(1);
colorMode(RGB, 256);
}
void draw() {
background(0);
noStroke();
offsetStep = random(8, 128);
zoomLevel = (int) random(10, 50);
systemZoom = 1 << zoomLevel;
for(int i = 0; i < 3; i++)
samplePoints[i] = (int) random(1, 5);
println("zoomLevel: " + zoomLevel);
println(samplePoints);
int xOffset = 1;
int yOffset = 1;
for(int x = 0; x < width / zoom; x++) {
for(int y = 0; y < height / zoom; y++) {
color curColor = getPoint(xOffset * systemZoom, yOffset * systemZoom);
fill(curColor);
rect(x * zoom, y * zoom, zoom, zoom);
float offAngle = brightness(curColor);
xOffset += cos(offAngle) * offsetStep;
yOffset += sin(offAngle) * offsetStep;
}
}
}
color getPoint(int x, int y) {
long interlaced = interlace(x, y);
Game game = new Game(interlaced);
float[] rgb = new float[3];
for(int i = 0; i < 3; i++) {
for(int step = 0; step < samplePoints[i]; step++) {
game.step();
//rgb[i] += game.size();
rgb[i] += game.totalSum;
}
rgb[i] /= samplePoints[i];
}
return color(rgb[0], rgb[1], rgb[2]);
}
long interlace(int x, int y) {
long interlaced = 0;
for(int i = 0; i < 32; i++) {
int curPosition = i * 2;
if(isSet(x, i))
interlaced |= 1 << curPosition;
if(isSet(y, i))
interlaced |= 1 << (curPosition + 1);
}
return interlaced;
}
boolean isSet(int x, int position) {
return (x & (1 << position)) != 0;
}
void keyPressed() {
if(key == 's') {
saveFrame("add attractor density " + samplePoints[0] + " " + samplePoints[1] + " " + samplePoints[2] + " zoom " + zoomLevel + ".png");
}
}
static public void println(char[] chars) {
println(join(strings(chars), ' '));
}
static public void println(boolean[] bits) {
println(join(strings(bits), ' '));
}
static public String[] strings(char[] chars) {
String[] strings = new String[chars.length];
for(int i = 0; i < chars.length; i++)
strings[i] = ((int) chars[i]) + "";
return strings;
}
static public String[] strings(boolean[] bits) {
String[] strings = new String[bits.length];
for(int i = 0; i < bits.length; i++)
strings[i] = bits[i] ? "1" : "0" + "";
return strings;
}
static public String binary(long x) {
String out = "";
for(int i = 63; i >= 0; i--)
out += ((x & ((long) 1 << i)) == 0) ? "0" : "1";
return out;
}
Visualization of structure within the game of Life. The first top left point is mapped to the a game of life (an 8x8 = 64-dimension binary space) and run for a while. A color is returned representing its life cycle (red intensity for the amount of cells early in the game, green mid game, blue end game). The color is used to determine which game to pick for the next cell (top to bottom, left to right). Varying zooms are chosen.