Created
August 5, 2021 18:51
-
-
Save devill/3d6cd56871b3f7890c91855172021f57 to your computer and use it in GitHub Desktop.
Final code for https://youtu.be/ncyzY-5MyB8
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
| import expect from 'expect.js' | |
| class GameOfLifeBoard { | |
| alvie = {}; | |
| isAlive(cell) { | |
| return !!this.alvie[cell]; | |
| } | |
| spawn(cell) { | |
| this.alvie[cell] = cell | |
| return this; | |
| } | |
| list() { | |
| return Object.values(this.alvie); | |
| } | |
| } | |
| class GameOfLife { | |
| board = new GameOfLifeBoard(); | |
| isAlive(cell) { | |
| return this.board.isAlive(cell); | |
| } | |
| spawn(cell) { | |
| this.board.spawn(cell) | |
| } | |
| evolve() { | |
| this.board = this.board | |
| .list() | |
| .flatMap((cell) => cell.neighbours()) | |
| .filter(cell => this.shouldBeAlive(cell)) | |
| .reduce((next, cell) => next.spawn(cell), new GameOfLifeBoard()); | |
| } | |
| shouldBeAlive(cell) { | |
| let count = this.countNeighbours(cell); | |
| return (count === 2 && this.isAlive(cell)) || count === 3; | |
| } | |
| countNeighbours(cell) { | |
| return cell.neighbours() | |
| .filter(cell => this.isAlive(cell)) | |
| .length | |
| } | |
| } | |
| class Cell { | |
| constructor(x, y) { | |
| this.x = x; | |
| this.y = y; | |
| } | |
| toString() { | |
| return `(${this.x},${this.y})` | |
| } | |
| neighbours() { | |
| return [ | |
| { x: -1, y: -1}, | |
| { x: -1, y: 0}, | |
| { x: -1, y: 1}, | |
| { x: 0, y: -1}, | |
| { x: 0, y: 1}, | |
| { x: 1, y: -1}, | |
| { x: 1, y: 0}, | |
| { x: 1, y: 1}, | |
| ] | |
| .map(delta => new Cell(this.x + delta.x, this.y + delta.y)) | |
| } | |
| } | |
| describe("GameOfLife", () => { | |
| let game = null; | |
| const cell = (x, y) => new Cell(x, y); | |
| const expectDead = (cell) => expect(game.isAlive(cell)).to.be(false); | |
| const expectAlive = (cell) => expect(game.isAlive(cell)).to.be(true); | |
| beforeEach(() => { | |
| game = new GameOfLife(); | |
| }); | |
| specify("that an empty world has dead (0,0) cell", () => { | |
| expectDead(cell(0,0)); | |
| }); | |
| specify("that a (0,0) cell can be spawned", () => { | |
| game.spawn(cell(0,0)); | |
| expectAlive(cell(0,0)); | |
| }); | |
| specify("that a (3,5) cell can be spawned independently of (0,0) cell", () => { | |
| game.spawn(cell(3, 5)); | |
| expectDead(cell(0,0)); | |
| }); | |
| specify("that empty world has dead (0,0) cell after being evolved", () => { | |
| game.evolve(); | |
| expectDead(cell(0,0)); | |
| }); | |
| specify("that lonely (0,0) cell dies when evolved", () => { | |
| game.spawn(cell(0,0)); | |
| game.evolve(); | |
| expectDead(cell(0,0)); | |
| }); | |
| specify("that (0,0) cell with single neighbour (-1, -1) dies", () => { | |
| game.spawn(cell( 0, 0)); | |
| game.spawn(cell(-1,-1)); | |
| game.evolve(); | |
| expectDead(cell(0,0)); | |
| }); | |
| [ | |
| cell(-1, 0), | |
| cell(-1, 1), | |
| cell( 0,-1), | |
| cell( 0, 1), | |
| cell( 1,-1), | |
| cell( 1, 0), | |
| cell( 1, 1) | |
| ].forEach(neighbourCell => { | |
| specify(`that (0,0) cell with two neighbours (-1, -1) and ${neighbourCell} stays alive`, () => { | |
| game.spawn(cell( 0, 0)); | |
| game.spawn(cell(-1,-1)); | |
| game.spawn(neighbourCell); | |
| game.evolve(); | |
| expectAlive(cell(0,0)); | |
| }); | |
| }); | |
| specify("that (0,0) cell with three neighbours (-1, -1), (-1, 0) and (-1,1) stays alive", () => { | |
| game.spawn(cell( 0, 0)); | |
| game.spawn(cell(-1,-1)); | |
| game.spawn(cell(-1, 0)); | |
| game.spawn(cell(-1, 1)); | |
| game.evolve(); | |
| expectAlive(cell(0,0)); | |
| }); | |
| specify("that dead (0,0) cell with three neighbours (-1, -1), (-1, 0) and (-1,1) spawn", () => { | |
| game.spawn(cell(-1,-1)); | |
| game.spawn(cell(-1, 0)); | |
| game.spawn(cell(-1, 1)); | |
| game.evolve(); | |
| expectAlive(cell(0,0)); | |
| }); | |
| specify("that dead (0,0) cell with two neighbours (0, -1) and (1,1) stays dead", () => { | |
| game.spawn(cell( 0,-1)); | |
| game.spawn(cell( 1, 1)); | |
| game.evolve(); | |
| expectDead(cell(0,0)); | |
| }); | |
| specify("that (3,5) cell with two neighbours stays alive", () => { | |
| game.spawn(cell(3,5)); | |
| game.spawn(cell(3,4)); | |
| game.spawn(cell(4,6)); | |
| game.evolve(); | |
| expectAlive(cell(3,5)); | |
| }); | |
| specify("that (-2,8) cell with two neighbours stays alive", () => { | |
| game.spawn(cell(-2,8)); | |
| game.spawn(cell(-1,7)); | |
| game.spawn(cell(-3,9)); | |
| game.evolve(); | |
| expectAlive(cell(-2,8)); | |
| }); | |
| }); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment