> show canvas only <


/* built with Studio Sketchpad: 
 *   https://sketchpad.cc
 * 
 * observe the evolution of this sketch: 
 *   https://studio.sketchpad.cc/sp/pad/view/ro.xpuAsNzn4Y$/rev.2369
 * 
 * authors: 
 *   Sean
 *   Michal Wallace
 *   Sean Siem

 * license (unless otherwise specified): 
 *   creative commons attribution-share alike 3.0 license.
 *   https://creativecommons.org/licenses/by-sa/3.0/ 
 */ 



/* Conway's Game of Life
 * (as implemented in processing by Michal Wallace on 5/19/2011)
 * This code is in the public domain.
 */

int kGridW = 50;
int kGridH = 50;
int kCellW = 10;
int kCellH = 10;
int kMaxAge = 16;

int[][] gGrid = new int[kGridW][kGridH];
int[][] gNext = new int[kGridW][kGridH];

void setup()
{
    // processing could do it this way, but it  breaks sketchpad:
    //size(kGridW * kCellW, kGridH * kCellH + 50);
    size(500, 550);
    frameRate(6);
    
    // 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) ? 1 : 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];
    }
}

// Returns 1 or 0
int count(int x, int y)
{
    int v = valueAt(x, y);
    return (v==0) ? 0 : 1;
}

// you consider all 8 neighbors :)
int neighborCount(int x, int y)
{
    return 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 copyGrid(fromGrid, 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
void applyRules()
{
    int x;
    int y;
    int 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 = neighborCount(x, y);
            
            // if alive:
            if (count(x, y) == 1)
            {
                if ((neighbors < 2) || (neighbors > 3))
                {
                    gNext[y][x] = 0; // die
                }
                else
                {
                    // get older:
                    gNext[y][x] = constrain(gGrid[y][x] + 1, 0, kMaxAge);
                }
            }
            else if (3 == neighbors)
            {
                gNext[y][x] = 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(x, y)
{
    // draw cells darker as they age:
    int shade = 256 - (8 * gGrid[y][x]);
    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] = 1;
        drawCell(cellX, cellY);
    }
}