A few defectors in a sea of cooperators unfold into an endless symmetric kaleidoscope.
This is the spatial prisoner's dilemma of Nowak and May. Every cell plays one round with itself and its eight neighbors: two cooperators earn 1 each, a defector facing a cooperator earns the temptation b, and everything else earns nothing. Then each cell copies the strategy of the best scorer in its 3x3 block. The rule is deterministic and symmetric, so a symmetric seed of defectors keeps the eightfold symmetry of the square forever, and for b between 1.8 and 2 neither strategy can win: the grid churns through fractal patterns with cooperators hovering near a third of the population. Blue cells cooperate, red ones defect, gold ones just defected and green ones just went back to cooperating, and the toroidal world is tiled like wallpaper around the original. Each new seed unfolds at double speed until its pattern wraps around the torus, and left alone the demo cycles through different seeds and temptations.
Try it. Drag the temptation slider across the phase boundaries. Drag on the grid to paint defectors, mirrored eight ways so the symmetry survives; Shift-drag or right-drag paints cooperators. Click the view, then use the left and right arrows to nudge b, Space to pause, S to single-step while paused, plus and minus for speed, R to reseed, N for the next scene and M to turn mirroring off.
Paste this into Claude Code, Codex or any coding agent to get a simple version running, then take it wherever you like.
Build the spatial prisoner's dilemma of Nowak and May with JavaScript and the HTML canvas element. Put everything in a single index.html file with no libraries or build step, so I can open it directly in a browser.
Start simple:
- Make a square grid of about 151 by 151 cells (an odd size, so there is a true center cell). Each cell is a player that either cooperates (0) or defects (1). Wrap the edges so the grid is a torus.
- Fill the grid with cooperators and put a single defector in the exact center.
- Each generation, every cell plays one round with itself and its eight neighbors. A cooperator earns 1 for each cooperator in its 3x3 block (itself included). A defector earns b for each cooperator in its block. Start with b = 1.85.
- Then, all at once, every cell adopts the strategy of the highest scorer in its 3x3 block. On a tie, keep the current strategy, so the pattern stays perfectly symmetric.
- Color each cell by its previous and current strategy: blue for cooperator to cooperator, red for defector to defector, yellow for a cell that just became a defector and green for one that just became a cooperator.
- Draw one pixel per cell into ImageData on a small offscreen canvas, then drawImage it scaled up with imageSmoothingEnabled = false. Step about 10 generations per second.
Once that works, make it beautiful:
- Darken cells that have not changed for a while, so the churning fronts glow against calmer regions.
- Add a soft bloom by drawing a quarter size copy of the grid on top with "lighter" blending.
- Add a slider for b from 1 to 2.4 and mark the interesting thresholds, especially 1.8 and 2, and plot the share of cooperators over time.
Explain the key ideas in short code comments. When you're done, tell me how to open it and suggest three directions I could take it next, such as painting defectors with the mouse mirrored eight ways, adding random noise to the update, or switching to asynchronous updates and comparing the patterns.