const pr = t => process.stdout.write(t) class GameOfLife { constructor(){ this.width = process.stdout.columns - 2 this.height = process.stdout.rows - 4 this.cells = Array.from({length: this.width * this.height}, () => Math.round(Math.random())) } printBoard() { console.clear() pr('╔' + '═'.repeat(this.width) + '╗') pr('║' + ' '.repeat(Math.floor((this.width - 12) / 2)) + 'GAME OF LIFE' + ' '.repeat(Math.ceil((this.width - 12) / 2)) + '║') pr('╠' + '═'.repeat(this.width) + '╣') for (let l=0; l ( c === 1 ? this.prevCells && this.prevCells[l*this.width+i] === 1 ? '#' : '\x1b[32m#\x1b[0m' : this.prevCells && this.prevCells[l*this.width+i] === 1 ? '\x1b[31m#\x1b[0m' : ' ' )).join('') + '║') } pr('╚' + '═'.repeat(this.width) + '╝') } findCell(x, y) { return this.cells[x + y * this.width] } computeCellNextState(x, y){ const st = (x, y) => { if (x >= 0 && x < this.width && y >= 0 && y < this.height) { return this.findCell(x, y) } else { return 0; } } const total = st(x-1, y-1) + st(x, y-1) + st(x+1, y-1) + st(x-1, y) + st(x+1, y) + st(x-1, y+1) + st(x, y+1) + st(x+1, y+1) if (st(x, y) === 1) { if (total < 2) { return 0 } else if (total >= 2 && total <= 3) { return 1 } else { return 0 } } else if (total === 3) { return 1 } else { return 0 } } printNextGeneration(){ const nextState = [] for (let y = 0; y < this.height; y++) { for (let x = 0; x < this.width; x++) { nextState.push(this.computeCellNextState(x, y)) } } this.prevCells = this.cells this.cells = nextState this.printBoard() } } let game = new GameOfLife() pr('\u001B[?25l') let animation = setInterval(() => game.printNextGeneration(), 250) process.on('SIGINT', function() { clearInterval(animation) pr('\u001B[?25h') console.clear() process.exit() }); process.stdout.on('resize', () => { clearInterval(animation) game = new GameOfLife() animation = setInterval(() => game.printNextGeneration(), 250) })