henad_core/authoring/model/grid_model.rs
1//! Authoring API for cellular automata over `u8` cells.
2
3use crate::action::ActionDescriptor;
4use crate::grid::Grid2D;
5use crate::params::{ParamDescriptor, ParamValue};
6use crate::topology::NeighborhoodKind;
7use crate::view::{StatDescriptor, StatValue};
8
9/// A cellular automaton over `u8` cells.
10///
11/// The engine owns grid allocation, double buffering, chunking, tick counting, the views, and the
12/// whole `SimState` impl.
13pub trait GridModel: Send + Sync + 'static {
14 /// Name shown in the UI.
15 const NAME: &'static str;
16 /// Stable id that identifies the model in a model set, on the command line and in a spec file.
17 const ID: &'static str;
18 /// One-line description shown in the UI.
19 const DESCRIPTION: &'static str;
20 /// Cell colours, indexed by cell value.
21 const PALETTE: &'static [[u8; 4]];
22 /// Neighbourhood whose cells [`Self::step_cell`] receives.
23 const NEIGHBORHOOD: NeighborhoodKind;
24 /// Stat series for the history chart. Declared once, so `stats` returns bare values.
25 const STATS: &'static [StatDescriptor];
26 /// One-off steps the user can trigger. Each gets a button in the Parameters panel.
27 const ACTIONS: &'static [ActionDescriptor] = &[];
28
29 /// Hot parameters, extracted once per tick to keep enum matching out of the inner loop.
30 type Params: Send + Sync;
31
32 /// Model parameters. The engine prepends grid width and height, but never shows them here.
33 fn param_descriptors() -> Vec<ParamDescriptor>;
34 /// Extracts the hot parameters for one tick. `params` is this model's own slice, so its indices are 0 based.
35 fn from_params(params: &[ParamValue]) -> Self::Params;
36
37 /// Fills the grid for a new run.
38 ///
39 /// `params` is this model's own slice, as for [`Self::from_params`].
40 fn init(grid: &mut Grid2D<u8>, params: &[ParamValue], rng: &mut u64);
41
42 /// Returns the next value of `cell`, given its neighbours.
43 ///
44 /// `neighbors` follows the order of [`MOORE_ROW_MAJOR`] or [`VON_NEUMANN`], as [`Self::NEIGHBORHOOD`] picks.
45 /// The function must be pure apart from `rng`, since the engine steps rows in parallel.
46 ///
47 /// [`MOORE_ROW_MAJOR`]: crate::authoring::primitives::space::MOORE_ROW_MAJOR
48 /// [`VON_NEUMANN`]: crate::authoring::primitives::space::VON_NEUMANN
49 fn step_cell(cell: u8, neighbors: &[u8], params: &Self::Params, rng: &mut u64) -> u8;
50
51 /// Runs [`Self::ACTIONS`] entry `action` over the current cells.
52 ///
53 /// Receives the arguments of `init`. An action is a setup step that the user requests mid run. `rng`
54 /// is a separate stream, so a press leaves the tick's draws where they were.
55 fn act(_action: usize, _grid: &mut Grid2D<u8>, _params: &[ParamValue], _rng: &mut u64) {}
56
57 /// Current statistics, in [`Self::STATS`] order.
58 ///
59 /// A step never calls it. The engine calls it when it publishes a snapshot or takes a sample.
60 fn stats(grid: &Grid2D<u8>) -> Vec<StatValue>;
61}