+ let to_pheno = function
+ | E -> PhenoType.make ' ' None
+ | T -> PhenoType.make 'T' (Some `green)
+ | B -> PhenoType.make '#' (Some `red)
+
+ let of_cell_state = function
+ | Cell.State.Dead -> E
+ | Cell.State.Alive Cell.State.Friendly -> T
+ | Cell.State.Alive Cell.State.Neutral -> E
+ | Cell.State.Alive Cell.State.Hostile -> B
+
+ let to_cell_state = function
+ | E -> Cell.State.Dead
+ | T -> Cell.State.Alive Cell.State.Friendly
+ | B -> Cell.State.Alive Cell.State.Hostile
+
+ let to_cell t =
+ { Cell.state = t |> to_cell_state
+ ; Cell.pheno = t |> to_pheno
+ }
+
+ let f = 0.000001 (* Probability of spontaneous ignition *)
+ let p = 0.1 (* Probability of spontaneous growth *)
+
+ let is_probable p =
+ (Random.float 1.0) <= p
+
+ let next t ~burning_neighbors =
+ match t, burning_neighbors with
+ | E, _ when is_probable p -> T
+ | E, _ -> E
+ | T, 0 when is_probable f -> B
+ | T, _ when burning_neighbors > 0 -> B
+ | T, _ -> T
+ | B, _ -> E
+ end
+
+ let init =
+ State.random |- State.to_cell
+
+ let count_of_burning =
+ List.map ~f:State.of_cell_state
+ |- List.filter ~f:State.is_burning
+ |- List.length
+
+ let transition ~self ~neighbors =
+ self |> State.of_cell_state
+ |> State.next ~burning_neighbors:(count_of_burning neighbors)
+ |> State.to_cell