Overview
Conway's Game of Life, 1970. Every cell on a grid is alive or dead, every generation each cell counts its eight neighbors, and a rule table decides who exists next tick. Zero players: you set the board, the rules do the rest. The rules fit on an index card; the consequences are Turing-complete.
Like the boids demo, it's plain JavaScript on one canvas.
Demo
[ click to toggle, drag to paint. the edges wrap. the phosphor is slow. ]
Things to try: the r-pentomino boils for a thousand-odd generations from five cells. The glider gun, on a wrapping grid, eventually shoots itself in the back. A long straight line collapses into blinkers. Painting into a running soup is encouraged.
The Rules
Each cell counts its eight neighbors:
- Loneliness — a live cell with fewer than two neighbors dies.
- Contentment — a live cell with two or three neighbors carries on.
- Overcrowding — a live cell with four or more neighbors dies.
- Birth — a dead cell with exactly three neighbors switches on.
That's B3/S23 — born on 3, survives on 2 or 3. Minus the drawing, the demo above is:
// two grids — count neighbors on one, write the verdict to the other
function step() {
for (let y = 0; y < rows; y++) {
const up = ((y + rows - 1) % rows) * cols; // % = the edges wrap
const mid = y * cols;
const dn = ((y + 1) % rows) * cols;
for (let x = 0; x < cols; x++) {
const xl = (x + cols - 1) % cols, xr = (x + 1) % cols;
const n = cur[up + xl] + cur[up + x] + cur[up + xr]
+ cur[mid + xl] + cur[mid + xr]
+ cur[dn + xl] + cur[dn + x] + cur[dn + xr];
// the entire game is this line:
nxt[mid + x] = (n === 3 || (n === 2 && cur[mid + x])) ? 1 : 0;
}
}
[cur, nxt] = [nxt, cur]; // swap buffers — never update in place
}
The one real trap is the last line: you need two grids. Update in place and half the neighbors you count are from the next generation — the symptom is gliders that smear apart.
Field Guide
Every soup settles into the same zoo:
- Still lifes — block, beehive, loaf: every cell at two or three neighbors, forever. Most soup ends here.
- Oscillators — the blinker (period 2) is most of the rest; the pulsar in the menu is period 3.
- Spaceships — the glider re-forms one diagonal cell over every four generations. Hacker heraldry.
- Methuselahs — the r-pentomino (5 cells) boils for ~1,100 generations; the acorn (7 cells) over 5,200. The first observed gliders escaped an r-pentomino.
- Guns — Gosper's glider gun won Conway's $50 prize for unbounded growth: period 30, one glider per cycle, forever.
Implementation Notes
If you build one:
- Two buffers, swap. Never update in place.
- One flat
Uint8Array, row-major. NoCellobjects; the step loop never allocates. - Hoist the wrap. Compute the wrapped row offsets once per row; or pad the grid with a copied border and skip modulo entirely.
- The phosphor is one extra buffer. Death writes 1.0, each generation multiplies by 0.72, drawn in four bucketed alphas so
fillStylechanges four times, not four thousand. - Only the ternary is Life. HighLife (B36/S23) has a replicator, Seeds (B2/S) detonates, Day & Night (B3678/S34678) is dead/alive symmetric — same loop, different line. The rabbit hole is Gosper's Hashlife.