use crate::{
cells::{Coord, State},
config::Config,
error::Error,
poly_world::PolyWorld,
rules::Rule,
search::{Algorithm, SetCell},
world::World,
};
use serde::{Deserialize, Serialize};
use std::time::Duration;
use std::collections::BTreeMap;
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum ReasonSer {
Known,
Decide,
Rule(Coord),
Sym(Coord),
Deduce,
Clause(Vec<Coord>),
TryAnother(usize),
}
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct SetCellSer {
pub(crate) coord: Coord,
pub(crate) state: State,
pub(crate) reason: ReasonSer,
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(default)]
pub struct WorldSer {
pub config: Config,
pub conflicts: u64,
pub set_stack: Vec<SetCellSer>,
pub check_index: u32,
#[serde(skip_serializing_if = "Option::is_none")]
pub timing: Option<Duration>,
#[serde(skip_serializing_if = "BTreeMap::is_empty")]
pub extra: BTreeMap<String, String>,
}
impl WorldSer {
pub fn deser<R: Rule, A: Algorithm<R>>(&self, world: &mut World<R, A>) -> Result<(), Error> {
for &SetCellSer {
coord,
state,
ref reason,
} in &self.set_stack
{
let cell = world.find_cell(coord).ok_or(Error::SetCellError(coord))?;
if let Some(old_state) = cell.state.get() {
if old_state != state {
return Err(Error::SetCellError(coord));
}
} else if state.0 >= world.rule.gen() {
return Err(Error::InvalidState(coord, state));
} else {
let reason = A::deser_reason(world, reason)?;
let cell = cell;
world.set_cell(cell, state, reason).ok();
}
}
world.conflicts = self.conflicts;
if self.check_index < self.set_stack.len() as u32 {
world.check_index = self.check_index;
}
Ok(())
}
pub fn world(&self) -> Result<PolyWorld, Error> {
let mut world = self.config.world()?;
world.deser(self)?;
Ok(world)
}
}
impl<R: Rule, A: Algorithm<R>> World<R, A> {
#[inline]
pub fn ser(&self) -> WorldSer {
WorldSer {
config: self.config.clone(),
conflicts: self.conflicts,
set_stack: self.set_stack.iter().map(SetCell::ser).collect(),
check_index: self.check_index,
timing: None,
extra: BTreeMap::new(),
}
}
#[inline]
pub fn deser(&mut self, ser: &WorldSer) -> Result<(), Error> {
ser.deser(self)
}
}