/// m13 life rules: the next generation is a function of the whole old board, and nothing else. module Snake.Life.Rules open Snake open Snake.Model open Snake.Life.Model /// One generation of Conway's Life on the LW x LH board (B3/S23), from a canonical list of live cells to a canonical /// list (sorted row-major: by `Y`, then `X`; no duplicates). /// - A live cell with 2 or 3 live neighbours stays alive; a dead cell with exactly 3 live neighbours is born; /// every other cell is dead in the next generation. /// - The neighbours of a cell are the up to 8 cells around it that are on the board: the edges are dead, /// nothing wraps around. /// - Every cell is judged by the *old* board only. let lifeStep (cells: Point list) : Point list = failwith "TODO m13" /// The one function that says how the world changes. /// - `Frame`: when running, the next generation (`lifeStep`) and `Generation + 1`; when paused, unchanged. /// - `Step`: when paused, the next generation and `Generation + 1`; when running, unchanged. /// - `TogglePause`: `Running` flips. /// - `Toggle cell`: a dead cell becomes alive, a live one dead, whether the world runs or not; `Cells` stays canonical /// (insert the new cell at its row-major place). A cell off the board changes nothing. `Generation` is unchanged. /// - `Clear`: no live cells, generation 0; `Running` and `Seed` are kept. /// - `Randomize`: draw `Random.intBelow 4` (Module 4) once for every cell of the board, in row-major order /// (y = 0..LH-1, and within a row x = 0..LW-1), threading the seed from `state.Seed`; a cell is alive when its draw /// is 0. The state gets those cells, the seed after the last draw, and generation 0; `Running` is kept. let lifeUpdate (state: LifeState) (action: LifeAction) : LifeState = failwith "TODO m13"