Created
January 2, 2018 03:18
-
-
Save bvanderlaan/bdcda67395f8782958842d8e8d3b7e28 to your computer and use it in GitHub Desktop.
Here is my implementation of Conway's game of life which I banged out while between flights
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
const { expect } = require('chai'); | |
// GAME /////////////////////////////////// | |
class Cell { | |
constructor(alive = true) { | |
this.isAlive = alive; | |
} | |
die() { | |
this.isAlive = false; | |
} | |
resurrect() { | |
this.isAlive = true; | |
} | |
} | |
class Universe { | |
constructor() { | |
this.grid = []; | |
} | |
get cellCount() { | |
return this.grid.filter(({ cell }) => cell.isAlive).length; | |
} | |
addCell(x, y, cell) { | |
this.grid = this.grid.filter((tuple) => !((tuple.x === x) && (tuple.y === y))) | |
this.grid.push({ x, y, cell }); | |
} | |
getCell(x,y) { | |
const tuple = this.grid.find((tuple) => (tuple.x === x) && (tuple.y === y)); | |
return tuple ? tuple.cell : new Cell(false); | |
} | |
getNeighbours(x, y) { | |
const neighbours = [ | |
this.getCell(x - 1, y), | |
this.getCell(x - 1, y - 1), | |
this.getCell(x - 1, y + 1), | |
this.getCell(x + 1, y), | |
this.getCell(x + 1, y - 1), | |
this.getCell(x + 1, y + 1), | |
this.getCell(x, y - 1), | |
this.getCell(x, y + 1), | |
]; | |
return neighbours.filter(cell => cell.isAlive); | |
} | |
} | |
class Rules { | |
constructor(universe) { | |
this.universe = universe; | |
} | |
process() { | |
const cell = this.universe.getCell(0,0); | |
const neighbours = this.universe.getNeighbours(0,0); | |
if ((neighbours.length < 2) || (neighbours.length > 3)) { | |
cell.die(); | |
} else if (neighbours.length === 3) { | |
cell.resurrect(); | |
} | |
} | |
} | |
// //////////////////////////////////////// | |
describe('Game of Life', () => { | |
describe('Cell', () => { | |
it('should be able to be born', () => { | |
const cell = new Cell(); | |
expect(cell.isAlive).to.be.true; | |
}); | |
it('should be able to start dead', () => { | |
const cell = new Cell(false); | |
expect(cell.isAlive).to.be.false; | |
}); | |
it('should be able to be killed', () => { | |
const cell = new Cell(); | |
cell.die(); | |
expect(cell.isAlive).to.be.false; | |
}); | |
it('should be able to be reborn', () => { | |
const cell = new Cell(); | |
cell.die(); | |
cell.resurrect(); | |
expect(cell.isAlive).to.be.true; | |
}) | |
}); | |
describe('Universe', () => { | |
it('should report zero if no cells', () => { | |
const universe = new Universe(); | |
expect(universe.cellCount).to.equal(0); | |
}); | |
it('should be able to add cells', () => { | |
const universe = new Universe(); | |
const cell = new Cell(); | |
universe.addCell(0,0,cell); | |
expect(universe.cellCount).to.equal(1); | |
}); | |
it('should not report dead cells', () => { | |
const universe = new Universe(); | |
const cell1 = new Cell(); | |
universe.addCell(0,0,cell1); | |
const cell2 = new Cell(); | |
universe.addCell(0, 1, cell2); | |
cell2.die(); | |
expect(universe.cellCount).to.equal(1); | |
}); | |
it('should allow a cell to be retrieved', () => { | |
const universe = new Universe(); | |
const cell = new Cell(); | |
cell.die(); | |
universe.addCell(0,0, cell); | |
expect(universe.getCell(0,0)).to.equal(cell); | |
}); | |
it('should return a dead cell if cell does not exist', () => { | |
const universe = new Universe(); | |
expect(universe.getCell(0,0)).to.deep.equals(new Cell(false)); | |
}) | |
it('should allow cells to be overwritten', () => { | |
const universe = new Universe(); | |
const deadCell = new Cell(); | |
deadCell.die(); | |
universe.addCell(0,0, deadCell); | |
const liveCell = new Cell(); | |
universe.addCell(0,0, liveCell); | |
expect(universe.getCell(0,0)).to.equal(liveCell); | |
}); | |
it('should allow negative coordinates', () => { | |
const universe = new Universe(); | |
const cell = new Cell(); | |
universe.addCell(-20,-10, cell); | |
expect(universe.getCell(-20,-10)).to.equal(cell); | |
}); | |
it('should be able to get a cells living neighbours', () => { | |
const universe = new Universe(); | |
universe.addCell(0, 0, new Cell()); | |
universe.addCell(0, -1, new Cell()); | |
universe.addCell(1, 1, new Cell()); | |
universe.addCell(1, 0, new Cell(false)); | |
universe.addCell(10, 10, new Cell()); | |
expect(universe.getNeighbours(0,0)).to.deep.equals([ | |
new Cell(), | |
new Cell(), | |
]); | |
}); | |
it('should be able to get a cells living neighbours even if the cell does not exist', () => { | |
const universe = new Universe(); | |
universe.addCell(0, -1, new Cell()); | |
universe.addCell(1, 1, new Cell()); | |
universe.addCell(1, 0, new Cell(false)); | |
universe.addCell(10, 10, new Cell()); | |
expect(universe.getNeighbours(0,0)).to.deep.equals([ | |
new Cell(), | |
new Cell(), | |
]); | |
}); | |
it('should return an empty array if cell has no living neighbours', () => { | |
const universe = new Universe(); | |
universe.addCell(0, 0, new Cell()); | |
universe.addCell(0, -1, new Cell()); | |
universe.addCell(1, 1, new Cell()); | |
universe.addCell(1, 0, new Cell(false)); | |
universe.addCell(10, 10, new Cell()); | |
expect(universe.getNeighbours(1000,0)).to.deep.equals([]); | |
}); | |
}); | |
describe('Rules', () => { | |
// ///////////////// | |
// fewer then 2 = dead | |
// 2 or 3 = live | |
// 3 or more = dead | |
// ///////////////// | |
it('should kill cell if less then 2 neighours', () => { | |
const universe = new Universe(); | |
universe.addCell(0,0, new Cell()); | |
universe.addCell(0,1, new Cell()); | |
const rules = new Rules(universe); | |
rules.process(); | |
expect(universe.getCell(0,0).isAlive).to.be.false; | |
}); | |
it('should leave cell alive if it has 2 neighours', () => { | |
const universe = new Universe(); | |
universe.addCell(0,0, new Cell()); | |
universe.addCell(0,1, new Cell()); | |
universe.addCell(1,1, new Cell()); | |
const rules = new Rules(universe); | |
rules.process(); | |
expect(universe.getCell(0,0).isAlive).to.be.true; | |
}); | |
it('should leave cell dead if it has only 2 neighours', () => { | |
const universe = new Universe(); | |
universe.addCell(0,0, new Cell(false)); | |
universe.addCell(0,1, new Cell()); | |
universe.addCell(1,1, new Cell()); | |
const rules = new Rules(universe); | |
rules.process(); | |
expect(universe.getCell(0,0).isAlive).to.be.false; | |
}); | |
it('should resurrect cell dead if it has at least 3 neighours', () => { | |
const universe = new Universe(); | |
universe.addCell(0,0, new Cell(false)); | |
universe.addCell(0,1, new Cell()); | |
universe.addCell(1,1, new Cell()); | |
universe.addCell(1,0, new Cell()); | |
const rules = new Rules(universe); | |
rules.process(); | |
expect(universe.getCell(0,0).isAlive).to.be.true; | |
}); | |
it('should kill cell if it has more then 3 neighours', () => { | |
const universe = new Universe(); | |
universe.addCell(0,0, new Cell()); | |
universe.addCell(0,1, new Cell()); | |
universe.addCell(1,1, new Cell()); | |
universe.addCell(1,0, new Cell()); | |
universe.addCell(-1,0, new Cell()); | |
const rules = new Rules(universe); | |
rules.process(); | |
expect(universe.getCell(0,0).isAlive).to.be.false; | |
}); | |
it('should apply rules to all cells', () => { | |
const universe = new Universe(); | |
universe.addCell(0,0, new Cell()); | |
universe.addCell(0,1, new Cell()); | |
universe.addCell(1,1, new Cell()); | |
universe.addCell(1,0, new Cell()); | |
universe.addCell(-1,0, new Cell()); | |
// todo | |
const rules = new Rules(universe); | |
rules.process(); | |
expect(universe.getCell(0,0).isAlive).to.be.false; | |
expect(universe.getCell(0,1).isAlive).to.be.false; | |
expect(universe.getCell(1,0).isAlive).to.be.false; | |
expect(universe.getCell(1,1).isAlive).to.be.false; | |
expect(universe.getCell(-1,0).isAlive).to.be.false; | |
}); | |
}); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment