puzzle_solver/constraint/
unify.rs1use std::iter;
4use std::rc::Rc;
5
6use ::{Constraint,PsResult,PuzzleSearch,VarToken};
7
8pub struct Unify {
9 var1: VarToken,
10 var2: VarToken,
11}
12
13impl Unify {
14 pub fn new(var1: VarToken, var2: VarToken) -> Self {
28 Unify {
29 var1: var1,
30 var2: var2,
31 }
32 }
33}
34
35impl Constraint for Unify {
36 fn vars<'a>(&'a self) -> Box<Iterator<Item=&'a VarToken> + 'a> {
37 if self.var1 != self.var2 {
38 Box::new(iter::once(&self.var1).chain(iter::once(&self.var2)))
39 } else {
40 Box::new(iter::empty())
41 }
42 }
43
44 fn on_updated(&self, search: &mut PuzzleSearch) -> PsResult<()> {
45 if self.var1 != self.var2 {
46 search.unify(self.var1, self.var2)
47 } else {
48 Ok(())
49 }
50 }
51
52 fn substitute(&self, from: VarToken, to: VarToken)
53 -> PsResult<Rc<Constraint>> {
54 let var1 = if self.var1 == from { to } else { self.var1 };
55 let var2 = if self.var2 == from { to } else { self.var2 };
56 Ok(Rc::new(Unify{ var1: var1, var2: var2 }))
57 }
58}
59
60#[cfg(test)]
61mod tests {
62 use ::Puzzle;
63
64 #[test]
65 fn test_unify_alldifferent() {
66 let mut puzzle = Puzzle::new();
67 let v0 = puzzle.new_var_with_candidates(&[1,2]);
68 let v1 = puzzle.new_var_with_candidates(&[1,2]);
69
70 puzzle.all_different(&[v0, v1]);
71 puzzle.unify(v0, v1);
72
73 let search = puzzle.step();
74 assert!(search.is_none());
75 }
76
77 #[test]
78 fn test_unify_equality() {
79 let mut puzzle = Puzzle::new();
80 let v0 = puzzle.new_var_with_candidates(&[1,2,3,4]);
81 let v1 = puzzle.new_var_with_candidates(&[1,2,3,4]);
82 let v2 = puzzle.new_var_with_candidates(&[1,2,3,4]);
83
84 puzzle.equals(v0 + 2 * v1 + v2, 6);
85 puzzle.unify(v0, v1);
86
87 let search = puzzle.step().expect("contradiction");
88 assert_eq!(search[v0], 1);
89 assert_eq!(search[v1], 1);
90 assert_eq!(search[v2], 3);
91 }
92
93 #[test]
94 fn test_unify_unify() {
95 let mut puzzle = Puzzle::new();
96 let v0 = puzzle.new_var_with_candidates(&[1]);
97 let v1 = puzzle.new_var_with_candidates(&[1,2,3,4]);
98 let v2 = puzzle.new_var_with_candidates(&[1,2,3,4]);
99
100 puzzle.unify(v0, v1);
101 puzzle.unify(v1, v2);
102
103 let search = puzzle.step().expect("contradiction");
104 assert_eq!(search[v0], 1);
105 assert_eq!(search[v1], 1);
106 assert_eq!(search[v2], 1);
107 }
108}