> show canvas only <


/* built with Studio Sketchpad: 
 *   https://sketchpad.cc
 * 
 * observe the evolution of this sketch: 
 *   https://studio.sketchpad.cc/sp/pad/view/ro.SfVsIFyZeST/rev.3425
 * 
 * authors: 
 *   Ruben Nijveld

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



// Press space or p to start the simulation, press space or p again to pause
// Use the mouse to activate cells (you can click + drag to activate more)
// Rules: http://en.wikipedia.org/wiki/Conway's_Game_of_Life


int CELLS_X = 40;
int CELLS_Y = 40;
int CELL_X_SIZE;
int CELL_Y_SIZE;
boolean isPause;
boolean changed;

int frame;
int PROCESS_EVERY = 4;

int prevMouseX;
int prevMouseY;

CellList cells;

void setup() {
    // settings for processing
    background(255);
    size(400, 400);
    frameRate(60);
    rectMode(CORNER);
    strokeWeight(1);
    strokeCap(PROJECT);
    strokeJoin(MITER);
    
    // game settings and variables
    CELL_X_SIZE = round(width / CELLS_X);
    CELL_Y_SIZE = round(height / CELLS_Y);
    cells = new CellList();
    isPause = true;
    changed = true;
    
    frame = 0;
} 

void draw() {
    if(frame >= PROCESS_EVERY) {
        frame = 0;
    }
    
    if(!isPause && frame == 0) {
        cells.update();
    }
    
    if(changed || frame == 0) {
        cells.draw();
        changed = false;
    }
    
    if(mousePressed && (mouseX != prevMouseX || mouseY != prevMouseY)) {
        cells.getcell(
            floor(mouseX / CELL_X_SIZE), 
            floor(mouseY / CELL_Y_SIZE)
        ).alive = true;
    }
    
    frame += 1;
}

void mousePressed() {
    prevMouseX = mouseX;
    prevMouseY = mouseY;
}

void mouseClicked() {
    if(prevMouseX == mouseX && prevMouseY == mouseY) {
        cells.getcell(
            floor(mouseX / CELL_X_SIZE), 
            floor(mouseY / CELL_Y_SIZE)
        ).toggle();
        changed = true;
    }
}

void keyPressed() {
    if(key == 'p' || key == 'P' || key == ' ') {
        isPause = !isPause;
        changed = true;
    }
}

class Cell {
    int cellX;
    int cellY;
    boolean alive;
    int livingNb;
    
    Cell(int x, int y) {
        cellX = x;
        cellY = y;
        alive = false;
        livingNb = 0;
    }
    
    void toggle() {
        alive = !alive;
    }
    
    void sweep() {
        livingNb = 0;
        for(int xPos = -1; xPos <= 1; xPos++) {
            for(int yPos = -1; yPos <= 1; yPos++) {
                if(xPos == 0 && yPos == 0) {
                    continue;
                }
                if(cells.isAlive(cellX+xPos, cellY+yPos)) {
                    livingNb += 1;
                }
            }
        }
    }
    
    void update() {
        if(!alive && livingNb == 3) {
            alive = true;
        } else if(alive && (livingNb < 2 || livingNb > 3)) {
            alive = false;
        }
    }
    
    void draw() {
        if(isPause) {
            stroke(0);
        } else {
            stroke(75);
        }
        
        if(alive) {
            fill(255, 255, 0);
        } else {
            fill(40);
        }
        
        rect(
            cellX * CELL_X_SIZE, 
            cellY * CELL_Y_SIZE,
            CELL_X_SIZE, 
            CELL_Y_SIZE
        );
    }
}

class CellList {
    Cell[] cells;
    
    CellList() {
        cells = new Cell[CELLS_X * CELLS_Y];
        for(int currX = 0; currX < CELLS_X; currX++) {
            for(int currY = 0; currY < CELLS_Y; currY++) {
                cells[currX + CELLS_Y * currY] = new Cell(currX, currY);
            }
        }
    }
    
    void getcell(int xPos, int yPos) {
        return this.cells[xPos + CELLS_Y * yPos];
    }
    
    void isAlive(int xPos, int yPos) {
        if(xPos < 0 || yPos < 0) {
            return false;
        }
        
        if(xPos >= CELLS_X || yPos >= CELLS_Y) {
            return false;
        }
        
        return this.cells[xPos + CELLS_Y * yPos].alive;
    }
    
    void update() {
        for(int i = 0; i < CELLS_X * CELLS_Y; i++) {
            this.cells[i].sweep();
        }
        for(int i = 0; i < CELLS_X * CELLS_Y; i++) {
            this.cells[i].update();
        }
    }
    
    void draw() {
        for(int i = 0; i < CELLS_X * CELLS_Y; i++) {
            this.cells[i].draw();
        }
    }
}