Conway's Game of Life — one generation step on a fixed grid
The grid is a flat row-major list of 0/1 over an r×c board. step() applies the B3/S23 rule with bounded (non-wrapping) neighbour counts. A blinker oscillates with period 2; a block is still life. Run: soma run conway_life.cell --signal demo Test: soma test conway_life.cell
A Soma program from the games part of the verified corpus: 82 lines, cells ConwayLife, ConwayTests. It passes soma check with soma 3.2.4.
How it is built
The cell ConwayLife declares 4 signals in its face: neighbors(grid: List, r: Int, c: Int, y: Int, x: Int) -> Int, step(grid: List, r: Int, c: Int) -> List, alive_count(grid: List) -> Int and demo() -> List. Handlers: neighbors (line 21), alive_count (line 37), step (line 41) and demo (line 57).
The file also holds 1 test cell (ConwayTests) with 7 assertions, run by soma test.
The source
soma.toml
[package]
name = "games-corpus"
version = "0.1.0"
description = "Training corpus: games & simulations"
# The turn/phase machine is intentionally cyclic (a game loops through
# phases each round) with a `* -> over` escape, so we verify only that no
# reachable state deadlocks — liveness to a terminal is not the contract here.
[verify]
deadlock_free = trueconway_life.cell
// ============================================================================
// Conway's Game of Life — one generation step on a fixed grid
// ============================================================================
//
// The grid is a flat row-major list of 0/1 over an r×c board. step() applies
// the B3/S23 rule with bounded (non-wrapping) neighbour counts. A blinker
// oscillates with period 2; a block is still life.
//
// Run: soma run conway_life.cell --signal demo
// Test: soma test conway_life.cell
cell ConwayLife {
face {
signal neighbors(grid: List, r: Int, c: Int, y: Int, x: Int) -> Int
signal step(grid: List, r: Int, c: Int) -> List
signal alive_count(grid: List) -> Int
signal demo() -> List
}
// Count live cells in the 8-neighbourhood of (y,x); edges are dead.
on neighbors(grid: List, r: Int, c: Int, y: Int, x: Int) {
let n = 0
for dy in range(-1, 2) {
for dx in range(-1, 2) {
if dy != 0 || dx != 0 {
let ny = y + dy
let nx = x + dx
if ny >= 0 && ny < r && nx >= 0 && nx < c {
n = n + grid[ny * c + nx]
}
}
}
}
return n
}
on alive_count(grid: List) {
return sum(grid)
}
on step(grid: List, r: Int, c: Int) {
let out = []
for y in range(0, r) {
for x in range(0, c) {
let live = grid[y * c + x]
let n = neighbors(grid, r, c, y, x)
// B3/S23: born on 3, survives on 2 or 3.
let next = 0
if live == 1 && (n == 2 || n == 3) { next = 1 }
if live == 0 && n == 3 { next = 1 }
out = push(out, next)
}
}
return out
}
on demo() {
// vertical blinker in a 3x3 grid → horizontal blinker
let g = [0, 1, 0, 0, 1, 0, 0, 1, 0]
return step(g, 3, 3)
}
}
cell test ConwayTests {
rules {
// Vertical blinker (column) becomes a horizontal blinker (middle row).
// 3x3, live at (0,1),(1,1),(2,1):
assert step([0, 1, 0, 0, 1, 0, 0, 1, 0], 3, 3)[3] == 1
assert step([0, 1, 0, 0, 1, 0, 0, 1, 0], 3, 3)[4] == 1
assert step([0, 1, 0, 0, 1, 0, 0, 1, 0], 3, 3)[5] == 1
assert step([0, 1, 0, 0, 1, 0, 0, 1, 0], 3, 3)[1] == 0
// Two steps returns to the original blinker (period 2).
assert step(step([0, 1, 0, 0, 1, 0, 0, 1, 0], 3, 3), 3, 3)[1] == 1
// A 2x2 block in a 4x4 grid is a still life.
// block at (1,1),(1,2),(2,1),(2,2):
assert alive_count(step(
[0,0,0,0, 0,1,1,0, 0,1,1,0, 0,0,0,0], 4, 4)) == 4
// neighbour count at the centre of the block is 3 (the other 3 block cells)
assert neighbors([0,0,0,0, 0,1,1,0, 0,1,1,0, 0,0,0,0], 4, 4, 1, 1) == 3
}
}What the toolchain says
$ soma check conway_life.cell
✓ All checks passed.$ soma test conway_life.cell
test ConwayTests ...
✓ assert step([0, 1, 0, 0, 1, 0, 0, 1, 0], 3, 3)[3] == 1
✓ assert step([0, 1, 0, 0, 1, 0, 0, 1, 0], 3, 3)[4] == 1
✓ assert step([0, 1, 0, 0, 1, 0, 0, 1, 0], 3, 3)[5] == 1
✓ assert step([0, 1, 0, 0, 1, 0, 0, 1, 0], 3, 3)[1] == 0
✓ assert step(step([0, 1, 0, 0, 1, 0, 0, 1, 0], 3, 3), 3, 3)[1] == 1
✓ assert alive_count(step( [0,0,0,0, 0,1,1,0, 0,1,1,0, 0,0,0,0], 4, 4)) == 4
✓ assert neighbors([0,0,0,0, 0,1,1,0, 0,1,1,0, 0,0,0,0], 4, 4, 1, 1) == 3
7 tests: 7 passed, 0 failed$ soma verify conway_life.cell
Verifying conway_life.cell...
No state machine in this program: nothing to prove beyond `soma check` (invariants and lifecycles are what verify proves).
VERIFY OK (vacuous — no state machine)