/* built with Studio Sketchpad:
* https://sketchpad.cc
*
* observe the evolution of this sketch:
* https://studio.sketchpad.cc/sp/pad/view/ro.CZFhvmJx$BE/rev.1288
*
* authors:
*
* Michal Wallace
* Sean Siem
*
*
* license (unless otherwise specified):
* creative commons attribution-share alike 3.0 license.
* https://creativecommons.org/licenses/by-sa/3.0/
*/
// This sketch builds on a prior work, "ConwayGameOfLife", created Michal Wallace & Sean Siem
// http://studio.sketchpad.cc/sp/pad/view/ro.9$PLBJ$HcoHs4/rev.2369
//* Conway's Game of Life Mashed Up with Go
//* (as implemented in processing by Michal Wallace on 5/19/2011)
final int kGridW = 50;
final int kGridH = 50;
final int kCellW = 10;
final int kCellH = 10;
final int kMaxAge = 15;
final int kR = 0x10;
final int kG = 0x20;
final int kB = 0x40;
int[][] gGrid = new int[kGridW][kGridH];
int[][] gNext = new int[kGridW][kGridH];
int randColor()
{
int r = int(random(3));
if (0 == r) return kR +1;
if (1 == r) return kG +1;
return kB + 1;
}
void setup()
{
// processing could do it this way, but it breaks sketchpad:
//size(kGridW * kCellW, kGridH * kCellH + 50);
size(500, 500);
frameRate(10);
// initialize to a random grid:
for (int y = 0; y < kGridH; ++y)
{
for (int x = 0; x < kGridW; ++x)
{
gGrid[y][x] = (random(1) > 0.5) ? randColor() : 0;
gNext[y][x] = 0;
}
}
}
// I want to color-code the cells by age, so the value will
// be the age of the cell.
int valueAt(int x, int y)
{
// assume anything outside is dead
if ((x < 0)
|| (x >= kGridW)
|| (y < 0)
|| (y >= kGridH))
{
return 0;
}
else
{
return gGrid[y][x];
}
}
int colorAt(int x, int y)
{
int v = gGrid[y][x];
int c = v & 0xF0;
if (c == kR) return kR;
if (c == kG) return kG;
if (c == kB) return kB;
return 0;
}
class NeighborCount
{
int r = 0;
int g = 0;
int b = 0;
int n = 0;
NeighborCount(int x, int y)
{
count(x, y - 1); // N
count(x + 1, y - 1); // NE
count(x + 1, y); // E
count(x + 1, y + 1); // SE
count(x, y + 1); // S
count(x - 1, y + 1); // SW
count(x - 1, y); // W
count(x - 1, y - 1); // NW
}
void count(int x, int y)
{
int v = valueAt(x, y);
if (v > 0)
{
this.n += 1;
switch(colorAt(x, y))
{
case kR:
this.r += 1;
break;
case kG:
this.g += 1;
break;
case kB:
this.b += 1;
break;
default:
break;
}
}
}
int dominantColor()
{
int c = 0;
if (this.r >= 2) { c = kR; }
if (this.g >= 2) { c = kG; }
if (this.b >= 2) { c = kB; }
return c;
}
}
void copyGrid(int[][] fromGrid, int[][] toGrid)
{
for (y = 0; y < kGridH; ++y)
{
for (x = 0; x < kGridW; ++x)
{
toGrid[y][x] = fromGrid[y][x];
}
}
}
// Rules of Life:
// --------------------
// 1. die if neighbors < 2
// 2. stay alive if 2 or 3 neighbors
// 3. die if neigbors > 3
// 4. come alive if exactly 3 live neighbors
// 5. groups of cells randomly generate in one of 4 colors - RGBW
// 6. Clicking inside the gamespace colors a single cell to player's color (ATM - Green, but player will be able to select color later).
// 7. Game goal is to clear other colors from gamespace.
// 8.
void applyRules()
{
int x;
int y;
NeighborCount neighbors;
for (y = 0; y < kGridH; ++y)
{
for (x = 0; x < kGridW; ++x)
{
// start with a clean copy of the grid:
gNext[y][x] = 0;
neighbors = new NeighborCount(x, y);
// if alive:
if (valueAt(x, y) > 0)
{
if ((neighbors.n < 2) || (neighbors.n > 3))
{
gNext[y][x] = 0; // die
}
else
{
// get older:
int age = gGrid[y][x] & 0x0F;
int rgb = gGrid[y][x] & 0xF0;
age = constrain(age + 1, 0, kMaxAge);
gNext[y][x] = rgb + age;
}
}
else if (3 == neighbors.n)
{
gNext[y][x] = neighbors.dominantColor() + 1; // birth
}
}
}
copyGrid(gNext, gGrid);
}
void draw()
{
int x;
int y;
applyRules();
// reset colors
background(0);
stroke(color(0, 0, 0));
fill(color(255, 255, 255));
// draw the grid:
for (y = 0; y < kGridH; ++y)
{
for (x = 0; x < kGridW; ++x)
{
if (0 != gGrid[y][x])
{
drawCell(x, y);
}
}
}
}
void drawCell(int x, int y)
{
int cell = gGrid[y][x];
int rgb = 0xF0 & cell;
int age = 0x0F & cell;
int shade = 256 - (8 * age);
if (rgb == kR)
fill(color(shade, 0, 0));
else if (rgb == kG)
fill(color(0, shade, 0));
else if (rgb == kB)
fill(color(0, 0, shade));
else
fill(color(shade, shade, shade));
rect(x * kCellW, y * kCellH, kCellW, kCellH);
}
// paint with the mouse:
void mouseDragged()
{
onMouse();
}
void mousePressed()
{
onMouse();
}
void mouseClicked()
{
onMouse();
}
void onMouse()
{
int cellX = int(mouseX / kCellW);
int cellY = int(mouseY / kCellH);
if (cellY < kGridH)
{
gGrid[cellY][cellX] = kG + 1;
drawCell(cellX, cellY);
}
}