Created
September 21, 2012 20:22
-
-
Save alexbeletsky/3763692 to your computer and use it in GitHub Desktop.
Game of Life in 50 lines and 20 specs
This file contains 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
// http://en.wikipedia.org/wiki/Conway's_Game_of_Life | |
var Game = { | |
init: function (options) { | |
this.grid = new Grid(options); | |
}, | |
putCell: function (x, y, state) { | |
this.grid.putCell(x, y, state); | |
}, | |
getCell: function (x, y) { | |
return this.grid.getCell(x, y); | |
}, | |
nextStep: function () { | |
var cells = this.grid.allCells(); | |
_.each(cells, function(currentCell) { | |
var neighboursCount = getNeighboursCountFor(currentCell, cells); | |
var nextCellState = getNextCellState(currentCell, neighboursCount); | |
currentCell.cell.setStateTo(nextCellState); | |
}); | |
function getNeighboursCountFor(currentCell, cells) { | |
var neighboursCells = _.filter(cells, function (otherCell) { | |
return isCloseTo(currentCell, otherCell); | |
function isCloseTo(currentCell, otherCell) { | |
var yDistance = otherCell.y - currentCell.y; | |
var xDistance = otherCell.x - currentCell.x; | |
return (yDistance !== 0 || xDistance !== 0) && (yDistance >= 1 || xDistance >= 1); | |
} | |
}); | |
return neighboursCells.length; | |
} | |
function getNextCellState(currentCell, neighboursCount) { | |
if (currentCell.cell.state === CellState.Dead && neighboursCount === 3) { | |
return CellState.Live; | |
} else if (neighboursCount < 2 || neighboursCount >= 3) { | |
return CellState.Dead; | |
} | |
return currentCell.cell.state; | |
} | |
} | |
}; |
This file contains 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
describe('game spec', function () { | |
describe('when game is initialing', function () { | |
beforeEach(function () { | |
Game.init(); | |
}); | |
it ('should create game field', function () { | |
expect(Game.grid).toBeDefined(); | |
}); | |
}); | |
describe('when game is constructing with options', function () { | |
beforeEach(function () { | |
Game.init({ height: 4, width: 14}); | |
}); | |
it ('should create game field with dimentions', function () { | |
expect(Game.grid.height).toEqual(4); | |
expect(Game.grid.width).toEqual(14); | |
}); | |
}); | |
describe('when cell are placed on game', function () { | |
beforeEach(function () { | |
Game.init({ height: 4, width: 4}); | |
Game.putCell(0, 2); | |
}); | |
it ('should field have corresponding cell', function () { | |
expect(Game.getCell(0, 2)).toBeDefined(); | |
}); | |
}); | |
describe('when game step is happen', function () { | |
beforeEach(function () { | |
Game.init({ height: 4, width: 4}); | |
}); | |
describe('live cell with fewer than two live neighbours', function () { | |
beforeEach(function () { | |
Game.putCell(0, 0); | |
Game.nextStep(); | |
}); | |
it ('should cell die', function () { | |
expect(Game.getCell(0, 0).state).toEqual(CellState.Dead); | |
}); | |
}); | |
describe('live cell with fewer than two live neighbours', function () { | |
beforeEach(function () { | |
Game.putCell(0, 0); | |
Game.putCell(0, 1); | |
Game.nextStep(); | |
}); | |
it ('should cell die', function () { | |
expect(Game.getCell(0, 0).state).toEqual(CellState.Dead); | |
}); | |
}); | |
describe('live cell with two or three live neighbours lives on to the next generation', function () { | |
beforeEach(function () { | |
Game.putCell(0, 0); | |
Game.putCell(0, 1); | |
Game.putCell(1, 0); | |
Game.nextStep(); | |
}); | |
it ('should cell live', function () { | |
expect(Game.getCell(0, 0).state).toEqual(CellState.Live); | |
}); | |
it ('rest cells should be dead', function () { | |
expect(Game.getCell(0, 1).state).toEqual(CellState.Dead); | |
expect(Game.getCell(1, 0).state).toEqual(CellState.Dead); | |
}); | |
}); | |
describe('live cell with more than three live neighbours dies, as if by overcrowding', function () { | |
beforeEach(function () { | |
Game.putCell(0, 0); | |
Game.putCell(0, 1); | |
Game.putCell(1, 0); | |
Game.putCell(1, 1); | |
Game.nextStep(); | |
}); | |
it ('should die', function () { | |
expect(Game.getCell(0, 0).state).toEqual(CellState.Dead); | |
}); | |
}); | |
describe('dead cell with exactly three live neighbours becomes a live cell, as if by reproduction', function () { | |
beforeEach(function () { | |
Game.putCell(0, 0, CellState.Dead); | |
Game.putCell(0, 1); | |
Game.putCell(1, 0); | |
Game.putCell(1, 1); | |
Game.nextStep(); | |
}); | |
it ('should live', function () { | |
expect(Game.getCell(0, 0).state).toEqual(CellState.Live); | |
}); | |
}); | |
}); | |
}); |
This file contains 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
describe('when game step is happen 2x2 grid', function () { | |
beforeEach(function () { | |
Game.init({ height: 2, width: 2}); | |
}); | |
describe('live cell with fewer than two live neighbours', function () { | |
beforeEach(function () { | |
Game.putCell(0, 0); | |
Game.nextStep(); | |
}); | |
it ('should cell die', function () { | |
expect(Game.getCell(0, 0).state).toEqual(CellState.Dead); | |
}); | |
}); | |
describe('live cell with fewer than two live neighbours', function () { | |
beforeEach(function () { | |
Game.putCell(0, 0); | |
Game.putCell(0, 1); | |
Game.nextStep(); | |
}); | |
it ('should cell die', function () { | |
expect(Game.getCell(0, 0).state).toEqual(CellState.Dead); | |
}); | |
}); | |
describe('live cell with two or three live neighbours lives on to the next generation', function () { | |
beforeEach(function () { | |
Game.putCell(0, 0); | |
Game.putCell(0, 1); | |
Game.putCell(1, 0); | |
Game.nextStep(); | |
}); | |
it ('should cell live', function () { | |
expect(Game.getCell(0, 0).state).toEqual(CellState.Live); | |
}); | |
it ('rest cells should be dead', function () { | |
expect(Game.getCell(0, 1).state).toEqual(CellState.Dead); | |
expect(Game.getCell(1, 0).state).toEqual(CellState.Dead); | |
}); | |
}); | |
describe('live cell with more than three live neighbours dies, as if by overcrowding', function () { | |
beforeEach(function () { | |
Game.putCell(0, 0); | |
Game.putCell(0, 1); | |
Game.putCell(1, 0); | |
Game.putCell(1, 1); | |
Game.nextStep(); | |
}); | |
it ('should die', function () { | |
expect(Game.getCell(0, 0).state).toEqual(CellState.Dead); | |
}); | |
}); | |
describe('dead cell with exactly three live neighbours becomes a live cell, as if by reproduction', function () { | |
beforeEach(function () { | |
Game.putCell(0, 0, CellState.Dead); | |
Game.putCell(0, 1); | |
Game.putCell(1, 0); | |
Game.putCell(1, 1); | |
Game.nextStep(); | |
}); | |
it ('should live', function () { | |
expect(Game.getCell(0, 0).state).toEqual(CellState.Live); | |
}); | |
}); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment