use crate::{
cells::{CellRef, 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, PartialEq, Eq)]
pub(crate) enum Reason {
Decide(usize),
Deduce,
}
#[derive(Clone, Copy)]
pub(crate) struct SetCell<'a, R: Rule> {
pub(crate) cell: CellRef<'a, R>,
pub(crate) reason: Reason,
}
impl<'a, R: Rule> SetCell<'a, R> {
pub(crate) fn new(cell: CellRef<'a, R>, reason: Reason) -> Self {
SetCell { cell, reason }
}
}
impl<'a, R: Rule> World<'a, R> {
fn consistify(&mut self, cell: CellRef<'a, R>) -> bool {
Rule::consistify(self, cell)
}
fn consistify10(&mut self, cell: CellRef<'a, R>) -> bool {
self.consistify(cell)
&& {
if let Some(pred) = cell.pred {
self.consistify(pred)
} else {
true
}
}
&& cell
.nbhd
.iter()
.all(|&neigh| self.consistify(neigh.unwrap()))
}
fn proceed(&mut self) -> bool {
while self.check_index < self.set_stack.len() {
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 if !self.set_cell(sym, state, Reason::Deduce) {
return false;
}
}
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.clear_cell(cell);
if 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 u64) -> bool {
loop {
*step += 1;
if self.proceed() {
return true;
} else {
self.conflicts += 1;
if !self.backup() {
return false;
}
}
}
}
fn decide(&mut self) -> Option<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(),
};
Some(self.set_cell(cell, state, Reason::Decide(i)))
} else {
None
}
}
pub fn search(&mut self, max_step: Option<u64>) -> 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 let Some(result) = self.decide() {
if !result && !self.backup() {
return Status::None;
}
} else if self.nontrivial() {
if self.reduce_max {
let cell_count = *self.cell_count.iter().min().unwrap();
self.max_cell_count = Some(cell_count - 1);
}
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<u64>) -> Status;
fn display_gen(&self, t: isize) -> String;
fn period(&self) -> isize;
fn cell_count(&self, t: isize) -> usize;
fn conflicts(&self) -> u64;
fn set_max_cell_count(&mut self, max_cell_count: Option<usize>);
}
impl<'a, R: Rule> Search for World<'a, R> {
fn search(&mut self, max_step: Option<u64>) -> Status {
self.search(max_step)
}
fn display_gen(&self, t: isize) -> String {
self.display_gen(t)
}
fn period(&self) -> isize {
self.period
}
fn cell_count(&self, t: isize) -> usize {
self.cell_count[t as usize]
}
fn conflicts(&self) -> u64 {
self.conflicts
}
fn set_max_cell_count(&mut self, max_cell_count: Option<usize>) {
self.max_cell_count = max_cell_count;
if let Some(max) = self.max_cell_count {
while *self.cell_count.iter().min().unwrap() > max {
if !self.backup() {
break;
}
}
}
}
}