``````<h1>Conway's game of life on a canvas</h1>
<canvas id="canvas" width="800" height="800"></canvas>

<div class="container">
<button id="start">Start</button>
<button id="stop">Stop</button>
<button id="step">Step</button>
</div>

<div class="container">
<button id="reset">Reset to empty</button>
<button id="glider">Set single glider</button>
<button id="random">Random (35% alive)</button>
</div>``````
``````canvas {
box-sizing: border-box;
border: 1px solid #000;
width: 800px;
height: 800px;
}

.container {
box-sizing: border-box;
width: 800px;
border: 1px solid #000;
margin-top: 10px;
}``````
``````const field = []
for (let y = 0; y < 100; y++) {
field[y] = []
for (let x = 0; x < 100; x++) {
field[y][x] = false
}
}

const scaleFactor = 8

const getNeighbors = (x, y, field) => {
let prevX = x - 1
if (prevX < 0) {
prevX = field[0].length - 1
}

let nextX = x + 1
if (nextX === field[0].length) {
nextX = 0
}

let prevY = y - 1
if (prevY < 0) {
prevY = field.length - 1
}

let nextY = y + 1
if (nextY === field.length) {
nextY = 0
}

return [
field[prevY][prevX],
field[prevY][x],
field[prevY][nextX],
field[y][prevX],
// field[y][x], That's the cell itself - we don't need this.
field[y][nextX],
field[nextY][prevX],
field[nextY][x],
field[nextY][nextX],
]
}

const getDeadOrAlive = (x, y, field) => {
const neighbors = getNeighbors(x, y, field)
const numberOfAliveNeighbors = neighbors.filter(Boolean).length

// Cell is alive
if (field[y][x]) {
if (numberOfAliveNeighbors < 2 || numberOfAliveNeighbors > 3) {
// Cell dies
return false
}

// Cell stays alive
return true
}

if (numberOfAliveNeighbors === 3) {
// Cell becomes alive
return true
}

return false
}

const drawField = field => {
const canvas = document.querySelector('#canvas')
const context = canvas.getContext('2d')

context.fillStyle = '#fff'
context.fillRect(0, 0, 100 * scaleFactor, 100 * scaleFactor);

context.fillStyle = '#008000'

field.forEach((row, y) => row.forEach((cell, x) => {
if (cell) {
context.fillRect(x * scaleFactor, y * scaleFactor, scaleFactor, scaleFactor)
}
}))
}

let nextField = field

drawField(field)

const step = () => {
nextField = nextField.map((row, y) => row.map((_, x) => {
}))

drawField(nextField)
}

let interval = null

nextField = field
})

interval = setInterval(step, 80)
})

clearInterval(interval)
})

for (let y = 0; y < 100; y++) {
for (let x = 0; x < 100; x++) {
field[y][x] = false
}
}

nextField = field

drawField(field)
})

for (let y = 0; y < 100; y++) {
for (let x = 0; x < 100; x++) {
field[y][x] = false
}
}

field[20][20] = true
field[20][21] = true
field[20][22] = true
field[19][22] = true
field[18][21] = true

nextField = field

drawField(field)
})

for (let y = 0; y < 100; y++) {
for (let x = 0; x < 100; x++) {
field[y][x] = Math.random() * 100 > 65
}
}

nextField = field

drawField(field)
})

const x = Math.floor(event.offsetX / scaleFactor)
const y = Math.floor(event.offsetY / scaleFactor)

field[y][x] = !field[y][x]

nextField = field

drawField(field)
})
``````

### External CSS

This Pen doesn't use any external CSS resources.

### External JavaScript

This Pen doesn't use any external JavaScript resources.