1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
mod environment_rule;
mod pattern_rule;
use std::fmt::Debug;
use std::fmt::Display;
use super::CellGrid;
pub use environment_rule::EnvironmentRule;
pub use pattern_rule::Pattern;
pub use pattern_rule::PatternRule;
/// A rule describes a transition from one state of a cellular automaton to the next.
pub trait Rule: Debug {
/// Transforms the passed cell grid according to this transformation rule.
/// Transformation happens in-place.
fn transform(&self, grid: &mut CellGrid);
}
/// A multi rule consists of multiple rules. Each rule will be applied in order, and the result of the final application is the result of the multi rule.
#[derive(Debug)]
pub struct MultiRule {
/// The collection of rules to be applied in order.
pub(crate) rules: Vec<Box<dyn Rule>>,
}
impl Rule for MultiRule {
fn transform(&self, grid: &mut CellGrid) {
for rule in &self.rules {
rule.transform(grid);
}
}
}
/// Describes how Rules, specifically [EnvironmentRule] and [PatternRule], deal with the edges of the state space.
#[derive(Clone, Copy, Debug, Default, serde::Serialize, serde::Deserialize)]
pub enum BoundaryBehaviour {
#[default]
/// When trying to get a cell from an index outside of the state space, wrap around
Periodic,
/// When trying to get a cell from outside the state space, return '_' to indicate a wall.
/// PatternRules will not check subareas that leave the state space.
Symbol(char),
}
impl Display for BoundaryBehaviour {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
BoundaryBehaviour::Periodic => write!(f, "Periodic"),
BoundaryBehaviour::Symbol(symbol) => write!(f, "Symbol:{symbol}"),
}
}
}
impl From<&str> for BoundaryBehaviour {
fn from(value: &str) -> Self {
match value {
"Periodic" => Self::Periodic,
value => {
let parts = value.split(':').collect::<Vec<&str>>();
if parts[0] == "Symbol" {
Self::Symbol(parts[1].as_bytes()[0] as char)
} else {
Self::Symbol(' ')
}
}
}
}
}