/* built with Studio Sketchpad:
* https://sketchpad.cc
*
* observe the evolution of this sketch:
* https://studio.sketchpad.cc/sp/pad/view/ro.SvZIRjMIwhS/rev.2619
*
* authors:
* Oliver Skanberg-Tippen
*
* license (unless otherwise specified):
* creative commons attribution-share alike 3.0 license.
* https://creativecommons.org/licenses/by-sa/3.0/
*/
CellGrid grid;
int WIDTH = 33;
int HEIGHT = 20;
int CELL_SIZE = 15;
/*
* Part of processing.js - runs once
*/
void setup()
{
grid = new CellGrid(WIDTH, HEIGHT);
//set the size of the canvas
size(WIDTH * CELL_SIZE, HEIGHT * CELL_SIZE);
// smooth edges
smooth();
// limit the number of frames per second
frameRate(5);
// set the width of the line.
strokeWeight(3);
//draw the background to 80 grey
background(80);
}
/*
* Part of processing.js - runs repeatedly
*/
void draw()
{
//draw the grid
print();
//calculate the next step
calcNext();
//step the grid to its next state
grid.stepGrid();
}
/*
* For each cell, check the number of alive neighbours
* if less than two (under-population) cell dies
* if more than two (overcrowding) cell dies (this is more strict than Conway's)
*/
void calcNext()
{
int neighbours = 0;
for (int x = 0; x < WIDTH; x++) {
for (int y = 0; y < HEIGHT; y++) {
neighbours = grid.getAliveNeighbours(x, y);
if (neighbours < 2 || neighbours > 2) {
grid.setCellNState(x, y, false);
} else {
grid.setCellNState(x, y, true);
}
}
}
}
/*
* For each cell, check its state; colour (230, 230, 230) if alive
* and 80 grey if not alive.
*/
void print()
{
for (int x = 0; x < WIDTH; x++) {
for (int y = 0; y < HEIGHT; y++) {
if (grid.getCellState(x, y) == true) {
//set fill to RGB 230, 230, 230
fill(230, 230, 230);
//draw the rectangle
rect(x * CELL_SIZE, y * CELL_SIZE, CELL_SIZE, CELL_SIZE);
} else {
fill(80);
rect(x * CELL_SIZE, y * CELL_SIZE, CELL_SIZE, CELL_SIZE);
}
}
}
}
/*
* Part of processing.js - called if mouse pressed within the canvas
*/
void mousePressed()
{
grid.reset();
}
class CellGrid
{
Cell[][] grid;
int HEIGHT;
int WIDTH;
CellGrid(int width, int height)
{
this.HEIGHT = height;
this.WIDTH = width;
//instantiate grid with set height and width
grid = new Cell[WIDTH][HEIGHT];
for (int x = 0; x < WIDTH; x++) {
for (int y = 0; y < HEIGHT; y++) {
grid[x][y] = new Cell();
}
}
}
boolean getCellState(int x, int y)
{
return grid[x][y].isAlive();
}
void setCellState(int x, int y, boolean isAlive)
{
grid[x][y].setAlive(isAlive);
}
/*
* Repopulate the grid with new cells,
*/
void reset()
{
for (int x = 0; x < WIDTH; x++) {
for (int y = 0; y < HEIGHT; y++) {
grid[x][y] = new Cell();
}
}
}
/*
* Set the next state of a given cell
*/
void setCellNState(int x, int y, boolean isAlive)
{
grid[x][y].setNAlive(isAlive);
}
/*
* For each cell, update to next state
*/
void stepGrid()
{
for (Cell[] row: grid) {
for (Cell c: row) {
c.step();
}
}
}
/*
* Count and return the number of alive neighbours of
* a given cell
*/
int getAliveNeighbours(int x, int y)
{
int tmp = 0;
//y-1, y+1, x-1, x+1, taking into account 'wrapping around'
int ym, yp, xm, xp;
if (y == 0) {
ym = HEIGHT - 1;
yp = 1;
} else {
//checking above the width and height limit will check the opposite
//side of the grid - as if grid is 3d and wraps around
ym = (y-1) % HEIGHT;
yp = (y+1) % HEIGHT;
}
if (x == 0) {
xm = WIDTH - 1;
xp = 1;
} else {
xm = (x-1) % WIDTH;
xp = (x+1) % WIDTH;
}
//increment tmp for each appropriate live cell
tmp += getCellState(xm, ym) ? 1 : 0;
tmp += getCellState(xm, y) ? 1 : 0;
tmp += getCellState(xm, yp) ? 1 : 0;
tmp += getCellState(x, ym) ? 1 : 0;
tmp += getCellState(x, yp) ? 1 : 0;
tmp += getCellState(xp, ym) ? 1 : 0;
tmp += getCellState(xp, y) ? 1 : 0;
tmp += getCellState(xp, yp) ? 1 : 0;
return tmp;
}
}
class Cell
{
//alive now, alive next step
boolean alive, nAlive;
Cell()
{
//random chance of being alive when instantiated
if (Math.random() < 0.03) {
this.alive = true;
} else {
this.alive = false;
}
this.nAlive = false;
}
boolean isAlive()
{
return alive;
}
void setAlive(boolean state)
{
alive = state;
}
/*
* Set whether alive in the next step
*/
void setNAlive(boolean state)
{
nAlive = state;
}
/*
* Step the cell to next state
*/
void step()
{
alive = nAlive;
}
}