Game of Life

Conway's Game of Life producing grid frames.

Level:Beginner

cellular-automatagrid

  • Probes:alive
FAQ
Why use wrapping indexes in count_neighbors?
Neighbor positions are computed with modulo so the grid edges wrap around like a torus.
How is the next generation computed?
Each step counts living neighbours and applies the standard rules to produce a new grid.
What does the frame function record?
It snapshots the entire grid each step so the evolution can be replayed.
simulation.py

Conway's Game of Life

This simulation generates successive frames of Conway's Game of Life on a rectangular grid. Each cell is either alive or dead and evolves according to the standard rules of the game.


from tys import progress, frame, probe
import random

Run the Game of Life simulation.

def simulate(cfg: dict):

    rows = cfg["rows"]
    cols = cfg["cols"]
    steps = cfg["steps"]
    chance = cfg.get("initial_chance", 0.2)

    grid = [[1 if random.random() < chance else 0 for _ in range(cols)] for _ in range(rows)]
    probe("alive", 0, sum(sum(row) for row in grid))

    def count_neighbors(r: int, c: int) -> int:
        total = 0
        for dr in (-1, 0, 1):
            for dc in (-1, 0, 1):
                if dr == 0 and dc == 0:
                    continue
                rr = (r + dr) % rows
                cc = (c + dc) % cols
                total += grid[rr][cc]
        return total

    for step in range(steps):
        frame(step, grid)
        new_grid = [[0] * cols for _ in range(rows)]
        for r in range(rows):
            for c in range(cols):
                n = count_neighbors(r, c)
                if grid[r][c]:
                    new_grid[r][c] = 1 if n in (2, 3) else 0
                else:
                    new_grid[r][c] = 1 if n == 3 else 0
        grid = new_grid
        alive = sum(sum(row) for row in grid)
        probe("alive", step + 1, alive)
        progress(int(100 * (step + 1) / steps))

    frame(steps, grid)
    alive = sum(sum(row) for row in grid)
    return {"alive": alive}


def requirements():
    return {
        "builtin": ["micropip", "pyyaml"],
        "external": []
    }
Default.yaml
rows: 80
cols: 80
steps: 60
initial_chance: 0.3
Charts (Default)

alive

alive chartCSV
Samples61 @ 0.00–60.00
Valuesmin 705.00, mean 1144.93, median 1085.00, max 2292.00, σ 350.10
Final Frame (Default)
final frame
Final Results (Default)
MetricValue
alive705.00