use crate::{
cells::{LifeCell, State},
config::NewState,
rules::Rule,
world::World,
};
#[cfg(feature = "stdweb")]
use serde::{Deserialize, Serialize};
#[derive(Clone, Copy, Debug, PartialEq)]
#[cfg_attr(feature = "stdweb", derive(Serialize, Deserialize))]
pub enum Status {
Found,
None,
Searching,
Paused,
}
#[derive(Clone, Copy)]
pub(crate) enum Reason {
Decide(usize),
Deduce,
}
#[derive(Clone, Copy)]
pub(crate) struct SetCell<'a, R: Rule> {
cell: &'a LifeCell<'a, R>,
reason: Reason,
}
impl<'a, R: Rule> SetCell<'a, R> {
pub(crate) fn new(cell: &'a LifeCell<'a, R>, reason: Reason) -> Self {
SetCell { cell, reason }
}
}
impl<'a, R: Rule> World<'a, R> {
fn consistify(&mut self, cell: &'a LifeCell<'a, R>) -> bool {
Rule::consistify(self, &cell)
}
fn consistify10(&mut self, cell: &'a LifeCell<'a, R>) -> bool {
self.consistify(cell) && {
let pred = cell.pred.unwrap();
self.consistify(pred) && {
cell.nbhd
.iter()
.all(|&neigh| self.consistify(neigh.unwrap()))
}
}
}
fn proceed(&mut self) -> bool {
while self.check_index < self.set_stack.len() {
if let Some(max) = self.max_cell_count {
if self.gen0_cell_count > max {
return false;
}
}
if self.non_empty_front && self.front_cell_count == 0 {
return false;
}
let cell = self.set_stack[self.check_index].cell;
let state = cell.state.get().unwrap();
for &sym in cell.sym.iter() {
if let Some(old_state) = sym.state.get() {
if state != old_state {
return false;
}
} else {
self.set_cell(sym, state, Reason::Deduce);
}
}
if !self.consistify10(cell) {
return false;
}
self.check_index += 1;
}
true
}
fn backup(&mut self) -> bool {
while let Some(set_cell) = self.set_stack.pop() {
let cell = set_cell.cell;
match set_cell.reason {
Reason::Decide(i) => {
self.check_index = self.set_stack.len();
self.search_index = i + 1;
let state = !cell.state.get().unwrap();
self.set_cell(cell, state, Reason::Deduce);
return true;
}
Reason::Deduce => {
self.clear_cell(cell);
}
}
}
self.check_index = 0;
self.search_index = 0;
false
}
fn go(&mut self, step: &mut u32) -> bool {
loop {
*step += 1;
if self.proceed() {
return true;
} else if !self.backup() {
return false;
}
}
}
fn decide(&mut self) -> bool {
if let Some((i, cell)) = self.get_unknown(self.search_index) {
self.search_index = i + 1;
let state = match self.new_state {
NewState::Choose(State::Dead) => cell.background,
NewState::Choose(State::Alive) => !cell.background,
NewState::Random => rand::random(),
};
self.set_cell(cell, state, Reason::Decide(i));
true
} else {
false
}
}
pub fn search(&mut self, max_step: Option<u32>) -> Status {
let mut step_count = 0;
if self.get_unknown(0).is_none() && !self.backup() {
return Status::None;
}
while self.go(&mut step_count) {
if !self.decide() {
if self.nontrivial() {
return Status::Found;
} else if !self.backup() {
return Status::None;
}
}
if let Some(max) = max_step {
if step_count > max {
return Status::Searching;
}
}
}
Status::None
}
}
pub trait Search {
fn search(&mut self, max_step: Option<u32>) -> Status;
fn display_gen(&self, t: isize) -> String;
fn period(&self) -> isize;
fn gen0_cell_count(&self) -> u32;
}
impl<'a, R: Rule> Search for World<'a, R> {
fn search(&mut self, max_step: Option<u32>) -> Status {
self.search(max_step)
}
fn display_gen(&self, t: isize) -> String {
self.display_gen(t)
}
fn period(&self) -> isize {
self.period
}
fn gen0_cell_count(&self) -> u32 {
self.gen0_cell_count
}
}