Skip to content

Instantly share code, notes, and snippets.

@rmela
Last active January 23, 2020 04:11
Show Gist options
  • Save rmela/76fe92595473ac07c25cf3dd1d631a38 to your computer and use it in GitHub Desktop.
Save rmela/76fe92595473ac07c25cf3dd1d631a38 to your computer and use it in GitHub Desktop.
Simple Game of Life module - ( add to package.json as "any-name-here": "gist:76fe92595473ac07c25cf3dd1d631a38" )
function toString( rows ) {
return rows
.map( row => row
.map( cell => cell.value ? '1' : '0' )
.join( ' ' )
).join("\n")
}
class Game {
constructor( rows, cols ) {
this.rows = rows
this.cols = cols
this.length = rows * cols
this.cells = []
this.initialize()
this.flattened = this.cells.flat()
}
set( row, col, value ) {
this.cells[row][col].value = value
}
get( row, col ) {
return this.cells[row][col].value
}
count( cell ) {
let cnt = 0
for( let n of cell.neighbors ) {
n = this.cells[ n.row ][n.col]
if( n.value === 1 ) {
cnt += 1
}
}
return cnt
}
initialize() {
let idx = 0
for( let rownum = 0; rownum < this.rows; ++rownum ) {
let row = this.cells[rownum] = []
for( let colnum = 0; colnum < this.cols; ++colnum ) {
let cell = { idx: idx++, row: rownum, col: colnum, value: 0 }
this.assignNeighbors( cell )
row.push( cell )
}
}
}
assignNeighbors(cell) {
let r = cell.row
let c = cell.col
let i = cell.idx
let neighbors = [
{ idx: i, row: r , col: c - 1 }, // left
{ idx: i, row: r , col: c + 1 }, // right
{ idx: i, row: r - 1, col: c }, // above
{ idx: i, row: r - 1, col: c - 1 }, // aboveLeft
{ idx: i, row: r - 1, col: c + 1 }, // aboveRight
{ idx: i, row: r + 1, col: c }, // below
{ idx: i, row: r + 1, col: c - 1 }, // belowLeft
{ idx: i, row: r + 1, col: c + 1 } // belowRight
]
let filter = cell => (
cell.row >= 0 &&
cell.row < this.rows &&
cell.col >= 0 &&
cell.col < this.cols
)
cell.neighbors = neighbors.filter( filter )
}
changes() {
let rv = []
for( let cell of this.flattened ) {
let cnt = this.count( cell )
if( cnt === 3 && cell.value === 0 ) {
//console.log( 'reviving', cell.row, cell.col )
rv.push( { row: cell.row, col: cell.col, value: 1 } )
continue
}
if( cell.value === 1 && ( cnt > 3 || cnt < 2 ) ) {
//console.log( 'killing', cell.row, cell.col )
rv.push( { row: cell.row, col: cell.col, value: 0 } )
}
}
return rv
}
apply( changes ) {
let cells = []
for( let c of changes ) {
let cell = this.cells[c.row][c.col];
cell.value = c.value
cells.push( cell )
}
return cells
}
toString() {
return toString( this.cells )
}
advance() {
return this.apply( this.changes() )
}
}
module.exports.Game = Game
{
"name": "gol",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "mocha test.js"
},
"devDependencies": {
"mocha": ""
},
"author": "[email protected]",
"license": "ISC"
}
/* Lives at package root since gists don't allow subdirs */
const assert = require('assert')
const Game = require('./index').Game
const VERTICAL = [
// Blink pattern
[ 1, 0 ],
[ 1, 1 ],
[ 1, 2 ]
]
const HORIZONTAL = [
[ 0, 1 ],
[ 1, 1 ],
[ 2, 1 ],
]
function match( game, expected ) {
for( let ridx = 0; ridx < game.rows; ++ridx ) {
for( let cidx = 0; cidx < game.cols; ++cidx ) {
if( orientation[ridx][cidx] != game.get( ridx, cidx ) )
return false
}
}
return true
}
function newGame() {
let rv = new Game( 3, 3 )
for( let [row,col] of VERTICAL ) {
rv.set( row, col, 1 )
}
return rv
}
it("should run blink", function() {
let game = newGame()
assert.equal( true, match( VERTICAL ) )
game.advance()
assert.equal( true, match( HORIZONTAL ) )
game.advance()
assert.equal( true, match( VERTICAL ) )
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment