Game of Life

Conway's Game of Life producing grid frames.

Level: Beginner

cellular-automatagrid

  • Probes: alive
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 {
        "external": []
    }
Default.yaml
rows: 80
cols: 80
steps: 60
initial_chance: 0.3
Charts (Default)

alive

Samples61 @ 0.00–60.00
Valuesmin 852.00, mean 1197.07, median 1106.00, max 2186.00, σ 310.14
Final Frame (Default)
final frame
Final Results (Default)
MetricValue
alive876.00
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.