use crate::{
cells::{CellRef, State},
config::NewState,
rules::Rule,
world::World,
};
use rand::{thread_rng, Rng};
mod backjump;
mod no_backjump;
pub use backjump::ReasonBackjump;
pub use no_backjump::ReasonNoBackjump;
#[cfg(feature = "serde")]
use crate::{
error::Error,
save::{ReasonSer, SetCellSer},
};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum Status {
Initial,
Found,
None,
Searching,
Paused,
}
pub trait Reason<'a, R: Rule>: Sized {
const KNOWN: Self;
const DECIDED: Self;
const LEVEL: bool;
fn from_cell(cell: CellRef<'a, R>) -> Self;
fn is_decided(&self) -> bool;
#[doc(hidden)]
fn go(world: &mut World<'a, R, Self>, step: &mut u64) -> bool;
#[doc(hidden)]
fn retreat(world: &mut World<'a, R, Self>) -> bool;
#[doc(hidden)]
fn presearch(world: World<'a, R, Self>) -> World<'a, R, Self>;
#[cfg(feature = "serde")]
fn ser(&self) -> ReasonSer;
#[cfg(feature = "serde")]
fn deser(ser: &ReasonSer, world: &World<'a, R, Self>) -> Result<Self, Error>;
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct SetCell<'a, R: Rule, RE: Reason<'a, R>> {
pub(crate) cell: CellRef<'a, R>,
pub(crate) reason: RE,
}
impl<'a, R: Rule, RE: Reason<'a, R>> SetCell<'a, R, RE> {
pub(crate) fn new(cell: CellRef<'a, R>, reason: RE) -> Self {
SetCell { cell, reason }
}
#[cfg(feature = "serde")]
pub(crate) fn ser(&self) -> SetCellSer {
SetCellSer {
coord: self.cell.coord,
state: self.cell.state.get().unwrap(),
reason: self.reason.ser(),
}
}
}
impl<'a, R: Rule, RE: Reason<'a, R>> World<'a, R, RE> {
fn decide(&mut self) -> Option<bool> {
if let Some(cell) = self.get_unknown() {
self.next_unknown = cell.next;
let state = match self.config.new_state {
NewState::ChooseDead => cell.background,
NewState::ChooseAlive => !cell.background,
NewState::Random => State(thread_rng().gen_range(0..self.rule.gen())),
};
Some(self.set_cell(cell, state, RE::DECIDED))
} else {
None
}
}
pub fn search(&mut self, max_step: Option<u64>) -> Status {
let mut step_count = 0;
if self.next_unknown.is_none() && !RE::retreat(self) {
return Status::None;
}
while RE::go(self, &mut step_count) {
if let Some(result) = self.decide() {
if !result && !RE::retreat(self) {
return Status::None;
}
} else if !self.is_boring() {
if self.config.reduce_max {
self.config.max_cell_count = Some(self.cell_count() - 1);
}
return Status::Found;
} else if !RE::retreat(self) {
return Status::None;
}
if let Some(max) = max_step {
if step_count > max {
return Status::Searching;
}
}
}
Status::None
}
}