Game of Life
Level: Advanced 60–90 minConcepts: StateAlgorithms
Solutions: C# | TypeScript | Python
Implement Conway’s Game of Life, a cellular automaton that simulates the evolution of a population of cells based on simple rules. The game is played on a grid of cells, where each cell can be either alive or dead.
Rules
The rules of the game are:
- Any live cell with fewer than two live neighbors dies (underpopulation)
- Any live cell with two or three live neighbors lives on to the next generation
- Any live cell with more than three live neighbors dies (overpopulation)
- Any dead cell with exactly three live neighbors becomes a live cell (reproduction)
Requirements
- Create a grid of cells that can be initialized with a specific pattern
- Implement the rules to calculate the next generation
- Handle edge cases (cells at the boundaries of the grid)
- Support different grid sizes
- Provide a way to visualize the current state of the grid
Hint
Start by implementing the core rules for a single cell, then expand to handle the entire grid. Consider using a two-dimensional array or a more sophisticated data structure to represent the grid. Think about how to handle the edges of the grid - you could either wrap around (toroidal) or consider cells outside the grid as dead.
Bonus
- Implement different initial patterns (glider, blinker, etc.)
- Add the ability to save and load patterns
- Implement a graphical interface to visualize the evolution
- Add the ability to pause and resume the simulation
- Implement different rule variations (e.g., High Life, Day & Night)
Reference Walkthrough
Full C#, TypeScript, and Python implementations live at tddbuddy-reference-katas/game-of-life. Eighteen scenarios across empty/trivial grids, individual rule verification, still lifes (Block), oscillators (Blinker), spaceships (Glider), and grid queries — shared across all three languages — with an immutable Grid entity backed by a set of Cell value-type coordinates, and a GridBuilder for readable test setup.
- C# (.NET 8, xUnit, FluentAssertions) — walkthrough
- TypeScript (Node 20, Vitest, strict types) — walkthrough
- Python (3.11, pytest, frozen dataclass, frozenset) — walkthrough
This kata ships in Agent Full-Bake (F3) mode: one commit per language with the full domain design landing together. The walkthroughs read as design rationale — why the grid is a Set<Cell> instead of a 2D array (unbounded infinite plane, no boundary questions), why Grid is immutable (simultaneous rule application), why tick() uses a neighbor-count dictionary (work proportional to population, not plane). No collaborators are needed — GoL is pure transformation with no clock, no notifier, no capacity. The reference scopes to the eighteen core scenarios; the bonus items (graphical visualization, rule variations) are deliberately out of scope. See the repo’s Gears section for when middle gear is the right call.
Related reading
- Katas Are Rehearsal, Not Performance
You don't practice TDD on production code. You practice on katas and bring the muscle memory to production. The gap between knowing TDD and doing TDD is reps. - Test Deletion Is a Privileged Operation
The cheapest way for an agent to make a failing test pass is to delete it. That is logical for the agent and catastrophic for the codebase. Tests are append-only by default. Deletion needs a human author, a separate commit, and a separate review. - The Instruction File Is Not the Discipline
Teams that want their agent to do TDD reach for the instruction file. The TDAD paper measured this directly: adding a 'do TDD' instruction raised regressions by nearly two-thirds. Contextual test discovery cut them by seventy percent. The instruction is theatre. The codebase's test surface is the discipline.