Skip to main content

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}