diff --git a/src/constraint/alldifferent.rs b/src/constraint/alldifferent.rs index 98f9627..d9a6871 100644 --- a/src/constraint/alldifferent.rs +++ b/src/constraint/alldifferent.rs @@ -1,6 +1,7 @@ //! All different implementation. use std::collections::HashMap; +use std::rc::Rc; use ::{Constraint,PuzzleSearch,Val,VarToken}; @@ -75,6 +76,19 @@ impl Constraint for AllDifferent { true } + + fn substitute(&self, from: VarToken, to: VarToken) + -> Option> { + if let Some(idx) = self.vars.iter().position(|&var| var == from) { + if !self.vars.contains(&to) { + let mut new_vars = self.vars.clone(); + new_vars[idx] = to; + return Some(Rc::new(AllDifferent{ vars: new_vars })); + } + } + + None + } } #[cfg(test)] diff --git a/src/constraint/equality.rs b/src/constraint/equality.rs index 24d4f4d..b35aaba 100644 --- a/src/constraint/equality.rs +++ b/src/constraint/equality.rs @@ -1,5 +1,7 @@ //! Equality implementation. +use std::rc::Rc; + use ::{Constraint,LinExpr,PuzzleSearch,Val,VarToken}; use intdiv::IntDiv; @@ -140,6 +142,16 @@ impl Constraint for Equality { true } + + fn substitute(&self, from: VarToken, to: VarToken) + -> Option> { + let mut eqn = self.eqn.clone(); + if let Some(coef) = eqn.coef.remove(&from) { + eqn = eqn + coef * to; + } + + Some(Rc::new(Equality{ eqn: eqn })) + } } #[cfg(test)] diff --git a/src/constraint/mod.rs b/src/constraint/mod.rs index a7ae8f8..3ae214f 100644 --- a/src/constraint/mod.rs +++ b/src/constraint/mod.rs @@ -1,9 +1,11 @@ //! Constraint trait, and some common constraints. //! //! Note that all puzzle states visited during the solution search -//! share the same set of constraints. This means that you cannot -//! store additional information about the state (e.g. caches) in the -//! constraint to reuse later. +//! share the same set of constraint objects. This means that you +//! cannot store additional information about the state (e.g. caches) +//! in the constraint to reuse later. + +use std::rc::Rc; use ::{PuzzleSearch,Val,VarToken}; @@ -28,6 +30,14 @@ pub trait Constraint { fn on_updated(&self, _search: &mut PuzzleSearch) -> bool { true } + + /// Substitute the "from" variable with the "to" variable. + /// + /// Returns a new constraint with all instances of "from" replaced + /// with "to", or None if a contradiction was found in the + /// process. + fn substitute(&self, from: VarToken, to: VarToken) + -> Option>; } pub use self::alldifferent::AllDifferent; diff --git a/tests/queens.rs b/tests/queens.rs index 788fda5..1fc60a0 100644 --- a/tests/queens.rs +++ b/tests/queens.rs @@ -4,6 +4,7 @@ extern crate puzzle_solver; +use std::rc::Rc; use puzzle_solver::{Constraint,Puzzle,PuzzleSearch,Solution,Val,VarToken}; struct NoDiagonal { @@ -29,6 +30,11 @@ impl Constraint for NoDiagonal { true } + + fn substitute(&self, _from: VarToken, _to: VarToken) + -> Option> { + unimplemented!(); + } } fn make_queens(n: usize) -> (Puzzle, Vec) {