Skip to content

Instantly share code, notes, and snippets.

@christianscott
Last active November 14, 2019 14:39
Show Gist options
  • Save christianscott/60af56ea6f3d628a6ab437e5a7c11cd3 to your computer and use it in GitHub Desktop.
Save christianscott/60af56ea6f3d628a6ab437e5a7c11cd3 to your computer and use it in GitHub Desktop.
Conway's game of life
// @ts-check
const ALIVE = 1;
const DEAD = 0;
/**
* @param {0 | 1} cell
* @param {number} nNeighbours
*/
function getNextCell(cell, nNeighbours) {
if (cell === DEAD) {
return nNeighbours === 3 ? ALIVE : DEAD;
}
if (nNeighbours === 2 || nNeighbours === 3) {
return ALIVE;
}
return DEAD;
}
/**
* @param {{ length: number; }} arr
* @param {number} index
*/
function isOutOfBounds(arr, index) {
return index < 0 || index >= arr.length;
}
export const ConwaysGameBoard = {
/** @typedef {(0 | 1)[][]} ConwaysGameBoard */
/**
* @param {any[][]} arr
*/
_check(arr) {
const n = arr.length;
for (const row of arr) {
if (row.length !== n) {
throw new Error("not a square 2 dimensional array");
}
if (!row.every(el => el === ALIVE || el === DEAD)) {
throw new Error("contains values other than ALIVE or DEAD");
}
}
},
/**
* @param {any[][]} board
* @returns {ConwaysGameBoard}
*/
create(board) {
ConwaysGameBoard._check(board);
return board;
},
/** @param {ConwaysGameBoard} board */
update(board) {
const nextBoard = ConwaysGameBoard.clone(board);
for (let row = 0; row < board.length; row++) {
for (let col = 0; col < board[row].length; col++) {
const nNeighbours = ConwaysGameBoard.countNeighboursOf(board, {
row,
col
});
const cell = board[row][col];
const nextCell = getNextCell(cell, nNeighbours);
nextBoard[row][col] = nextCell;
}
}
return nextBoard;
},
/**
* @param {ConwaysGameBoard} board
* @param {{ row: number; col: number }} cellRow
*/
countNeighboursOf(board, { row: cellRow, col: cellCol }) {
let total = 0;
for (const row of [cellRow - 1, cellRow, cellRow + 1]) {
if (isOutOfBounds(board, row)) {
continue;
}
for (const col of [cellCol - 1, cellCol, cellCol + 1]) {
// don't count the current cell
if (
isOutOfBounds(board[row], col) ||
(row === cellRow && col === cellCol)
) {
continue;
}
total += board[row][col];
}
}
return total;
},
/** @param {ConwaysGameBoard} board */
print(board) {
const printed = board.map(row => row.join("")).join("\n");
console.log(printed + "\n");
},
/**
* @param {ConwaysGameBoard} board
* @returns {ConwaysGameBoard}
*/
clone(board) {
return JSON.parse(JSON.stringify(board));
}
};
import { ConwaysGameBoard } from './conways_game_of_life';
(function example() {
let board = ConwaysGameBoard.create([[1, 1, 1], [0, 0, 1], [0, 1, 1]]);
let iterations = 10;
while (iterations--) {
board = ConwaysGameBoard.update(board);
ConwaysGameBoard.print(board);
}
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment