summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChun Li <chun@bibliocommons.com>2018-07-18 17:20:15 -0400
committerChun Li <chun@bibliocommons.com>2018-07-18 17:20:15 -0400
commitd24df5d0e20a65a8f4fe5fc3ad99f9687e08ab75 (patch)
treeb487f8b4d47ab87e9f51c2cf51fdfa6d4f5b5793
Initial commit.
-rw-r--r--README.md5
-rw-r--r--index.html18
-rw-r--r--life.js158
3 files changed, 181 insertions, 0 deletions
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..acaef0c
--- /dev/null
+++ b/README.md
@@ -0,0 +1,5 @@
+# Conway's Game of Life
+## Author: Chun Li
+
+Conway's Game of Life, implemented in Javascript using a canvas element. Isn't
+it mesmerizing? :)
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..f206848
--- /dev/null
+++ b/index.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="UTF-8">
+ <link rel="stylesheet" type="text/css" href="theme.css">
+ </head>
+ <body>
+ <canvas id="canvas"></canvas>
+ <br />
+ <button onClick="startGame()">Start</button>
+ <button onClick="randomize()">Randomize</button>
+ <button onClick="cleanGame()">Clear</button>
+ <button onClick="glider()">Glider</button>
+ <button onClick="update()">Next</button>
+ <button onClick="stopGame()">Stop</button>
+ <script src="life.js"></script>
+ </body>
+</html>
diff --git a/life.js b/life.js
new file mode 100644
index 0000000..dd0f990
--- /dev/null
+++ b/life.js
@@ -0,0 +1,158 @@
+// initialization
+let canvas = document.querySelector("#canvas");
+var ctx = canvas.getContext("2d");
+
+var running = false;
+var UPDATE_INTERVAL = 100; // time between updates in ms
+var CELL_SIZE = 10; // 10x10px cell size
+// game grid size
+var WIDTH = 100;
+var HEIGHT = 50;
+var CANVAS_WIDTH = CELL_SIZE * WIDTH;
+var CANVAS_HEIGHT = CELL_SIZE * HEIGHT;
+canvas.width = CANVAS_WIDTH;
+canvas.height = CANVAS_HEIGHT;
+var BACKGROUND_COLOR="#ffffff";
+var CELL_COLOR="#427df4";
+
+// 2d array containing cells
+// 0 is dead, 1 is alive
+var grid = initGrid();
+
+function getRandomInt(max) {
+ return Math.floor(Math.random() * Math.floor(max));
+}
+
+function randomize() {
+ for (let i = 0; i < grid.length; i++) {
+ grid[i] = new Array(WIDTH);
+ for (let j = 0; j < grid[i].length; j++) {
+ grid[i][j] = Math.round(Math.random());
+ }
+ }
+ paint();
+}
+
+function cleanGame() {
+ for (let i = 0; i < grid.length; i++) {
+ grid[i] = new Array(WIDTH);
+ for (let j = 0; j < grid[i].length; j++) {
+ grid[i][j] = 0;
+ }
+ }
+ paint();
+}
+
+// Puts a random glider in somewhere
+function glider() {
+ let start_row = getRandomInt(HEIGHT-5) + 2;
+ let start_col = getRandomInt(WIDTH-5) + 3;
+ let glider = [[start_row, start_col],
+ [start_row+1, start_col+1],
+ [start_row+1, start_col+2],
+ [start_row, start_col+2],
+ [start_row-1, start_col+2]];
+ for (i in glider) {
+ let coords = glider[i];
+ grid[coords[0]][coords[1]] = 1;
+ }
+ paint();
+}
+
+function initGrid() {
+ let arr = new Array(HEIGHT);
+ for (let i = 0; i < arr.length; i++) {
+ arr[i] = new Array(WIDTH);
+ for (let j = 0; j < arr[i].length; j++) {
+ arr[i][j] = 0;
+ }
+ }
+ return arr;
+};
+
+// Implements the "Rules of Life". Change this if you want to try a different
+// set of rules (for ex. Night and Day).
+//
+// Returns 1 if this cell should be alive, 0 otherwise.
+// state is the current state of the cell.
+// neighboursAlive is the number of neighbouring cells that are also alive.
+function isAlive(state, neighboursAlive) {
+ if (state === 0 && neighboursAlive === 3) {
+ return 1;
+ } else if (state === 1 && (neighboursAlive === 2 || neighboursAlive === 3)) {
+ return 1;
+ }
+ return 0;
+}
+
+// Counts the number of alive neighbours around grid[row][col].
+//
+// Change this if you want to implement grid-wrapping, or what counts as a
+// neighbour.
+function numAliveNeighbours(row, col) {
+ let numAlive = 0;
+ for (let i = -1; i <= 1; i++) {
+ for (let j = -1; j <= 1; j++) {
+ let checkRow = row+i;
+ let checkCol = col+j;
+ if (!(checkRow === row && checkCol == col)) { // don't count myself
+ // wrap around the grid boundaries
+ if (checkRow === -1) {
+ checkRow = HEIGHT-1;
+ } else if (checkRow === HEIGHT) {
+ checkRow = 0;
+ }
+ if (checkCol === -1) {
+ checkCol = WIDTH-1;
+ } else if (checkCol === WIDTH) {
+ checkCol = 0;
+ }
+ //if (checkRow >= 0 && checkRow < HEIGHT && checkCol >= 0 && checkCol < WIDTH) {
+ numAlive += grid[checkRow][checkCol];
+ //}
+ }
+ }
+ }
+ return numAlive;
+}
+
+function update() {
+ // calculate new grid
+ let new_grid = initGrid();
+ for (let i = 0; i < new_grid.length; i++) {
+ for (let j = 0; j < new_grid[i].length; j++) {
+ new_grid[i][j] = isAlive(grid[i][j], numAliveNeighbours(i, j));
+ }
+ }
+ grid = new_grid;
+
+ // paint to canvas
+ paint();
+
+ if (running === true) {
+ setTimeout(update, UPDATE_INTERVAL);
+ }
+}
+
+function paint() {
+ ctx.fillStyle = BACKGROUND_COLOR;
+ ctx.fillRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
+
+ ctx.fillStyle = CELL_COLOR;
+ for (let i = 0; i < grid.length; i++) {
+ for (let j = 0; j < grid[i].length; j++) {
+ if (grid[i][j] === 1) {
+ ctx.fillRect(CELL_SIZE*j, CELL_SIZE*i, CELL_SIZE, CELL_SIZE);
+ }
+ }
+ }
+}
+
+function startGame() {
+ running = true;
+ setTimeout(update, UPDATE_INTERVAL);
+}
+
+function stopGame() {
+ running = false;
+}