use crate::rules::Rule;
use rand::{
distributions::{Distribution, Standard},
Rng,
};
use std::{
cell::Cell,
fmt::{Debug, Error, Formatter},
ops::Not,
};
pub use State::{Alive, Dead};
#[cfg(feature = "stdweb")]
use serde::{Deserialize, Serialize};
#[derive(Clone, Copy, Debug, PartialEq)]
#[cfg_attr(feature = "stdweb", derive(Serialize, Deserialize))]
pub enum State {
Alive = 0b01,
Dead = 0b10,
}
impl Not for State {
type Output = State;
fn not(self) -> Self::Output {
match self {
Alive => Dead,
Dead => Alive,
}
}
}
impl Distribution<State> for Standard {
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> State {
match rng.gen_range(0, 2) {
0 => Dead,
_ => Alive,
}
}
}
pub struct LifeCell<'a, R: Rule> {
pub(crate) background: State,
pub(crate) state: Cell<Option<State>>,
pub(crate) desc: Cell<R::Desc>,
pub(crate) pred: Option<&'a LifeCell<'a, R>>,
pub(crate) succ: Option<&'a LifeCell<'a, R>>,
pub(crate) nbhd: [Option<&'a LifeCell<'a, R>>; 8],
pub(crate) sym: Vec<&'a LifeCell<'a, R>>,
pub(crate) is_gen0: bool,
pub(crate) is_front: bool,
}
impl<'a, R: Rule> LifeCell<'a, R> {
pub(crate) fn new(background: State, b0: bool) -> Self {
let succ_state = if b0 { !background } else { background };
LifeCell {
background,
state: Cell::new(Some(background)),
desc: Cell::new(R::new_desc(background, succ_state)),
pred: Default::default(),
succ: Default::default(),
nbhd: Default::default(),
sym: Default::default(),
is_gen0: false,
is_front: false,
}
}
pub(crate) fn update_desc(&self, old_state: Option<State>, state: Option<State>) {
R::update_desc(self, old_state, state);
}
}
impl<'a, R: Rule<Desc = D>, D: Copy + Debug> Debug for LifeCell<'a, R> {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
write!(
f,
"LifeCell {{ state: {:?}, desc: {:?} }}",
self.state.get(),
self.desc.get()
)
}
}