{
  "id": "P036",
  "slug": "game-of-life",
  "key": "P036-game-of-life",
  "title": "Game of Life",
  "summary": "Conway's Game of Life on a 12 x 20 board: edit cells or pick a ready-made pattern, then run a generation at a time or many at once. Every board is remembered with the generation it first appeared in, so the program says when the board has died, stopped changing, or started to repeat - and with what period.",
  "entry": "main.eml",
  "ui": "terminal",
  "readme": "# P036 - Game of Life\n\nConway's Game of Life on a board of 12 rows and 20 columns. Cells can be\nturned on and off one at a time, or a ready-made pattern placed; then the\nboard runs a generation at a time or many at once. Every board is remembered\nwith the generation it first appeared in, so the program says when everything\nhas died, when nothing changes any more, or when the board starts to repeat -\nand with what period.\n\n- `main.eml` - the menu, the board on screen, editing, stepping and running,\n  and the remembered boards\n- `life.eml` - the board and the rule: one generation, the live count, a\n  board as one string, flipping a cell, placing a shape\n- `patterns.eml` - six ready-made patterns and where they go\n\nHow each part works:\n\n- Every cell outside the board counts as dead, so the board has a hard edge.\n  A generation is worked out into a new grid, as in the corpus case\n  `conway-game-of-life`: each cell must read the previous generation, and\n  writing into the grid being read would let the cells already updated change\n  the neighbour counts of the rest.\n- Each board is turned into one string and kept in a dictionary with the\n  generation it first appeared in. A step that makes a board already in it\n  has found a cycle: one generation after its first appearance means a still\n  life, more than one means the board repeats with that period. A board with\n  no live cell is reported as dead at once. There are only finitely many\n  boards of this size, so every run ends in one of these ways sooner or\n  later, and a run of many generations stops there.\n- The patterns show the endings: the blinker, the toad and the beacon repeat\n  every 2 generations and the pentadecathlon every 15; the glider travels\n  down to the bottom edge and turns into a still block at generation 35; the\n  R-pentomino, five cells, changes for 76 generations before it settles into\n  a block.\n- Editing the board or placing a pattern starts again at generation 0 and\n  forgets the remembered boards.\n\nWhat is checked: a row from 1 to 12 and a column from 1 to 20, typed as `3 5`\nor `3,5`; 1 to 500 generations for a run; a pattern number from the list. An\nempty answer cancels, or ends the editing.\n\nSessions: `sessions/basic.in` places the glider, steps twice and runs on\nuntil it settles into a block (generation 36, still life since 35); places\nthe pentadecathlon and runs until generation 15 turns out to be generation 0\nagain; clears the board, draws a blinker by hand and steps twice to see it\ncome back (period 2). `sessions/bad-input.in` gives menu choices 0 and x, a\nstep on the empty board (everything has died), runs of 0, 501 and abc\ngenerations, cells 13 1, 1 21, x, 3 and 1 2 3, a cell turned on and off\nagain, a lone cell that dies at the next step, an L of three cells that\nbecomes a block, a domino that dies during a run, pattern numbers 0, 7 and x,\nand then runs the R-pentomino until it settles (generation 77, still life\nsince 76).\n\nBuilt on the verified corpus case `conway-game-of-life` (one generation of\nLife into a fresh grid, with a glider as the self-checking pattern).\n",
  "modules": [
    {
      "name": "main.eml",
      "eml": "# P036 Game of Life: a 12 x 20 board to edit cell by cell or fill with a\n# ready-made pattern, then run a generation at a time or many at once. Every\n# board is remembered with the generation it first appeared in, so the\n# program notices when the board stops changing, starts repeating, or dies.\nimport life\nimport patterns\n\n500 => most_generations\n\ndef trim(s):\n    0 => i\n    len(s) => j\n    while i < j and s[i] == \" \":\n        i + 1 => i\n    while j > i and s[j - 1] == \" \":\n        j - 1 => j\n    return s[i:j]\n\ndef whole_number(s):\n    # The value of 1 to 3 digits, otherwise -1.\n    if s == \"\" or len(s) > 3:\n        return -1\n    0 => n\n    for c in s:\n        if not (c in \"0123456789\"):\n            return -1\n        n * 10 + int(c) => n\n    return n\n\ndef two_numbers(s):\n    # \"3 5\" or \"3,5\" as [3, 5]; [] if it is not two whole numbers.\n    [] => parts\n    \"\" => word\n    for c in s + \" \":\n        if c == \" \" or c == \",\":\n            if word != \"\":\n                parts + [word] => parts\n            \"\" => word\n        else:\n            word + c => word\n    if len(parts) != 2:\n        return []\n    whole_number(parts[0]) => a\n    whole_number(parts[1]) => b\n    if a < 0 or b < 0:\n        return []\n    return [a, b]\n\ndef show(grid, generation, change):\n    # change is [born, died] after a step, or [] for a board just set up.\n    (\"Generation \" + str(generation) + \": \" + str(life.alive(grid)) + \" alive\") => line\n    if len(change) > 0:\n        line + \" (\" + str(change[0]) + \" born, \" + str(change[1]) + \" died)\" => line\n    line ^0\n    \"    \" => header\n    for c in [1:life.cols]:\n        header + str(c % 10) => header\n    header ^0\n    for r in [0:life.rows - 1]:\n        str(r + 1) => label\n        while len(label) < 3:\n            \" \" + label => label\n        label + \" \" => line\n        for cell in grid[r]:\n            if cell == 1:\n                line + \"#\" => line\n            else:\n                line + \".\" => line\n        line ^0\n\ndef generations(n):\n    if n == 1:\n        return \"1 generation\"\n    return str(n) + \" generations\"\n\ndef verdict(grid, generation, first):\n    # What it means that the board has died, or already appeared in\n    # generation first.\n    if life.alive(grid) == 0:\n        return \"Everything has died.\"\n    if generation - first == 1:\n        return \"Still life: nothing has changed since generation \" + str(first) + \".\"\n    return \"It repeats: generation \" + str(generation) + \" is generation \" + str(first) + \" again, a period of \" + str(generation - first) + \".\"\n\ndef fresh(grid):\n    # A new start from this board: generation 0, and only it remembered.\n    {} => seen\n    0 => seen[life.key(grid)]\n    return [grid, 0, seen]\n\ndef advance(state):\n    # One generation. Returns [state, change, first], where first is the\n    # generation this board first appeared in, or -1 if it is new.\n    life.step(state[0]) => s\n    s[0] => grid\n    state[1] + 1 => generation\n    state[2] => seen\n    life.key(grid) => k\n    -1 => first\n    if k in seen:\n        seen[k] => first\n    else:\n        generation => seen[k]\n    return [[grid, generation, seen], [s[1], s[2]], first]\n\ndef run(state):\n    while True:\n        trim(input(\"generations (1 to \" + str(most_generations) + \")> \")) => answer\n        if answer == \"\":\n            \"Cancelled.\" ^0\n            return state\n        whole_number(answer) => n\n        if n >= 1 and n <= most_generations:\n            0 => done\n            -1 => first\n            [] => change\n            while done < n and first == -1 and (done == 0 or life.alive(state[0]) > 0):\n                advance(state) => a\n                a[0] => state\n                a[1] => change\n                a[2] => first\n                done + 1 => done\n            if life.alive(state[0]) == 0:\n                (\"Stopped after \" + generations(done) + \": no cell is left.\") ^0\n            elif first == -1:\n                (\"Ran \" + generations(done) + \".\") ^0\n            else:\n                (\"Stopped after \" + generations(done) + \": this board was seen before.\") ^0\n            show(state[0], state[1], change)\n            if first != -1 or life.alive(state[0]) == 0:\n                verdict(state[0], state[1], first) ^0\n            return state\n        (\"Type a number from 1 to \" + str(most_generations) + \".\") ^0\n\ndef toggle(state):\n    state[0] => grid\n    0 => changed\n    True => editing\n    while editing:\n        trim(input(\"cell (row column, empty to finish)> \")) => answer\n        if answer == \"\":\n            False => editing\n        else:\n            two_numbers(answer) => rc\n            if len(rc) == 0 or rc[0] < 1 or rc[0] > life.rows or rc[1] < 1 or rc[1] > life.cols:\n                (\"Type a row from 1 to \" + str(life.rows) + \" and a column from 1 to \" + str(life.cols) + \", like 3 5.\") ^0\n            else:\n                life.toggled(grid, rc[0] - 1, rc[1] - 1) => grid\n                changed + 1 => changed\n                \"dead\" => now\n                if grid[rc[0] - 1][rc[1] - 1] == 1:\n                    \"alive\" => now\n                (\"Row \" + str(rc[0]) + \", column \" + str(rc[1]) + \" is now \" + now + \".\") ^0\n    if changed == 0:\n        return state\n    fresh(grid) => state\n    show(state[0], 0, [])\n    return state\n\ndef choose_pattern(state):\n    for i in [0:len(patterns.patterns) - 1]:\n        (\"  \" + str(i + 1) + \") \" + patterns.patterns[i][0]) ^0\n    while True:\n        trim(input(\"pattern> \")) => answer\n        if answer == \"\":\n            \"Cancelled.\" ^0\n            return state\n        whole_number(answer) => n\n        if n >= 1 and n <= len(patterns.patterns):\n            patterns.patterns[n - 1] => p\n            fresh(life.placed(p[1], p[2], p[3])) => state\n            (\"Placed: \" + p[0] + \".\") ^0\n            show(state[0], 0, [])\n            return state\n        (\"Type a number from 1 to \" + str(len(patterns.patterns)) + \".\") ^0\n\n\"== Game of Life ==\" ^0\n\"A 12 x 20 board; cells outside it count as dead. A live cell stays alive\" ^0\n\"with 2 or 3 live neighbours, and a dead cell comes alive with exactly 3.\" ^0\nfresh(life.empty()) => state\nTrue => running\nwhile running:\n    \"\" ^0\n    \"1) step  2) run  3) toggle cells  4) pattern  5) clear  6) show  7) quit\" ^0\n    trim(input(\"choice> \")) => choice\n    if choice == \"1\":\n        advance(state) => a\n        a[0] => state\n        show(state[0], state[1], a[1])\n        if a[2] != -1 or life.alive(state[0]) == 0:\n            verdict(state[0], state[1], a[2]) ^0\n    elif choice == \"2\":\n        run(state) => state\n    elif choice == \"3\":\n        toggle(state) => state\n    elif choice == \"4\":\n        choose_pattern(state) => state\n    elif choice == \"5\":\n        fresh(life.empty()) => state\n        \"The board is empty.\" ^0\n    elif choice == \"6\":\n        show(state[0], state[1], [])\n    elif choice == \"7\":\n        False => running\n    else:\n        \"Pick a number from 1 to 7.\" ^0\n\"Bye.\" ^0\n",
      "python": "import life\nimport patterns\nmost_generations = 500\n\ndef trim(s):\n    i = 0\n    j = len(s)\n    while i < j and s[i] == \" \":\n        i = i + 1\n    while j > i and s[j - 1] == \" \":\n        j = j - 1\n    return s[i:j]\n\ndef whole_number(s):\n    if s == \"\" or len(s) > 3:\n        return -1\n    n = 0\n    for c in s:\n        if not c in \"0123456789\":\n            return -1\n        n = n * 10 + int(c)\n    return n\n\ndef two_numbers(s):\n    parts = []\n    word = \"\"\n    for c in s + \" \":\n        if c == \" \" or c == \",\":\n            if word != \"\":\n                parts = parts + [word]\n            word = \"\"\n        else:\n            word = word + c\n    if len(parts) != 2:\n        return []\n    a = whole_number(parts[0])\n    b = whole_number(parts[1])\n    if a < 0 or b < 0:\n        return []\n    return [a, b]\n\ndef show(grid, generation, change):\n    line = \"Generation \" + str(generation) + \": \" + str(life.alive(grid)) + \" alive\"\n    if len(change) > 0:\n        line = line + \" (\" + str(change[0]) + \" born, \" + str(change[1]) + \" died)\"\n    print(line)\n    header = \"    \"\n    for c in range(1, life.cols+1):\n        header = header + str(c % 10)\n    print(header)\n    for r in range(0, life.rows):\n        label = str(r + 1)\n        while len(label) < 3:\n            label = \" \" + label\n        line = label + \" \"\n        for cell in grid[r]:\n            if cell == 1:\n                line = line + \"#\"\n            else:\n                line = line + \".\"\n        print(line)\n\ndef generations(n):\n    if n == 1:\n        return \"1 generation\"\n    return str(n) + \" generations\"\n\ndef verdict(grid, generation, first):\n    if life.alive(grid) == 0:\n        return \"Everything has died.\"\n    if generation - first == 1:\n        return \"Still life: nothing has changed since generation \" + str(first) + \".\"\n    return \"It repeats: generation \" + str(generation) + \" is generation \" + str(first) + \" again, a period of \" + str(generation - first) + \".\"\n\ndef fresh(grid):\n    seen = {}\n    seen[life.key(grid)] = 0\n    return [grid, 0, seen]\n\ndef advance(state):\n    s = life.step(state[0])\n    grid = s[0]\n    generation = state[1] + 1\n    seen = state[2]\n    k = life.key(grid)\n    first = -1\n    if k in seen:\n        first = seen[k]\n    else:\n        seen[k] = generation\n    return [[grid, generation, seen], [s[1], s[2]], first]\n\ndef run(state):\n    while True:\n        answer = trim(input(\"generations (1 to \" + str(most_generations) + \")> \"))\n        if answer == \"\":\n            print(\"Cancelled.\")\n            return state\n        n = whole_number(answer)\n        if n >= 1 and n <= most_generations:\n            done = 0\n            first = -1\n            change = []\n            while done < n and first == -1 and (done == 0 or life.alive(state[0]) > 0):\n                a = advance(state)\n                state = a[0]\n                change = a[1]\n                first = a[2]\n                done = done + 1\n            if life.alive(state[0]) == 0:\n                print(\"Stopped after \" + generations(done) + \": no cell is left.\")\n            elif first == -1:\n                print(\"Ran \" + generations(done) + \".\")\n            else:\n                print(\"Stopped after \" + generations(done) + \": this board was seen before.\")\n            show(state[0], state[1], change)\n            if first != -1 or life.alive(state[0]) == 0:\n                print(verdict(state[0], state[1], first))\n            return state\n        print(\"Type a number from 1 to \" + str(most_generations) + \".\")\n\ndef toggle(state):\n    grid = state[0]\n    changed = 0\n    editing = True\n    while editing:\n        answer = trim(input(\"cell (row column, empty to finish)> \"))\n        if answer == \"\":\n            editing = False\n        else:\n            rc = two_numbers(answer)\n            if len(rc) == 0 or rc[0] < 1 or rc[0] > life.rows or rc[1] < 1 or rc[1] > life.cols:\n                print(\"Type a row from 1 to \" + str(life.rows) + \" and a column from 1 to \" + str(life.cols) + \", like 3 5.\")\n            else:\n                grid = life.toggled(grid, rc[0] - 1, rc[1] - 1)\n                changed = changed + 1\n                now = \"dead\"\n                if grid[rc[0] - 1][rc[1] - 1] == 1:\n                    now = \"alive\"\n                print(\"Row \" + str(rc[0]) + \", column \" + str(rc[1]) + \" is now \" + now + \".\")\n    if changed == 0:\n        return state\n    state = fresh(grid)\n    show(state[0], 0, [])\n    return state\n\ndef choose_pattern(state):\n    for i in range(0, len(patterns.patterns)):\n        print(\"  \" + str(i + 1) + \") \" + patterns.patterns[i][0])\n    while True:\n        answer = trim(input(\"pattern> \"))\n        if answer == \"\":\n            print(\"Cancelled.\")\n            return state\n        n = whole_number(answer)\n        if n >= 1 and n <= len(patterns.patterns):\n            p = patterns.patterns[n - 1]\n            state = fresh(life.placed(p[1], p[2], p[3]))\n            print(\"Placed: \" + p[0] + \".\")\n            show(state[0], 0, [])\n            return state\n        print(\"Type a number from 1 to \" + str(len(patterns.patterns)) + \".\")\n\nprint(\"== Game of Life ==\")\nprint(\"A 12 x 20 board; cells outside it count as dead. A live cell stays alive\")\nprint(\"with 2 or 3 live neighbours, and a dead cell comes alive with exactly 3.\")\nstate = fresh(life.empty())\nrunning = True\nwhile running:\n    print(\"\")\n    print(\"1) step  2) run  3) toggle cells  4) pattern  5) clear  6) show  7) quit\")\n    choice = trim(input(\"choice> \"))\n    if choice == \"1\":\n        a = advance(state)\n        state = a[0]\n        show(state[0], state[1], a[1])\n        if a[2] != -1 or life.alive(state[0]) == 0:\n            print(verdict(state[0], state[1], a[2]))\n    elif choice == \"2\":\n        state = run(state)\n    elif choice == \"3\":\n        state = toggle(state)\n    elif choice == \"4\":\n        state = choose_pattern(state)\n    elif choice == \"5\":\n        state = fresh(life.empty())\n        print(\"The board is empty.\")\n    elif choice == \"6\":\n        show(state[0], state[1], [])\n    elif choice == \"7\":\n        running = False\n    else:\n        print(\"Pick a number from 1 to 7.\")\nprint(\"Bye.\")\n"
    },
    {
      "name": "life.eml",
      "eml": "# P036 Game of Life - the board and its rule. The board has 12 rows and 20\n# columns, and every cell outside it counts as dead. A grid is a list of rows\n# of 0 (dead) and 1 (alive).\n#\n# A generation is worked out into a brand-new grid, as in the corpus case\n# conway-game-of-life: every cell must read the previous generation, so\n# writing into the grid being read would let early cells change the\n# neighbour counts of later ones.\n\n12 => rows\n20 => cols\n\ndef empty():\n    [] => grid\n    for r in [1:rows]:\n        grid + [[0] * cols] => grid\n    return grid\n\ndef neighbours(grid, r, c):\n    0 => n\n    for dr in [0:2]:\n        for dc in [0:2]:\n            r + dr - 1 => y\n            c + dc - 1 => x\n            if (dr != 1 or dc != 1) and y >= 0 and y < rows and x >= 0 and x < cols:\n                n + grid[y][x] => n\n    return n\n\ndef step(grid):\n    # The next generation: a live cell stays alive with 2 or 3 live\n    # neighbours, a dead cell comes alive with exactly 3. Returns\n    # [next grid, cells born, cells that died].\n    [] => out\n    0 => born\n    0 => died\n    for r in [0:rows - 1]:\n        [] => row\n        for c in [0:cols - 1]:\n            neighbours(grid, r, c) => n\n            0 => cell\n            if grid[r][c] == 1:\n                if n == 2 or n == 3:\n                    1 => cell\n                else:\n                    died + 1 => died\n            elif n == 3:\n                1 => cell\n                born + 1 => born\n            row + [cell] => row\n        out + [row] => out\n    return [out, born, died]\n\ndef alive(grid):\n    0 => n\n    for row in grid:\n        for cell in row:\n            n + cell => n\n    return n\n\ndef key(grid):\n    # The whole board as one string, to recognise a board seen before.\n    \"\" => s\n    for row in grid:\n        for cell in row:\n            if cell == 1:\n                s + \"#\" => s\n            else:\n                s + \".\" => s\n        s + \"/\" => s\n    return s\n\ndef toggled(grid, r, c):\n    # The grid with cell (r, c) flipped; rows and columns count from 0.\n    [] => out\n    for y in [0:rows - 1]:\n        if y == r:\n            grid[y][0:c] + [1 - grid[y][c]] + grid[y][c + 1:cols] => row\n            out + [row] => out\n        else:\n            out + [grid[y]] => out\n    return out\n\ndef placed(shape, top, left):\n    # A board with only the shape on it: shape rows are strings of \"#\" and\n    # \".\", their top-left corner at (top, left).\n    empty() => grid\n    for i in [0:len(shape) - 1]:\n        for j in [0:len(shape[i]) - 1]:\n            if shape[i][j] == \"#\":\n                toggled(grid, top + i, left + j) => grid\n    return grid\n",
      "python": "rows = 12\ncols = 20\n\ndef empty():\n    grid = []\n    for r in range(1, rows+1):\n        grid = grid + [[0] * cols]\n    return grid\n\ndef neighbours(grid, r, c):\n    n = 0\n    for dr in range(0, 3):\n        for dc in range(0, 3):\n            y = r + dr - 1\n            x = c + dc - 1\n            if (dr != 1 or dc != 1) and y >= 0 and y < rows and x >= 0 and x < cols:\n                n = n + grid[y][x]\n    return n\n\ndef step(grid):\n    out = []\n    born = 0\n    died = 0\n    for r in range(0, rows):\n        row = []\n        for c in range(0, cols):\n            n = neighbours(grid, r, c)\n            cell = 0\n            if grid[r][c] == 1:\n                if n == 2 or n == 3:\n                    cell = 1\n                else:\n                    died = died + 1\n            elif n == 3:\n                cell = 1\n                born = born + 1\n            row = row + [cell]\n        out = out + [row]\n    return [out, born, died]\n\ndef alive(grid):\n    n = 0\n    for row in grid:\n        for cell in row:\n            n = n + cell\n    return n\n\ndef key(grid):\n    s = \"\"\n    for row in grid:\n        for cell in row:\n            if cell == 1:\n                s = s + \"#\"\n            else:\n                s = s + \".\"\n        s = s + \"/\"\n    return s\n\ndef toggled(grid, r, c):\n    out = []\n    for y in range(0, rows):\n        if y == r:\n            row = grid[y][0:c] + [1 - grid[y][c]] + grid[y][c + 1:cols]\n            out = out + [row]\n        else:\n            out = out + [grid[y]]\n    return out\n\ndef placed(shape, top, left):\n    grid = empty()\n    for i in range(0, len(shape)):\n        for j in range(0, len(shape[i])):\n            if shape[i][j] == \"#\":\n                grid = toggled(grid, top + i, left + j)\n    return grid\n"
    },
    {
      "name": "patterns.eml",
      "eml": "# P036 Game of Life - the ready-made patterns, each with where it is placed\n# on the board (top row and left column, counting from 0).\n\n[\n    [\"glider\", [\".#.\", \"..#\", \"###\"], 1, 1],\n    [\"blinker\", [\"###\"], 5, 8],\n    [\"toad\", [\".###\", \"###.\"], 5, 8],\n    [\"beacon\", [\"##..\", \"##..\", \"..##\", \"..##\"], 4, 8],\n    [\"pentadecathlon\", [\"..#....#..\", \"##.####.##\", \"..#....#..\"], 4, 5],\n    [\"R-pentomino\", [\".##\", \"##.\", \".#.\"], 5, 9],\n] => patterns\n",
      "python": "patterns = [[\"glider\", [\".#.\", \"..#\", \"###\"], 1, 1], [\"blinker\", [\"###\"], 5, 8], [\"toad\", [\".###\", \"###.\"], 5, 8], [\"beacon\", [\"##..\", \"##..\", \"..##\", \"..##\"], 4, 8], [\"pentadecathlon\", [\"..#....#..\", \"##.####.##\", \"..#....#..\"], 4, 5], [\"R-pentomino\", [\".##\", \"##.\", \".#.\"], 5, 9]]\n"
    }
  ],
  "sessions": [
    {
      "name": "bad-input",
      "input": "0\nx\n1\n2\n0\n501\nabc\n\n3\n13 1\n1 21\nx\n3\n1 2 3\n\n3\n1 1\n1 1\n12 20\n\n1\n3\n2 2\n2 3\n3 2\n\n2\n5\n5\n3\n9 9\n9 10\n\n2\n5\n4\n0\n7\nx\n\n4\n6\n2\n100\n6\n7\n",
      "screen": "== Game of Life ==\nA 12 x 20 board; cells outside it count as dead. A live cell stays alive\nwith 2 or 3 live neighbours, and a dead cell comes alive with exactly 3.\n\n1) step  2) run  3) toggle cells  4) pattern  5) clear  6) show  7) quit\nchoice> 0\nPick a number from 1 to 7.\n\n1) step  2) run  3) toggle cells  4) pattern  5) clear  6) show  7) quit\nchoice> x\nPick a number from 1 to 7.\n\n1) step  2) run  3) toggle cells  4) pattern  5) clear  6) show  7) quit\nchoice> 1\nGeneration 1: 0 alive (0 born, 0 died)\n    12345678901234567890\n  1 ....................\n  2 ....................\n  3 ....................\n  4 ....................\n  5 ....................\n  6 ....................\n  7 ....................\n  8 ....................\n  9 ....................\n 10 ....................\n 11 ....................\n 12 ....................\nEverything has died.\n\n1) step  2) run  3) toggle cells  4) pattern  5) clear  6) show  7) quit\nchoice> 2\ngenerations (1 to 500)> 0\nType a number from 1 to 500.\ngenerations (1 to 500)> 501\nType a number from 1 to 500.\ngenerations (1 to 500)> abc\nType a number from 1 to 500.\ngenerations (1 to 500)> \nCancelled.\n\n1) step  2) run  3) toggle cells  4) pattern  5) clear  6) show  7) quit\nchoice> 3\ncell (row column, empty to finish)> 13 1\nType a row from 1 to 12 and a column from 1 to 20, like 3 5.\ncell (row column, empty to finish)> 1 21\nType a row from 1 to 12 and a column from 1 to 20, like 3 5.\ncell (row column, empty to finish)> x\nType a row from 1 to 12 and a column from 1 to 20, like 3 5.\ncell (row column, empty to finish)> 3\nType a row from 1 to 12 and a column from 1 to 20, like 3 5.\ncell (row column, empty to finish)> 1 2 3\nType a row from 1 to 12 and a column from 1 to 20, like 3 5.\ncell (row column, empty to finish)> \n\n1) step  2) run  3) toggle cells  4) pattern  5) clear  6) show  7) quit\nchoice> 3\ncell (row column, empty to finish)> 1 1\nRow 1, column 1 is now alive.\ncell (row column, empty to finish)> 1 1\nRow 1, column 1 is now dead.\ncell (row column, empty to finish)> 12 20\nRow 12, column 20 is now alive.\ncell (row column, empty to finish)> \nGeneration 0: 1 alive\n    12345678901234567890\n  1 ....................\n  2 ....................\n  3 ....................\n  4 ....................\n  5 ....................\n  6 ....................\n  7 ....................\n  8 ....................\n  9 ....................\n 10 ....................\n 11 ....................\n 12 ...................#\n\n1) step  2) run  3) toggle cells  4) pattern  5) clear  6) show  7) quit\nchoice> 1\nGeneration 1: 0 alive (0 born, 1 died)\n    12345678901234567890\n  1 ....................\n  2 ....................\n  3 ....................\n  4 ....................\n  5 ....................\n  6 ....................\n  7 ....................\n  8 ....................\n  9 ....................\n 10 ....................\n 11 ....................\n 12 ....................\nEverything has died.\n\n1) step  2) run  3) toggle cells  4) pattern  5) clear  6) show  7) quit\nchoice> 3\ncell (row column, empty to finish)> 2 2\nRow 2, column 2 is now alive.\ncell (row column, empty to finish)> 2 3\nRow 2, column 3 is now alive.\ncell (row column, empty to finish)> 3 2\nRow 3, column 2 is now alive.\ncell (row column, empty to finish)> \nGeneration 0: 3 alive\n    12345678901234567890\n  1 ....................\n  2 .##.................\n  3 .#..................\n  4 ....................\n  5 ....................\n  6 ....................\n  7 ....................\n  8 ....................\n  9 ....................\n 10 ....................\n 11 ....................\n 12 ....................\n\n1) step  2) run  3) toggle cells  4) pattern  5) clear  6) show  7) quit\nchoice> 2\ngenerations (1 to 500)> 5\nStopped after 2 generations: this board was seen before.\nGeneration 2: 4 alive (0 born, 0 died)\n    12345678901234567890\n  1 ....................\n  2 .##.................\n  3 .##.................\n  4 ....................\n  5 ....................\n  6 ....................\n  7 ....................\n  8 ....................\n  9 ....................\n 10 ....................\n 11 ....................\n 12 ....................\nStill life: nothing has changed since generation 1.\n\n1) step  2) run  3) toggle cells  4) pattern  5) clear  6) show  7) quit\nchoice> 5\nThe board is empty.\n\n1) step  2) run  3) toggle cells  4) pattern  5) clear  6) show  7) quit\nchoice> 3\ncell (row column, empty to finish)> 9 9\nRow 9, column 9 is now alive.\ncell (row column, empty to finish)> 9 10\nRow 9, column 10 is now alive.\ncell (row column, empty to finish)> \nGeneration 0: 2 alive\n    12345678901234567890\n  1 ....................\n  2 ....................\n  3 ....................\n  4 ....................\n  5 ....................\n  6 ....................\n  7 ....................\n  8 ....................\n  9 ........##..........\n 10 ....................\n 11 ....................\n 12 ....................\n\n1) step  2) run  3) toggle cells  4) pattern  5) clear  6) show  7) quit\nchoice> 2\ngenerations (1 to 500)> 5\nStopped after 1 generation: no cell is left.\nGeneration 1: 0 alive (0 born, 2 died)\n    12345678901234567890\n  1 ....................\n  2 ....................\n  3 ....................\n  4 ....................\n  5 ....................\n  6 ....................\n  7 ....................\n  8 ....................\n  9 ....................\n 10 ....................\n 11 ....................\n 12 ....................\nEverything has died.\n\n1) step  2) run  3) toggle cells  4) pattern  5) clear  6) show  7) quit\nchoice> 4\n  1) glider\n  2) blinker\n  3) toad\n  4) beacon\n  5) pentadecathlon\n  6) R-pentomino\npattern> 0\nType a number from 1 to 6.\npattern> 7\nType a number from 1 to 6.\npattern> x\nType a number from 1 to 6.\npattern> \nCancelled.\n\n1) step  2) run  3) toggle cells  4) pattern  5) clear  6) show  7) quit\nchoice> 4\n  1) glider\n  2) blinker\n  3) toad\n  4) beacon\n  5) pentadecathlon\n  6) R-pentomino\npattern> 6\nPlaced: R-pentomino.\nGeneration 0: 5 alive\n    12345678901234567890\n  1 ....................\n  2 ....................\n  3 ....................\n  4 ....................\n  5 ....................\n  6 ..........##........\n  7 .........##.........\n  8 ..........#.........\n  9 ....................\n 10 ....................\n 11 ....................\n 12 ....................\n\n1) step  2) run  3) toggle cells  4) pattern  5) clear  6) show  7) quit\nchoice> 2\ngenerations (1 to 500)> 100\nStopped after 77 generations: this board was seen before.\nGeneration 77: 4 alive (0 born, 0 died)\n    12345678901234567890\n  1 ....................\n  2 ....................\n  3 ....................\n  4 ....................\n  5 ....................\n  6 ....................\n  7 ....##..............\n  8 ....##..............\n  9 ....................\n 10 ....................\n 11 ....................\n 12 ....................\nStill life: nothing has changed since generation 76.\n\n1) step  2) run  3) toggle cells  4) pattern  5) clear  6) show  7) quit\nchoice> 6\nGeneration 77: 4 alive\n    12345678901234567890\n  1 ....................\n  2 ....................\n  3 ....................\n  4 ....................\n  5 ....................\n  6 ....................\n  7 ....##..............\n  8 ....##..............\n  9 ....................\n 10 ....................\n 11 ....................\n 12 ....................\n\n1) step  2) run  3) toggle cells  4) pattern  5) clear  6) show  7) quit\nchoice> 7\nBye.\n",
      "interpreter": "equal"
    },
    {
      "name": "basic",
      "input": "4\n1\n1\n1\n2\n50\n4\n5\n2\n20\n5\n3\n6 9\n6 10\n6,11\n\n1\n1\n7\n",
      "screen": "== Game of Life ==\nA 12 x 20 board; cells outside it count as dead. A live cell stays alive\nwith 2 or 3 live neighbours, and a dead cell comes alive with exactly 3.\n\n1) step  2) run  3) toggle cells  4) pattern  5) clear  6) show  7) quit\nchoice> 4\n  1) glider\n  2) blinker\n  3) toad\n  4) beacon\n  5) pentadecathlon\n  6) R-pentomino\npattern> 1\nPlaced: glider.\nGeneration 0: 5 alive\n    12345678901234567890\n  1 ....................\n  2 ..#.................\n  3 ...#................\n  4 .###................\n  5 ....................\n  6 ....................\n  7 ....................\n  8 ....................\n  9 ....................\n 10 ....................\n 11 ....................\n 12 ....................\n\n1) step  2) run  3) toggle cells  4) pattern  5) clear  6) show  7) quit\nchoice> 1\nGeneration 1: 5 alive (2 born, 2 died)\n    12345678901234567890\n  1 ....................\n  2 ....................\n  3 .#.#................\n  4 ..##................\n  5 ..#.................\n  6 ....................\n  7 ....................\n  8 ....................\n  9 ....................\n 10 ....................\n 11 ....................\n 12 ....................\n\n1) step  2) run  3) toggle cells  4) pattern  5) clear  6) show  7) quit\nchoice> 1\nGeneration 2: 5 alive (2 born, 2 died)\n    12345678901234567890\n  1 ....................\n  2 ....................\n  3 ...#................\n  4 .#.#................\n  5 ..##................\n  6 ....................\n  7 ....................\n  8 ....................\n  9 ....................\n 10 ....................\n 11 ....................\n 12 ....................\n\n1) step  2) run  3) toggle cells  4) pattern  5) clear  6) show  7) quit\nchoice> 2\ngenerations (1 to 500)> 50\nStopped after 34 generations: this board was seen before.\nGeneration 36: 4 alive (0 born, 0 died)\n    12345678901234567890\n  1 ....................\n  2 ....................\n  3 ....................\n  4 ....................\n  5 ....................\n  6 ....................\n  7 ....................\n  8 ....................\n  9 ....................\n 10 ....................\n 11 ..........##........\n 12 ..........##........\nStill life: nothing has changed since generation 35.\n\n1) step  2) run  3) toggle cells  4) pattern  5) clear  6) show  7) quit\nchoice> 4\n  1) glider\n  2) blinker\n  3) toad\n  4) beacon\n  5) pentadecathlon\n  6) R-pentomino\npattern> 5\nPlaced: pentadecathlon.\nGeneration 0: 12 alive\n    12345678901234567890\n  1 ....................\n  2 ....................\n  3 ....................\n  4 ....................\n  5 .......#....#.......\n  6 .....##.####.##.....\n  7 .......#....#.......\n  8 ....................\n  9 ....................\n 10 ....................\n 11 ....................\n 12 ....................\n\n1) step  2) run  3) toggle cells  4) pattern  5) clear  6) show  7) quit\nchoice> 2\ngenerations (1 to 500)> 20\nStopped after 15 generations: this board was seen before.\nGeneration 15: 12 alive (8 born, 12 died)\n    12345678901234567890\n  1 ....................\n  2 ....................\n  3 ....................\n  4 ....................\n  5 .......#....#.......\n  6 .....##.####.##.....\n  7 .......#....#.......\n  8 ....................\n  9 ....................\n 10 ....................\n 11 ....................\n 12 ....................\nIt repeats: generation 15 is generation 0 again, a period of 15.\n\n1) step  2) run  3) toggle cells  4) pattern  5) clear  6) show  7) quit\nchoice> 5\nThe board is empty.\n\n1) step  2) run  3) toggle cells  4) pattern  5) clear  6) show  7) quit\nchoice> 3\ncell (row column, empty to finish)> 6 9\nRow 6, column 9 is now alive.\ncell (row column, empty to finish)> 6 10\nRow 6, column 10 is now alive.\ncell (row column, empty to finish)> 6,11\nRow 6, column 11 is now alive.\ncell (row column, empty to finish)> \nGeneration 0: 3 alive\n    12345678901234567890\n  1 ....................\n  2 ....................\n  3 ....................\n  4 ....................\n  5 ....................\n  6 ........###.........\n  7 ....................\n  8 ....................\n  9 ....................\n 10 ....................\n 11 ....................\n 12 ....................\n\n1) step  2) run  3) toggle cells  4) pattern  5) clear  6) show  7) quit\nchoice> 1\nGeneration 1: 3 alive (2 born, 2 died)\n    12345678901234567890\n  1 ....................\n  2 ....................\n  3 ....................\n  4 ....................\n  5 .........#..........\n  6 .........#..........\n  7 .........#..........\n  8 ....................\n  9 ....................\n 10 ....................\n 11 ....................\n 12 ....................\n\n1) step  2) run  3) toggle cells  4) pattern  5) clear  6) show  7) quit\nchoice> 1\nGeneration 2: 3 alive (2 born, 2 died)\n    12345678901234567890\n  1 ....................\n  2 ....................\n  3 ....................\n  4 ....................\n  5 ....................\n  6 ........###.........\n  7 ....................\n  8 ....................\n  9 ....................\n 10 ....................\n 11 ....................\n 12 ....................\nIt repeats: generation 2 is generation 0 again, a period of 2.\n\n1) step  2) run  3) toggle cells  4) pattern  5) clear  6) show  7) quit\nchoice> 7\nBye.\n",
      "interpreter": "equal"
    }
  ],
  "builtOn": [
    {
      "slug": "conway-game-of-life",
      "caseId": "097-conway-game-of-life",
      "title": "Conway's Game of Life"
    }
  ],
  "updated": "2026-10-10"
}
