// ============================================================================ // 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 } }