├── .gitignore ├── .github └── FUNDING.yml ├── Cargo.toml ├── LICENSE.md ├── examples ├── sudoku-entropy.rs ├── knapsack.rs ├── eight_queens.rs ├── rule_110.rs ├── tsp.rs ├── rule_153.rs ├── sudoku.rs └── magic_square.rs ├── README.md ├── stats └── queens.txt └── src └── lib.rs /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: bvssvni 4 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "quickbacktrack" 3 | version = "0.7.1" 4 | authors = ["Sven Nilsen "] 5 | description = "Library for backtracking with customizable search for moves" 6 | keywords = ["backtrack", "puzzle", "procedural", "generation", "advancedresearch"] 7 | license = "MIT" 8 | repository = "https://github.com/bvssvni/quickbacktrack.git" 9 | homepage = "https://github.com/bvssvni/quickbacktrack" 10 | edition = "2018" 11 | 12 | [dependencies] 13 | fnv = "1.0.5" 14 | rand = "0.7.3" 15 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Sven Nilsen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /examples/sudoku-entropy.rs: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Sudoku example using entropy solver. 4 | 5 | The entropy solver can learn from previous attempts. 6 | 7 | */ 8 | 9 | extern crate quickbacktrack; 10 | 11 | use quickbacktrack::{EntropyBackTrackSolver, Puzzle, EntropySolveSettings, SolveSettings}; 12 | 13 | #[derive(Clone)] 14 | pub struct Sudoku { 15 | pub slots: [[u8; 9]; 9], 16 | } 17 | 18 | impl Puzzle for Sudoku { 19 | type Pos = [usize; 2]; 20 | type Val = u8; 21 | 22 | fn solve_simple(&mut self, mut f: F) { 23 | loop { 24 | let mut found_any = false; 25 | for y in 0..9 { 26 | for x in 0..9 { 27 | if self.slots[y][x] != 0 { continue; } 28 | let possible = self.possible([x, y]); 29 | if possible.len() == 1 { 30 | f(self, [x, y], possible[0]); 31 | found_any = true; 32 | } 33 | } 34 | } 35 | if !found_any { break; } 36 | } 37 | } 38 | 39 | fn set(&mut self, pos: [usize; 2], val: u8) { 40 | self.slots[pos[1]][pos[0]] = val; 41 | } 42 | 43 | fn get(&self, pos: [usize; 2]) -> u8 { 44 | self.slots[pos[1]][pos[0]] 45 | } 46 | 47 | fn remove(&mut self, other: &Sudoku) { 48 | for y in 0..9 { 49 | for x in 0..9 { 50 | if other.slots[y][x] != 0 { 51 | self.slots[y][x] = 0; 52 | } 53 | } 54 | } 55 | } 56 | 57 | fn print(&self) { 58 | println!(" ___ ___ ___"); 59 | for y in 0..9 { 60 | print!("|"); 61 | for x in 0..9 { 62 | let v = self.slots[y][x]; 63 | if v == 0 { 64 | print!(" "); 65 | } else { 66 | print!("{}", self.slots[y][x]); 67 | } 68 | if x % 3 == 2 { 69 | print!("|"); 70 | } 71 | } 72 | println!(""); 73 | if y % 3 == 2 { 74 | println!(" ---+---+---"); 75 | } 76 | } 77 | } 78 | 79 | fn is_solved(&self) -> bool { 80 | for y in 0..9 { 81 | for x in 0..9 { 82 | if self.slots[y][x] == 0 { return false; } 83 | } 84 | } 85 | return true; 86 | } 87 | } 88 | 89 | impl Sudoku { 90 | pub fn possible(&self, pos: [usize; 2]) -> Vec { 91 | let mut res = vec![]; 92 | if self.slots[pos[1]][pos[0]] != 0 { 93 | return res; 94 | } 95 | 'next_val: for v in 1..10 { 96 | for x in 0..9 { 97 | if self.slots[pos[1]][x] == v { 98 | continue 'next_val; 99 | } 100 | if self.slots[x][pos[0]] == v { 101 | continue 'next_val; 102 | } 103 | } 104 | let block_x = 3 * (pos[0] / 3); 105 | let block_y = 3 * (pos[1] / 3); 106 | for y in block_y..block_y + 3 { 107 | for x in block_x..block_x + 3 { 108 | if self.slots[y][x] == v { 109 | continue 'next_val; 110 | } 111 | } 112 | } 113 | res.push(v); 114 | } 115 | return res; 116 | } 117 | } 118 | 119 | fn main() { 120 | let x = example4(); 121 | x.print(); 122 | 123 | let settings = SolveSettings::new() 124 | .solve_simple(true) 125 | .debug(false) 126 | .difference(true) 127 | .sleep_ms(500) 128 | .max_iterations(100) 129 | ; 130 | let entropy_settings = EntropySolveSettings::new() 131 | .attempts(200) 132 | .noise(0.5) 133 | .final_attempt(Some(None)); 134 | 135 | // Generate start choices. 136 | let mut start = vec![]; 137 | for i in 0..9 { 138 | for j in 0..9 { 139 | start.push(([i, j], Sudoku::possible(&x, [i, j]))); 140 | } 141 | } 142 | 143 | let mut solver = EntropyBackTrackSolver::new(x, start, entropy_settings, settings); 144 | 145 | let (i, solution) = solver.solve(Sudoku::possible); 146 | println!("Attempts: {}", i); 147 | let solution = solution.expect("Expected solution"); 148 | 149 | println!("Difference:"); 150 | solution.puzzle.print(); 151 | println!("Non-trivial moves: {}", solution.iterations); 152 | println!("Strategy: {}", solution.strategy.unwrap_or(0)); 153 | } 154 | 155 | pub fn example4() -> Sudoku { 156 | Sudoku { 157 | slots: [ 158 | [0, 5, 0, 0, 9, 6, 0, 7, 0], 159 | [2, 0, 9, 8, 0, 0, 0, 0, 0], 160 | [0, 0, 0, 0, 0, 0, 6, 0, 1], 161 | 162 | [0, 1, 0, 0, 6, 2, 0, 0, 5], 163 | [0, 0, 0, 0, 0, 0, 0, 0, 0], 164 | [8, 0, 0, 5, 1, 0, 0, 6, 0], 165 | 166 | [4, 0, 1, 0, 0, 0, 0, 0, 0], 167 | [0, 0, 0, 0, 0, 7, 3, 0, 9], 168 | [0, 9, 0, 1, 8, 0, 0, 2, 0], 169 | ] 170 | } 171 | } 172 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # QuickBacktrack 2 | Library for backtracking with customizable search for moves 3 | 4 | [Backtracking](https://en.wikipedia.org/wiki/Backtracking) is a general algorithm for finding solutions to constraint satisfaction problems. 5 | 6 | With other words, it solves puzzles like [Sudoku](https://en.wikipedia.org/wiki/Sudoku) or [Knapsack](https://en.wikipedia.org/wiki/Knapsack_problem)! 7 | 8 | ### Features 9 | 10 | - Customizable search for moves 11 | - Debug settings for watching the solving in real time 12 | - Solve simple steps to reduce debug output 13 | - Trait `Puzzle` for solving generic constraint satisfaction problems 14 | - Can start with non-empty puzzle 15 | - Can get difference from initial puzzle state 16 | 17 | ### Sudoku 18 | 19 | ```text 20 | ___ ___ ___ 21 | |43 | 8 |7 | 22 | |17 | 34|8 | 23 | |85 | 6 |3 | 24 | ---+---+--- 25 | |964|153|287| 26 | |285|497|136| 27 | |713|826|945| 28 | ---+---+--- 29 | |521|349|678| 30 | |347|61 |5 | 31 | |698| 7 |413| 32 | ---+---+--- 33 | Guess [8, 1], 9 depth ch: 6 prev: 38 it: 7 34 | ``` 35 | 36 | To run, open up Terminal and type: 37 | 38 | ```text 39 | cargo run --example sudoku 40 | ``` 41 | 42 | ### Knapsack 43 | 44 | ```text 45 | Item { desc: "chocolate", weight: 0.2, value: 40.0 } 46 | Item { desc: "book", weight: 0.5, value: 300.0 } 47 | Item { desc: "hat", weight: 0.1, value: 1000.0 } 48 | total weight: 0.80 49 | total value: 1340.00 50 | ``` 51 | 52 | To run, open up Terminal and type: 53 | 54 | ```text 55 | cargo run --example knapsack 56 | ``` 57 | 58 | ### 8 Queens 59 | 60 | ```text 61 | _ _ _ _ _ _ _ _ 62 | |_|_|_|_|_|_|_|x| 63 | |_|_|_|x|_|_|_|_| 64 | |x|_|_|_|_|_|_|_| 65 | |_|_|x|_|_|_|_|_| 66 | |_|_|_|_|_|_|_|_| 67 | |_|_|_|_|_|_|_|_| 68 | |_|_|_|_|_|_|_|_| 69 | |_|_|_|_|_|_|_|_| 70 | 71 | Guess 6, 7 depth ch: 5 prev: 5 it: 72 72 | ``` 73 | 74 | To run, open up Terminal and type: 75 | 76 | ```text 77 | cargo run --example eight_queens 78 | ``` 79 | 80 | ### Performance 81 | 82 | The performance of finding a solution can vary greatly with the algorithm used to look for the best position to set a value next. For example, a Sudoku puzzle with many missing numbers can take 59 iterations when picking an empty slot with minimum number of options, but it takes 295 992 iterations to solve when looking for the first empty slot. 83 | 84 | One can explain this difference in performance using probability theory. If a slot can contain 2 correct out of N possible values, the odds are `2:(N-2)`. 85 | When this slot is tangled through constraints with another slot with odds `1:(M-1)`, the total odds become `2*1:(N-2)*(M-1)`. To maximize the chance of finding a correct solution, one must maximize the odds for the remaining moves or fail to satisfy the constraints as early as possible. Fewer choices reduces the chances of being wrong, increases the chance of failing constraints early and therefore increases the chance of finding a solution more quickly. 86 | 87 | By making the search customizable, one can easier experiment with different algorithms to pick the next best guess and see which has the best performance on a given problem. This library is designed to assist with this kind of exploration. 88 | 89 | ### Solving simple moves 90 | 91 | In some constraint problems, there are lots of steps that are trivial once a choice is made. For example, in Sudoku a lot of numbers can be filled in once a number is selected for a slot. 92 | 93 | By solving simple moves separately, one can improve performance and reduce the debugging output significantly. 94 | 95 | ### Debugging 96 | 97 | The relationship between the structure of a puzzle and an efficient algorithm to pick the next best guess can be non-trivial, so understanding what happens is essential for finding an efficient algorithm. 98 | 99 | When the setting `SolveSettings::debug(true)` is enabled, the solver prints out the steps to standard output while solving. 100 | 101 | The solver prints "Guess" when making a new move, and "Try" when changing an earlier move. Number of iterations are printed at the end when the puzzle is solved. 102 | 103 | You can slow down the solving by setting `SolveSettings::sleep_ms(1000)`. This makes the solver wait one second (1000 milliseconds) before continuing to the next step. 104 | -------------------------------------------------------------------------------- /examples/knapsack.rs: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | We have a bag with maximum capacity and some valuable items we want to pack into it. 4 | Find the items required to reach maximum value without exceeding the capacity. 5 | 6 | For more information about the Knapsack problem, see https://en.wikipedia.org/wiki/Knapsack_problem 7 | 8 | */ 9 | 10 | extern crate quickbacktrack; 11 | 12 | use quickbacktrack::{BackTrackSolver, Puzzle, SolveSettings}; 13 | 14 | #[derive(Debug)] 15 | pub struct Item { 16 | pub desc: &'static str, 17 | pub weight: f64, 18 | pub value: f64, 19 | } 20 | 21 | #[derive(Debug, Clone)] 22 | pub struct Bag { 23 | pub items: u32, 24 | pub max_weight: f64, 25 | pub target_value: f64, 26 | } 27 | 28 | impl Puzzle for Bag { 29 | type Pos = usize; 30 | type Val = bool; 31 | 32 | fn set(&mut self, ind: usize, val: bool) { 33 | if val { 34 | self.items |= 1 << ind; 35 | } else { 36 | self.items &= !(1 << ind); 37 | } 38 | } 39 | 40 | fn get(&self, ind: usize) -> bool { 41 | self.items & (1 << ind) == (1 << ind) 42 | } 43 | 44 | fn print(&self) { 45 | for i in 0..self.item_count() { 46 | if self.get(i) { 47 | let info = self.item_info(i); 48 | println!("{:?}", info); 49 | } 50 | } 51 | } 52 | 53 | fn is_solved(&self) -> bool { 54 | self.total_value() > self.target_value 55 | } 56 | 57 | fn remove(&mut self, other: &Bag) { 58 | for i in 0..self.item_count() { 59 | if other.get(i) { 60 | self.set(i, false); 61 | } 62 | } 63 | } 64 | } 65 | 66 | impl Bag { 67 | pub fn new(max_weight: f64, target_value: f64) -> Bag { 68 | Bag { 69 | items: 0, 70 | max_weight: max_weight, 71 | target_value: target_value, 72 | } 73 | } 74 | 75 | pub fn item_count(&self) -> usize { 6 } 76 | 77 | pub fn item_info(&self, ind: usize) -> Item { 78 | match ind { 79 | 0 => Item { desc: "chocolate", weight: 0.2, value: 40.0 }, 80 | 1 => Item { desc: "book", weight: 0.5, value: 300.0 }, 81 | 2 => Item { desc: "hat", weight: 0.1, value: 1000.0 }, 82 | 3 => Item { desc: "sleeping bag", weight: 0.8, value: 1400.0 }, 83 | 4 => Item { desc: "socks", weight: 0.1, value: 200.0 }, 84 | 5 => Item { desc: "banana", weight: 0.2, value: 50.0 }, 85 | _ => panic!("Not an item {}", ind), 86 | } 87 | } 88 | 89 | pub fn get(&self, ind: usize) -> bool { 90 | self.items & (1 << ind) == (1 << ind) 91 | } 92 | 93 | pub fn total_weight(&self) -> f64 { 94 | let mut sum = 0.0; 95 | for i in 0..self.item_count() { 96 | if self.get(i) { 97 | let info = self.item_info(i); 98 | sum += info.weight; 99 | } 100 | } 101 | return sum; 102 | } 103 | 104 | pub fn total_value(&self) -> f64 { 105 | let mut sum = 0.0; 106 | for i in 0..self.item_count() { 107 | if self.get(i) { 108 | let info = self.item_info(i); 109 | sum += info.value; 110 | } 111 | } 112 | return sum; 113 | } 114 | 115 | fn possible(&self, ind: usize) -> Vec { 116 | let mut res = vec![]; 117 | if self.get(ind) { 118 | res.push(true); 119 | } else { 120 | let item = self.item_info(ind); 121 | if self.total_weight() + item.weight 122 | <= self.max_weight { 123 | res.push(true); 124 | } 125 | } 126 | return res; 127 | } 128 | } 129 | 130 | fn main() { 131 | let max_weight = 1.2; 132 | let mut target_value = 0.0; 133 | 134 | // Search for solutions, increasing target value until there are no solution found. 135 | loop { 136 | let bag = Bag::new(max_weight, target_value); 137 | 138 | let settings = SolveSettings::new() 139 | .debug(false) 140 | .sleep_ms(100) 141 | ; 142 | let solver = BackTrackSolver::new(bag, settings); 143 | let answer = match solver.solve(|bag| { 144 | for i in 0..bag.item_count() { 145 | if !bag.get(i) { return Some(i); } 146 | } 147 | return None; 148 | }, |bag, ind| bag.possible(ind)) { 149 | None => break, 150 | Some(x) => x.puzzle 151 | }; 152 | answer.print(); 153 | println!("total weight: {:.2}", answer.total_weight()); 154 | println!("total value: {:.2}", answer.total_value()); 155 | println!("~~~"); 156 | target_value = answer.total_value(); 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /examples/eight_queens.rs: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Place 8 queens on a chess board such that they can not attack each other. 4 | 5 | */ 6 | 7 | extern crate quickbacktrack; 8 | 9 | use quickbacktrack::{BackTrackSolver, Puzzle, SolveSettings}; 10 | 11 | #[derive(Clone)] 12 | pub struct EightQueens { 13 | pub queens: Vec, 14 | } 15 | 16 | impl Puzzle for EightQueens { 17 | type Pos = usize; 18 | type Val = u8; 19 | 20 | fn set(&mut self, pos: usize, val: u8) { 21 | self.queens[pos] = val; 22 | } 23 | 24 | fn get(&self, pos: usize) -> u8 { 25 | self.queens[pos] 26 | } 27 | 28 | fn print(&self) { 29 | for _ in 0..self.queens.len() { 30 | print!(" _"); 31 | } 32 | println!(""); 33 | for y in 0..self.queens.len() { 34 | print!("|"); 35 | for x in 0..self.queens.len() as u8 { 36 | let q = self.queens[y]; 37 | if q > 0 && q - 1 == x { 38 | print!("x|"); 39 | } else { 40 | print!("_|"); 41 | } 42 | } 43 | println!("") 44 | } 45 | println!("") 46 | } 47 | 48 | fn is_solved(&self) -> bool { 49 | for q in &self.queens { 50 | if *q == 0 { return false; } 51 | } 52 | return true; 53 | } 54 | 55 | fn remove(&mut self, other: &EightQueens) { 56 | for i in 0..self.queens.len() { 57 | if other.queens[i] > 0 { 58 | self.queens[i] = 0; 59 | } 60 | } 61 | } 62 | } 63 | 64 | impl EightQueens { 65 | pub fn new(size: usize) -> EightQueens { 66 | EightQueens { 67 | queens: vec![0; size] 68 | } 69 | } 70 | 71 | pub fn is_valid(&self, pos: usize, val: u8) -> bool { 72 | for q in &self.queens { 73 | if *q == val { return false; } 74 | } 75 | let this_pos = [val as i8 - 1, pos as i8]; 76 | for (i, q) in self.queens.iter().enumerate() { 77 | if *q == 0 { continue; } 78 | let that_pos = [*q as i8 - 1, i as i8]; 79 | if can_take(that_pos, this_pos) { 80 | return false; 81 | } 82 | } 83 | return true 84 | } 85 | 86 | pub fn next_pos(&self) -> Option { 87 | for i in 0..self.queens.len() { 88 | if self.queens[i] == 0 { return Some(i); } 89 | } 90 | return None; 91 | } 92 | 93 | pub fn next_imp_pos(&self) -> Option { 94 | // If it is impossible to place a queen in any row, 95 | // then the puzzle is impossible to solve. 96 | for i in 0..self.queens.len() { 97 | if self.queens[i] > 0 { continue; } 98 | if self.possible(i).len() == 0 { return None; }; 99 | } 100 | return self.next_pos(); 101 | } 102 | 103 | pub fn find_min_pos(&self) -> Option { 104 | let mut min: Option = None; 105 | let mut min_possible: Option = None; 106 | for i in 0..self.queens.len() { 107 | if self.queens[i] > 0 { continue; } 108 | let possible = self.possible(i); 109 | if min.is_none() || possible.len() < min_possible.unwrap() { 110 | min_possible = Some(possible.len()); 111 | min = Some(i); 112 | } 113 | } 114 | return min; 115 | } 116 | 117 | pub fn find_imp_pos(&self) -> Option { 118 | // If it is impossible to place a queen in any row, 119 | // then the puzzle is impossible to solve. 120 | for i in 0..self.queens.len() { 121 | if self.queens[i] > 0 { continue; } 122 | if self.possible(i).len() == 0 { return None; }; 123 | } 124 | return self.find_min_pos(); 125 | } 126 | 127 | pub fn possible(&self, pos: usize) -> Vec { 128 | let mut res = vec![]; 129 | if self.queens[pos] > 0 { 130 | res.push(self.queens[pos]); 131 | } else { 132 | for v in 1..(self.queens.len() + 1) as u8 { 133 | if self.is_valid(pos, v) { 134 | res.push(v); 135 | } 136 | } 137 | } 138 | return res; 139 | } 140 | } 141 | 142 | fn can_take(a: [i8; 2], b: [i8; 2]) -> bool { 143 | let diff = [a[0] - b[0], a[1] - b[1]]; 144 | return diff[0].abs() == diff[1].abs(); 145 | } 146 | 147 | fn main() { 148 | for i in 8..9 { 149 | let max_iterations = 300_000; 150 | let board = EightQueens::new(i); 151 | let settings = SolveSettings::new() 152 | .debug(true) 153 | .sleep_ms(100) 154 | .max_iterations(max_iterations) 155 | ; 156 | let solver = BackTrackSolver::new(board, settings); 157 | match solver.solve(|board| board.find_min_pos(), 158 | |board, p| board.possible(p)) { 159 | None => { 160 | println!("{} >{}", i, max_iterations); 161 | } 162 | Some(x) => { 163 | // answer.puzzle.print(); 164 | println!("{} {}", i, x.iterations); 165 | } 166 | } 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /examples/rule_110.rs: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Rule 110 is a simple cellular automaton that is universal. 4 | 5 | For more information, see https://en.wikipedia.org/wiki/Rule_110 6 | 7 | This solver reconstructs a space-time of cell states from known states. 8 | It works remarkably well, considering the simple strategy of picking 9 | the most constrained cell. 10 | 11 | */ 12 | 13 | extern crate quickbacktrack; 14 | 15 | use quickbacktrack::{BackTrackSolver, Puzzle, SolveSettings}; 16 | 17 | #[derive(Clone)] 18 | pub struct Rule110 { 19 | pub cells: Vec>, 20 | } 21 | 22 | impl Rule110 { 23 | pub fn next(&mut self) -> Vec { 24 | let last = self.cells.last().unwrap(); 25 | let n = last.len(); 26 | let mut new_row = vec![0; n]; 27 | for i in 0..n { 28 | let input = ( 29 | last[(i + n - 1) % n], 30 | last[i], 31 | last[(i + 1) % n] 32 | ); 33 | new_row[i] = rule(input); 34 | } 35 | new_row 36 | } 37 | 38 | /// Returns `false` when a contradition is found. 39 | /// This is checked by checking all affected cells in next step. 40 | /// Also checks the previous step. 41 | pub fn is_satisfied(&self, pos: [usize; 2], val: u8) -> bool { 42 | let row = pos[0]; 43 | let col = pos[1] as isize; 44 | 45 | let n = self.cells[row].len() as isize; 46 | if row + 1 < self.cells.len() { 47 | // Replace with new value if looking up cell at the location. 48 | let f = |ind: isize| { 49 | let map_ind = ((col + ind + n) % n) as usize; 50 | if map_ind == col as usize { val } 51 | else { self.cells[row][map_ind] } 52 | }; 53 | // [o o x] [o x o] [x o o] 54 | for i in -1..2 { 55 | let input = ( 56 | f(i - 1), 57 | f(i), 58 | f(i + 1), 59 | ); 60 | 61 | let col_next = ((col + n + i) % n) as usize; 62 | let new_value = rule(input); 63 | let old_value = self.cells[row + 1][col_next]; 64 | match (new_value, old_value) { 65 | (_, 0) => {} 66 | (0, _) => {} 67 | (a, b) if a == b => {} 68 | (_, _) => return false, 69 | } 70 | } 71 | } 72 | 73 | // Check that previous row yields value. 74 | if row > 0 { 75 | let f = |ind: isize| { 76 | let map_ind = ((col + ind + n) % n) as usize; 77 | self.cells[row - 1][map_ind] 78 | }; 79 | let input = ( 80 | f(-1), 81 | f(0), 82 | f(1), 83 | ); 84 | match (rule(input), val) { 85 | (_, 0) => {} 86 | (0, _) => {} 87 | (a, b) if a == b => {} 88 | (_, _) => return false, 89 | } 90 | } 91 | 92 | true 93 | } 94 | 95 | pub fn possible(&self, pos: [usize; 2]) -> Vec { 96 | let mut res = vec![]; 97 | for v in 1..3 { 98 | if self.is_satisfied(pos, v) { 99 | res.push(v); 100 | } 101 | } 102 | res 103 | } 104 | 105 | pub fn find_min_empty(&self) -> Option<[usize; 2]> { 106 | let mut min = None; 107 | let mut min_pos = None; 108 | for i in 0..self.cells.len() { 109 | for j in 0..self.cells[i].len() { 110 | if self.cells[i][j] == 0 { 111 | let possible = self.possible([i, j]); 112 | if min.is_none() || min.unwrap() >= possible.len() { 113 | min = Some(possible.len()); 114 | min_pos = Some([i, j]); 115 | } 116 | } 117 | } 118 | } 119 | return min_pos; 120 | } 121 | } 122 | 123 | /// Rule 110 extended with unknown inputs. 124 | fn rule(state: (u8, u8, u8)) -> u8 { 125 | match state { 126 | (2, 2, 2) => 1, 127 | (2, 2, 1) => 2, 128 | (2, 1, 2) => 2, 129 | (2, 1, 1) => 1, 130 | (1, 2, 2) => 2, 131 | (1, 2, 1) => 2, 132 | (1, 1, 2) => 2, 133 | (1, 1, 1) => 1, 134 | 135 | // 1 unknown. 136 | (2, 2, 0) => 0, 137 | (2, 0, 2) => 0, 138 | (0, 2, 2) => 0, 139 | (2, 0, 1) => 0, 140 | (0, 2, 1) => 2, 141 | (2, 1, 0) => 0, 142 | (0, 1, 2) => 2, 143 | (0, 1, 1) => 1, 144 | (1, 2, 0) => 2, 145 | (1, 0, 2) => 2, 146 | (1, 0, 1) => 0, 147 | (1, 1, 0) => 0, 148 | 149 | // All with 2 unknowns or more has unknown result. 150 | (_, _, _) => 0, 151 | } 152 | } 153 | 154 | impl Puzzle for Rule110 { 155 | type Pos = [usize; 2]; 156 | type Val = u8; 157 | 158 | fn solve_simple(&mut self, mut f: F) { 159 | loop { 160 | let mut found_any = false; 161 | for i in 0..self.cells.len() { 162 | for j in 0..self.cells[i].len() { 163 | if self.cells[i][j] != 0 { continue; } 164 | let possible = self.possible([i, j]); 165 | if possible.len() == 1 { 166 | f(self, [i, j], possible[0]); 167 | found_any = true; 168 | } 169 | } 170 | } 171 | if !found_any { break; } 172 | } 173 | } 174 | 175 | fn set(&mut self, pos: [usize; 2], val: u8) { 176 | self.cells[pos[0]][pos[1]] = val; 177 | } 178 | 179 | fn get(&self, pos: [usize; 2]) -> u8 { 180 | self.cells[pos[0]][pos[1]] 181 | } 182 | 183 | fn is_solved(&self) -> bool { 184 | // All cells must be non-empty. 185 | for row in &self.cells { 186 | for col in row { 187 | if *col == 0 { return false; } 188 | } 189 | } 190 | 191 | // All cells must satisfy the constraints. 192 | for i in 0..self.cells.len() { 193 | for j in 0..self.cells[i].len() { 194 | if !self.is_satisfied([i, j], self.cells[i][j]) { 195 | return false; 196 | } 197 | } 198 | } 199 | 200 | true 201 | } 202 | 203 | fn remove(&mut self, other: &Rule110) { 204 | for i in 0..self.cells.len() { 205 | for j in 0..self.cells[i].len() { 206 | if other.cells[i][j] != 0 { 207 | self.cells[i][j] = 0; 208 | } 209 | } 210 | } 211 | } 212 | 213 | fn print(&self) { 214 | println!(""); 215 | for row in &self.cells { 216 | for cell in row { 217 | if *cell == 2 { print!("o"); } 218 | else if *cell == 1 { print!("."); } 219 | else { print!(" "); } 220 | } 221 | println!("") 222 | } 223 | println!(""); 224 | } 225 | } 226 | 227 | fn main() { 228 | /* 229 | let mut r = Rule110 { 230 | cells: vec![ 231 | vec![1, 0, 2, 1] 232 | ] 233 | }; 234 | let next = r.next(); 235 | r.cells.push(next); 236 | r.print(); 237 | */ 238 | 239 | let x = Rule110 { 240 | cells: vec![ 241 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 242 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 243 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 244 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0], 245 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0], 246 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 247 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 248 | vec![0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0], 249 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 250 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0], 251 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 252 | vec![0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 253 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 254 | vec![0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0], 255 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], 256 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 257 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 258 | vec![0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 259 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 260 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 261 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 262 | vec![1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 2, 0], 263 | ] 264 | }; 265 | 266 | let settings = SolveSettings::new() 267 | .solve_simple(true) 268 | .debug(false) 269 | .difference(false) 270 | .sleep_ms(50) 271 | ; 272 | let solver = BackTrackSolver::new(x, settings); 273 | let difference = solver.solve(|s| s.find_min_empty(), |s, p| s.possible(p)) 274 | .expect("Expected solution").puzzle; 275 | println!("Solution:"); 276 | difference.print(); 277 | } 278 | 279 | pub fn example1() -> Rule110 { 280 | Rule110 { 281 | cells: vec![ 282 | vec![1, 1, 1, 2, 1], 283 | vec![1, 0, 0, 0, 1], 284 | vec![1, 0, 0, 0, 1], 285 | vec![2, 2, 1, 2, 1], 286 | ] 287 | } 288 | } 289 | 290 | pub fn example2() -> Rule110 { 291 | Rule110 { 292 | cells: vec![ 293 | vec![1, 1, 0, 0, 0], 294 | vec![0, 0, 0, 0, 0], 295 | vec![0, 0, 0, 0, 0], 296 | vec![2, 2, 1, 2, 1], 297 | ] 298 | } 299 | } 300 | -------------------------------------------------------------------------------- /stats/queens.txt: -------------------------------------------------------------------------------- 1 | size, next_pos, next_imp_pos, find_min_pos, find_imp_pos, 2 | 4, 9, 9, 9, 9, 3 | 5, 6, 6, 6, 6, 4 | 6, 32, 28, 28, 28, 5 | 7, 10, 9, 8, 8, 6 | 8, 114, 89, 76, 76, 7 | 9, 42, 35, 26, 26, 8 | 10, 103, 84, 36, 36, 9 | 11, 53, 41, 61, 61, 10 | 12, 262, 194, 154, 154, 11 | 13, 112, 89, 204, 204, 12 | 14, 1900, 1485, 125, 125, 13 | 15, 1360, 1027, 35, 35, 14 | 16, 10053, 7561, 45, 45, 15 | 17, 5375, 4259, 59, 59, 16 | 18, 41300, 30302, 56, 56, 17 | 19, 2546, 1906, 53, 53, 18 | 20, 199636, 145152, 146, 146, 19 | 21, 8563, 6007, 41, 41, 20 | 22, 1737189, >1000000, 25, 25, 21 | 23, 25429, 17650, 63, 63, 22 | 24, 411609, 286964, 44, 44, 23 | 25, 48684, 32841, 276, 276, 24 | 26, 397700, 269257, 274, 274, 25 | 27, 454214, 310851, 63, 63, 26 | 28, 3006299, >1000000, 29, 29, 27 | 29, 1532240, 995457, 38, 38, 28 | 30, 56429620, >1000000, 148, 148, 29 | 31, 13186251, >1000000, 82, 82, 30 | 32, 87491426, >1000000, 90, 90, 31 | 33, 139956637, >1000000, 39, 39, 32 | 34, >100000, >1000000, 37, 37, 33 | 35, >100000, >1000000, 309, 309, 34 | 36, >100000, >1000000, 51, 51, 35 | 37, >100000, >1000000, 135, 135, 36 | 38, >100000, >1000000, 143, 143, 37 | 39, >100000, >1000000, 200, 200, 38 | 40, >100000, >1000000, 124, 124, 39 | 41, >100000, >1000000, 1248, 1248, 40 | 42, >100000, >1000000, 7331, 7331, 41 | 43, >100000, >1000000, 4743, 4743, 42 | 44, >100000, >1000000, 48, 48, 43 | 45, >100000, >1000000, 366, 366, 44 | 46, >100000, >1000000, 221, 221, 45 | 47, >100000, >1000000, 470, 470, 46 | 48, >100000, >1000000, 146, 146, 47 | 49, >100000, >1000000, 1287, 1287, 48 | 50, >1000000, >1000000, 2069, 2069, 49 | 51, >1000000, >1000000, 314, 314, 50 | 52, >1000000, >1000000, 691, 691, 51 | 53, >1000000, >1000000, 7717, 7717, 52 | 54, >1000000, >1000000, 1529, 1529, 53 | 55, >1000000, >1000000, 891, 891, 54 | 56, >1000000, >1000000, 71, 71, 55 | 57, >10000000, >1000000, 1207, 1207, 56 | 58, >10000000, >300000, 253, 253, 57 | 59, >10000000, >300000, 2332, 2332, 58 | 60, >10000000, >300000, 1726, 1726, 59 | 61, >10000000, >300000, 107, 107, 60 | 62, >10000000, >300000, 961, 961, 61 | 63, >10000000, >300000, 206, 206, 62 | 64, >10000000, >300000, 1623, 1623, 63 | 65, >10000000, >300000, 69, 69, 64 | 66, >10000000, >300000, 434, 434, 65 | 67, >10000000, >300000, 444, 444, 66 | 68, >10000000, >300000, 70, 70, 67 | 69, >10000000, >300000, 77, 77, 68 | 70, >10000000, >300000, 75, 75, 69 | 71, >10000000, >300000, 475, 475, 70 | 72, >10000000, >300000, 177, 177, 71 | 73, >10000000, >300000, 151, 151, 72 | 74, >10000000, >300000, 156, 156, 73 | 75, >10000000, >300000, 9527, 9527, 74 | 76, >10000000, >300000, 250, 250, 75 | 77, >10000000, >300000, 1379, 1379, 76 | 78, >10000000, >300000, 941, 941, 77 | 79, >10000000, >300000, 335, 335, 78 | 80, >10000000, >300000, 165, 165, 79 | 81, >10000000, >300000, 27659, 27659, 80 | 82, >10000000, >300000, 7270, 7270, 81 | 83, >10000000, >300000, 264, 264, 82 | 84, >10000000, >300000, 452, 452, 83 | 85, >10000000, >300000, 107, 107, 84 | 86, >10000000, >300000, 191656, 191656, 85 | 87, >10000000, >300000, 215, 215, 86 | 88, >10000000, >300000, 95354903, >1000000, 87 | 89, >10000000, >300000, 301, 301, 88 | 90, >10000000, >300000, 1670, 1670, 89 | 91, >10000000, >300000, 21260321, >1000000, 90 | 92, >10000000, >300000, 108, 108, 91 | 93, >10000000, >300000, 12724206, >1000000, 92 | 94, >10000000, >300000, 149, 149, 93 | 95, >10000000, >300000, 9478, 9478, 94 | 96, >10000000, >300000, 2201, 2201, 95 | 97, >10000000, >300000, 32096117, >1000000, 96 | 98, >10000000, >300000, 4493361, >1000000, 97 | 99, >10000000, >300000, 27361646, >100000, 98 | 100, >10000000, >300000, 186, 186, 99 | 101, >10000000, >300000, 1370381, >100000, 100 | 102, >10000000, >300000, 192, 192, 101 | 103, >10000000, >300000, 104, 104, 102 | 104, >10000000, >300000, 6514, 6514, 103 | 105, >10000000, >300000, 195838, >100000, 104 | 106, >10000000, >300000, 4047, 4047, 105 | 107, >10000000, >300000, 7183, 7183, 106 | 108, >10000000, >300000, 59646569, >100000, 107 | 109, >10000000, >300000, 686, 686, 108 | 110, >10000000, >300000, 45723396, >100000, 109 | 111, >10000000, >300000, 22231, 22231, 110 | 112, >10000000, >300000, 6122, 6122, 111 | 113, >10000000, >300000, 6014, 6014, 112 | 114, >10000000, >300000, 277, 277, 113 | 115, >1000000, >300000, >1000000, >100000, 114 | 116, >1000000, >300000, 6370, 6370, 115 | 117, >1000000, >300000, 136336, >100000, 116 | 118, >1000000, >300000, 130, 130, 117 | 119, >1000000, >300000, >1000000, >100000, 118 | 120, >1000000, >300000, >1000000, >100000, 119 | 121, >1000000, >300000, 812, 812, 120 | 122, >1000000, >300000, 53181, 53181, 121 | 123, >1000000, >300000, >1000000, >100000, 122 | 124, >1000000, >300000, 524, 524, 123 | 125, >1000000, >300000, 588, 588, 124 | 126, >1000000, >300000, 62499, 62499, 125 | 127, >1000000, >300000, 34791, 34791, 126 | 128, >1000000, >300000, >1000000, >100000, 127 | 129, >1000000, >300000, 979, 979, 128 | 130, >1000000, >300000, 818, 818, 129 | 131, >1000000, >300000, 9372, 9372, 130 | 132, >1000000, >300000, 577, 577, 131 | 133, >1000000, >300000, 3413, 3413, 132 | 134, >1000000, >300000, 489, 489, 133 | 135, >1000000, >300000, 33388, 33388, 134 | 136, >1000000, >300000, >1000000, >100000, 135 | 137, >1000000, >300000, 407, 407, 136 | 138, >1000000, >300000, >1000000, >100000, 137 | 139, >1000000, >300000, 362, 362, 138 | 140, >1000000, >300000, 20262, 20262, 139 | 141, >1000000, >300000, 377, 377, 140 | 142, >1000000, >300000, 724, 724, 141 | 143, >1000000, >300000, 60666, 60666, 142 | 144, >1000000, >300000, 803, 803, 143 | 145, >1000000, >300000, >1000000, >100000, 144 | 146, >1000000, >300000, 288, 288, 145 | 147, >1000000, >300000, 156, 156, 146 | 148, >1000000, >300000, 992, 992, 147 | 149, >1000000, >300000, 331, 331, 148 | 150, >1000000, >300000, >1000000, >100000, 149 | 151, >1000000, >300000, 47092, 47092, 150 | 152, >1000000, >300000, 139417, >100000, 151 | 153, >1000000, >300000, >1000000, >100000, 152 | 154, >1000000, >300000, >1000000, >100000, 153 | 155, >1000000, >300000, >1000000, >100000, 154 | 156, >1000000, >300000, >1000000, >100000, 155 | 157, >1000000, >300000, >1000000, >100000, 156 | 158, >1000000, >300000, 25136, 25136, 157 | 159, >1000000, >300000, >1000000, >100000, 158 | 160, >1000000, >300000, >1000000, >100000, 159 | 161, >1000000, >300000, >1000000, >100000, 160 | 162, >1000000, >300000, >1000000, >100000, 161 | 163, >1000000, >300000, >1000000, >100000, 162 | 164, >1000000, >300000, >1000000, >100000, 163 | 165, >1000000, >300000, >1000000, >100000, 164 | 166, >1000000, >300000, >1000000, >100000, 165 | 167, >1000000, >300000, >1000000, >100000, 166 | 168, >1000000, >300000, >1000000, >100000, 167 | 169, >1000000, >300000, >1000000, >100000, 168 | 170, >1000000, >300000, 2736, 2736, 169 | 171, >1000000, >300000, >1000000, >100000, 170 | 172, >1000000, >300000, >1000000, >100000, 171 | 173, >1000000, >300000, >1000000, >100000, 172 | 174, >1000000, >300000, >1000000, >100000, 173 | 175, >1000000, >300000, >1000000, >100000, 174 | 176, >1000000, >300000, >1000000, >100000, 175 | 177, >1000000, >300000, >1000000, >100000, 176 | 178, >1000000, >300000, >1000000, >100000, 177 | 179, >1000000, >300000, >1000000, >100000, 178 | 180, >1000000, >300000, >1000000, >100000, 179 | 181, >1000000, >300000, >1000000, >100000, 180 | 182, >1000000, >300000, 14246, 14246, 181 | 183, >1000000, >300000, >1000000, >100000, 182 | 184, >1000000, >300000, >1000000, >100000, 183 | 185, >1000000, >300000, >1000000, >100000, 184 | 186, >1000000, >300000, >1000000, >100000, 185 | 187, >1000000, >300000, >1000000, >100000, 186 | 188, >1000000, >300000, >1000000, >100000, 187 | 189, >1000000, >300000, >1000000, >100000, 188 | 190, >1000000, >300000, >1000000, >100000, 189 | 191, >1000000, >300000, >1000000, >100000, 190 | 192, >1000000, >300000, >1000000, >100000, 191 | 193, >1000000, >300000, >1000000, >100000, 192 | 194, >1000000, >300000, >1000000, >100000, 193 | 195, >1000000, >300000, >1000000, >100000, 194 | 196, >1000000, >300000, >1000000, >100000, 195 | 197, >1000000, >300000, >1000000, >100000, 196 | 198, >1000000, >300000, >1000000, >100000, 197 | 199, >1000000, >300000, >1000000, >100000, 198 | -------------------------------------------------------------------------------- /examples/tsp.rs: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Traveling Salesman Problem 4 | 5 | Find a closed route between cities with the shortest length. 6 | 7 | This solver looks for the choice of roads that has the greatest 8 | potential for reducing distance compared to the next best alternative. 9 | Looks at pair of roads instead of considering each single road. 10 | The choice of roads can not lead to cycle. 11 | 12 | The algorithm is exact, and therefore not efficient. 13 | 14 | */ 15 | 16 | extern crate quickbacktrack; 17 | 18 | use std::sync::Arc; 19 | use quickbacktrack::{BackTrackSolver, Puzzle, SolveSettings}; 20 | 21 | #[derive(Clone, Debug)] 22 | pub struct Tsp { 23 | /// Choose a pair of roads for each city. 24 | pub slots: Vec>, 25 | /// Distances between cities. 26 | /// Stores `from` in first index, `to` in second index. 27 | pub distances: Arc>>, 28 | /// Find a distance less than the target. 29 | pub target: Option, 30 | } 31 | 32 | impl Tsp { 33 | pub fn new_2d(map: &Vec>) -> Tsp { 34 | let mut cities: Vec<(usize, usize)> = vec![]; 35 | for i in 0..map.len() { 36 | for j in 0..map[i].len() { 37 | if map[i][j] != 0 { 38 | cities.push((i, j)); 39 | } 40 | } 41 | } 42 | 43 | let mut distances: Vec> = vec![]; 44 | for a in &cities { 45 | let mut a_distances = vec![]; 46 | for b in &cities { 47 | let dx = b.0 as f64 - a.0 as f64; 48 | let dy = b.1 as f64 - a.1 as f64; 49 | a_distances.push((dx * dx + dy * dy).sqrt()); 50 | } 51 | distances.push(a_distances); 52 | } 53 | 54 | Tsp { 55 | slots: vec![None; cities.len()], 56 | distances: Arc::new(distances), 57 | target: None, 58 | } 59 | } 60 | 61 | /// Get possible choices, sorted by local distance. 62 | pub fn possible(&self, pos: usize) -> Vec> { 63 | if self.slots[pos].is_some() { return vec![self.slots[pos]]; } 64 | if let Some(target) = self.target { 65 | if target <= self.distance() { return vec![]; } 66 | } 67 | 68 | let n = self.slots.len(); 69 | let mut res: Vec> = vec![]; 70 | let mut local_distances: Vec<(usize, f64)> = vec![]; 71 | for i in 0..n { 72 | if i == pos { continue; } 73 | 74 | // Other cities must point to this edge. 75 | if let Some((i_a, i_b)) = self.slots[i] { 76 | if i_a != pos && i_b != pos { continue; } 77 | } 78 | 79 | 'j: for j in i + 1..n { 80 | if j == pos { continue; } 81 | 82 | // Other cities must point to this edge. 83 | if let Some((j_a, j_b)) = self.slots[j] { 84 | if j_a != pos && j_b != pos { continue; } 85 | } 86 | 87 | // Check that each city is only referenced twice. 88 | let count_i = self.slots.iter() 89 | .filter(|&&x| { 90 | if let Some((x_a, x_b)) = x { 91 | x_a == i || x_b == i 92 | } else { false } 93 | }).count(); 94 | if count_i >= 2 { continue; } 95 | 96 | let count_j = self.slots.iter() 97 | .filter(|&&x| { 98 | if let Some((x_a, x_b)) = x { 99 | x_a == j || x_b == j 100 | } else { false } 101 | }).count(); 102 | if count_j >= 2 { continue; } 103 | 104 | // Seems sufficient to point other slots to this. 105 | /* 106 | let mut visited: HashSet = HashSet::new(); 107 | visited.insert(pos); 108 | visited.insert(i); 109 | visited.insert(j); 110 | if self.detect_loop(&mut visited, j) { continue 'j; } 111 | */ 112 | 113 | // All other slots that point to this must 114 | // be pointed back to. 115 | for (ind, s) in self.slots.iter().enumerate() { 116 | if let &Some((a, b)) = s { 117 | if a == pos || b == pos { 118 | if i != ind && j != ind { 119 | continue 'j; 120 | } 121 | } 122 | } 123 | } 124 | 125 | local_distances.push((res.len(), 126 | self.distances[pos][i] + self.distances[pos][j])); 127 | res.push(Some((i, j))); 128 | } 129 | } 130 | 131 | if res.len() > 2 { 132 | // Try the pair by order of local distance. 133 | local_distances.sort_by(|a, b| a.1.partial_cmp(&b.1).unwrap()); 134 | res = local_distances.iter().rev().map(|p| res[p.0]).collect(); 135 | } 136 | 137 | res 138 | } 139 | 140 | /* 141 | fn detect_loop(&self, visited: &mut HashSet, pos: usize) -> bool { 142 | if let Some((a, b)) = self.slots[pos] { 143 | if !visited.contains(&a) { 144 | visited.insert(a); 145 | self.detect_loop(visited, a) 146 | } else if !visited.contains(&b) { 147 | visited.insert(b); 148 | self.detect_loop(visited, b) 149 | } else { 150 | true 151 | } 152 | } else { 153 | false 154 | } 155 | } 156 | */ 157 | 158 | pub fn find_empty(&self) -> Option { 159 | for i in 0..self.slots.len() { 160 | if self.slots[i].is_none() { return Some(i); } 161 | } 162 | None 163 | } 164 | 165 | // Pick empty slot with maximum potential of reducing distance 166 | // between first and second choice. 167 | pub fn find_min_empty(&self) -> Option { 168 | let mut max_potential: Option = None; 169 | let mut min_i: Option = None; 170 | for i in 0..self.slots.len() { 171 | if self.slots[i].is_some() { continue; } 172 | 173 | let possible = self.possible(i); 174 | if possible.len() == 0 { return None; } 175 | if possible.len() == 1 { return Some(i); } 176 | if possible.len() >= 2 { 177 | let n = possible.len(); 178 | let (aa, ab) = possible[n - 1].unwrap(); 179 | let (ba, bb) = possible[n - 2].unwrap(); 180 | let potential = 181 | -self.distances[i][aa] + 182 | -self.distances[i][ab] + 183 | self.distances[i][ba] + 184 | self.distances[i][bb]; 185 | if max_potential.is_none() || 186 | max_potential.unwrap() < potential { 187 | min_i = Some(i); 188 | max_potential = Some(potential); 189 | } 190 | } 191 | } 192 | min_i 193 | } 194 | 195 | pub fn distance(&self) -> f64 { 196 | use std::collections::HashSet; 197 | use std::cmp::{max, min}; 198 | 199 | let mut counted: HashSet<(usize, usize)> = HashSet::new(); 200 | let mut dist = 0.0; 201 | for i in 0..self.slots.len() { 202 | if let Some((a, b)) = self.slots[i] { 203 | let i_a = (min(i, a), max(i, a)); 204 | if !counted.contains(&i_a) { 205 | counted.insert(i_a); 206 | dist += self.distances[i][a]; 207 | } 208 | 209 | let i_b = (min(i, b), max(i, b)); 210 | if !counted.contains(&i_b) { 211 | counted.insert(i_b); 212 | dist += self.distances[i][b]; 213 | } 214 | } 215 | } 216 | dist 217 | } 218 | 219 | /// Computes lower bound by summing the minimum pair of distances 220 | /// from each city and then divide by 2. 221 | /// When the optimal route equals the lower bound, each edge 222 | /// is counted twice, so therefore we divide by 2. 223 | pub fn lower_bound(&self) -> f64 { 224 | let mut sum = 0.0; 225 | for s in 0..self.slots.len() { 226 | let mut min_dist: Option = None; 227 | for i in 0..self.slots.len() { 228 | for j in i + 1..self.slots.len() { 229 | let dist = self.distances[s][i] + self.distances[s][j]; 230 | if min_dist.is_none() || min_dist.unwrap() > dist { 231 | min_dist = Some(dist); 232 | } 233 | } 234 | } 235 | sum += min_dist.unwrap_or(0.0); 236 | } 237 | sum / 2.0 238 | } 239 | 240 | pub fn upper_bound(&self) -> f64 { 241 | let mut sum = 0.0; 242 | for s in 0..self.slots.len() { 243 | let mut max_dist: Option = None; 244 | for i in 0..self.slots.len() { 245 | for j in i + 1..self.slots.len() { 246 | let dist = self.distances[s][i] + self.distances[s][j]; 247 | if max_dist.is_none() || max_dist.unwrap() < dist { 248 | max_dist = Some(dist); 249 | } 250 | } 251 | } 252 | sum += max_dist.unwrap_or(0.0); 253 | } 254 | sum / 2.0 255 | } 256 | } 257 | 258 | impl Puzzle for Tsp { 259 | type Pos = usize; 260 | type Val = Option<(usize, usize)>; 261 | 262 | fn set(&mut self, pos: usize, val: Option<(usize, usize)>) { 263 | self.slots[pos] = val; 264 | } 265 | 266 | fn get(&self, pos: usize) -> Option<(usize, usize)> { 267 | self.slots[pos] 268 | } 269 | 270 | fn print(&self) { 271 | println!("{:?}", self.slots); 272 | println!("Distance {}", self.distance()); 273 | } 274 | 275 | fn remove(&mut self, other: &Tsp) { 276 | for i in 0..self.slots.len() { 277 | if other.slots[i].is_some() { 278 | self.slots[i] = None; 279 | } 280 | } 281 | } 282 | 283 | fn is_solved(&self) -> bool { 284 | if let Some(target) = self.target { 285 | if target <= self.distance() { 286 | return false; 287 | } 288 | } 289 | 290 | self.slots.iter().all(|d| d.is_some()) 291 | } 292 | } 293 | 294 | fn main() { 295 | let x = Tsp::new_2d(&vec![ 296 | vec![0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0], 297 | vec![0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 298 | vec![0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1], 299 | vec![1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0], 300 | vec![0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0], 301 | vec![0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0], 302 | vec![0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0], 303 | vec![0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 304 | vec![0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1], 305 | vec![1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0], 306 | vec![0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0], 307 | vec![0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0], 308 | ]); 309 | 310 | // Compute lower bound. 311 | println!("Lower bound: {}", x.lower_bound()); 312 | println!("Upper bound: {}", x.upper_bound()); 313 | 314 | let settings = SolveSettings::new() 315 | .solve_simple(false) 316 | .debug(false) 317 | .difference(true) 318 | .sleep_ms(500) 319 | ; 320 | 321 | let solver = BackTrackSolver::new(x, settings); 322 | let difference = solver.solve(|s| s.find_min_empty(), |s, p| s.possible(p)) 323 | .expect("Expected solution").puzzle; 324 | println!("Difference:"); 325 | difference.print(); 326 | } 327 | -------------------------------------------------------------------------------- /examples/rule_153.rs: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Rule 153 is a simple cellular automaton. 4 | 5 | */ 6 | 7 | extern crate quickbacktrack; 8 | 9 | use quickbacktrack::*; 10 | 11 | const BOUNDARY: bool = false; 12 | 13 | #[derive(Clone)] 14 | pub struct Rule153 { 15 | pub cells: Vec>, 16 | } 17 | 18 | impl Rule153 { 19 | pub fn next(&mut self) -> Vec { 20 | let last = self.cells.last().unwrap(); 21 | let n = last.len(); 22 | let mut new_row = vec![0; n]; 23 | for i in 0..n { 24 | let input = ( 25 | last[(i + n - 1) % n], 26 | last[i], 27 | last[(i + 1) % n] 28 | ); 29 | new_row[i] = rule(input); 30 | } 31 | new_row 32 | } 33 | 34 | /// Returns `false` when a contradition is found. 35 | /// This is checked by checking all affected cells in next step. 36 | /// Also checks the previous step. 37 | pub fn is_satisfied(&self, pos: [usize; 2], val: u8) -> bool { 38 | let row = pos[0]; 39 | let col = pos[1] as isize; 40 | 41 | if self.get(pos) != 0 {return self.get(pos) == val} 42 | 43 | let n = self.cells[row].len() as isize; 44 | if row + 1 < self.cells.len() { 45 | // Replace with new value if looking up cell at the location. 46 | let f = |ind: isize| { 47 | // println!("TEST col + ind {}", col + ind); 48 | let map_ind = ((col + ind + n) % n) as usize; 49 | if BOUNDARY && (col + ind < 0 || col + ind >= n) {1} 50 | else { 51 | if map_ind == col as usize { val } 52 | else {self.cells[row][map_ind]} 53 | } 54 | }; 55 | // [o o x] [o x o] [x o o] 56 | for i in -1..2 { 57 | let input = ( 58 | f(i - 1), 59 | f(i), 60 | f(i + 1), 61 | ); 62 | 63 | let col_next = ((col + n + i) % n) as usize; 64 | let new_value = rule(input); 65 | let old_value = if BOUNDARY && (col + i < 0 || col + i >= n) {1} 66 | else {self.cells[row + 1][col_next]}; 67 | match (new_value, old_value) { 68 | (_, 0) => {} 69 | (0, _) => {} 70 | (a, b) if a == b => {} 71 | (_, _) => return false, 72 | } 73 | } 74 | } 75 | 76 | // Check that previous row yields value. 77 | if row > 0 { 78 | let f = |ind: isize| { 79 | let map_ind = ((col + ind + n) % n) as usize; 80 | if BOUNDARY && (col + ind < 0 || col + ind >= n) {1} 81 | else {self.cells[row - 1][map_ind]} 82 | }; 83 | let input = ( 84 | f(-1), 85 | f(0), 86 | f(1), 87 | ); 88 | match (rule(input), val) { 89 | (_, 0) => {} 90 | (0, _) => {} 91 | (a, b) if a == b => {} 92 | (_, _) => return false, 93 | } 94 | } 95 | 96 | true 97 | } 98 | 99 | pub fn possible(&self, pos: [usize; 2]) -> Vec { 100 | let mut res = vec![]; 101 | if self.get(pos) != 0 {return res} 102 | for v in 1..3 { 103 | if self.is_satisfied(pos, v) { 104 | res.push(v); 105 | } 106 | } 107 | res 108 | } 109 | 110 | pub fn find_min_empty(&self) -> Option<[usize; 2]> { 111 | let mut min = None; 112 | let mut min_pos = None; 113 | for i in 0..self.cells.len() { 114 | for j in 0..self.cells[i].len() { 115 | if self.cells[i][j] == 0 { 116 | let possible = self.possible([i, j]); 117 | if min.is_none() || min.unwrap() >= possible.len() { 118 | min = Some(possible.len()); 119 | min_pos = Some([i, j]); 120 | } 121 | } 122 | } 123 | } 124 | return min_pos; 125 | } 126 | } 127 | 128 | /// Rule 217 extended with unknown inputs. 129 | fn rule(state: (u8, u8, u8)) -> u8 { 130 | match state { 131 | (2, 2, 2) => 2, 132 | (2, 2, 1) => 1, 133 | (2, 1, 2) => 1, 134 | (2, 1, 1) => 2, 135 | (1, 2, 2) => 2, 136 | (1, 2, 1) => 1, 137 | (1, 1, 2) => 1, 138 | (1, 1, 1) => 2, 139 | 140 | // 1 unknown. 141 | (2, 2, 0) => 0, 142 | (2, 0, 2) => 0, 143 | (0, 2, 2) => 2, 144 | (2, 0, 1) => 0, 145 | (0, 2, 1) => 1, 146 | (2, 1, 0) => 0, 147 | (0, 1, 2) => 1, 148 | (0, 1, 1) => 2, 149 | (1, 2, 0) => 0, 150 | (1, 0, 2) => 0, 151 | (1, 0, 1) => 0, 152 | (1, 1, 0) => 0, 153 | 154 | // All with 2 unknowns or more has unknown result. 155 | (_, _, _) => 0, 156 | } 157 | } 158 | 159 | impl Puzzle for Rule153 { 160 | type Pos = [usize; 2]; 161 | type Val = u8; 162 | 163 | fn solve_simple(&mut self, mut f: F) { 164 | loop { 165 | let mut found_any = false; 166 | for i in 0..self.cells.len() { 167 | for j in 0..self.cells[i].len() { 168 | if self.cells[i][j] != 0 { continue; } 169 | let possible = self.possible([i, j]); 170 | if possible.len() == 1 { 171 | f(self, [i, j], possible[0]); 172 | found_any = true; 173 | } 174 | } 175 | } 176 | if !found_any { break; } 177 | } 178 | } 179 | 180 | fn set(&mut self, pos: [usize; 2], val: u8) { 181 | self.cells[pos[0]][pos[1]] = val; 182 | } 183 | 184 | fn get(&self, pos: [usize; 2]) -> u8 { 185 | self.cells[pos[0]][pos[1]] 186 | } 187 | 188 | fn is_solved(&self) -> bool { 189 | // All cells must be non-empty. 190 | for row in &self.cells { 191 | for col in row { 192 | if *col == 0 { return false; } 193 | } 194 | } 195 | 196 | // All cells must satisfy the constraints. 197 | for i in 0..self.cells.len() { 198 | for j in 0..self.cells[i].len() { 199 | if !self.is_satisfied([i, j], self.cells[i][j]) { 200 | return false; 201 | } 202 | } 203 | } 204 | 205 | true 206 | } 207 | 208 | fn remove(&mut self, other: &Rule153) { 209 | for i in 0..self.cells.len() { 210 | for j in 0..self.cells[i].len() { 211 | if other.cells[i][j] != 0 { 212 | self.cells[i][j] = 0; 213 | } 214 | } 215 | } 216 | } 217 | 218 | fn print(&self) { 219 | println!(""); 220 | for row in &self.cells { 221 | for cell in row { 222 | if *cell == 2 { print!("o"); } 223 | else if *cell == 1 { print!("-"); } 224 | else { print!(" "); } 225 | } 226 | println!("") 227 | } 228 | println!(""); 229 | } 230 | } 231 | 232 | fn main() { 233 | let x = example4(); 234 | 235 | // Generate start choices. 236 | let mut start = vec![]; 237 | for i in 0..x.cells.len() { 238 | for j in 0..x.cells[i].len() { 239 | start.push(([i, j], Rule153::possible(&x, [i, j]))); 240 | } 241 | } 242 | 243 | let entropy_settings = EntropySolveSettings::new() 244 | .attempts(20000) 245 | .noise(0.5) 246 | .final_attempt(Some(Some(1000))); 247 | let settings = SolveSettings::new() 248 | .solve_simple(true) 249 | .debug(false) 250 | .difference(false) 251 | .sleep_ms(5) 252 | .max_iterations(100) 253 | ; 254 | let mut solver = EntropyBackTrackSolver::new(x, start, entropy_settings, settings); 255 | let (i, solution) = solver.solve(Rule153::possible); 256 | println!("Attempts: {}", i); 257 | let solution = solution.expect("Expected solution"); 258 | 259 | println!("Solution:"); 260 | solution.puzzle.print(); 261 | println!("Non-trivial moves: {}", solution.iterations); 262 | 263 | } 264 | 265 | pub fn example1() -> Rule153 { 266 | Rule153 { 267 | cells: vec![ 268 | vec![0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1], 269 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 270 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 271 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 272 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 273 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 274 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 275 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 276 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 277 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 278 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 279 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 280 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 281 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 282 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 283 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 284 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 285 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 286 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 287 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 288 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 289 | vec![1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1], 290 | ] 291 | } 292 | } 293 | 294 | pub fn example2() -> Rule153 { 295 | Rule153 { 296 | cells: vec![ 297 | vec![0, 0, 0, 0, 0, 0, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], 298 | vec![0, 0, 0, 0, 0, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0], 299 | vec![0, 0, 0, 0, 0, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0], 300 | vec![0, 0, 0, 0, 0, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0], 301 | vec![0, 0, 0, 0, 0, 0, 1, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], 302 | vec![0, 0, 0, 0, 0, 0, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0], 303 | vec![0, 0, 0, 0, 0, 0, 1, 2, 2, 2, 2, 2, 1, 1, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0], 304 | vec![0, 0, 0, 0, 0, 0, 1, 2, 2, 2, 2, 1, 2, 1, 2, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0], 305 | vec![0, 0, 0, 0, 0, 0, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], 306 | vec![0, 0, 0, 0, 0, 0, 1, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0], 307 | ] 308 | } 309 | } 310 | 311 | pub fn example3() -> Rule153 { 312 | Rule153 { 313 | cells: vec![ 314 | vec![1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1], 315 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 316 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 317 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 318 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 319 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 320 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 321 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 322 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 323 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 324 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 325 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 326 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 327 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 328 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 329 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 330 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 331 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 332 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 333 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 334 | ] 335 | } 336 | } 337 | 338 | 339 | pub fn example4() -> Rule153 { 340 | Rule153 { 341 | cells: vec![ 342 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 343 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 344 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 345 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 346 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 347 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 348 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 349 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 350 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 351 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 352 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 353 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 354 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 355 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 356 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 357 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 358 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 359 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 360 | vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 361 | vec![2, 2, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2], 362 | ] 363 | } 364 | } 365 | -------------------------------------------------------------------------------- /examples/sudoku.rs: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Sudoku is a puzzle where you fill numbers 1-9 until every row, column and group contains 1-9. 4 | 5 | For more information, see https://en.wikipedia.org/wiki/Sudoku 6 | 7 | An interesting thing with this example is the varying performance with different algorithms 8 | for picking the next empty slot. 9 | 10 | */ 11 | 12 | extern crate quickbacktrack; 13 | 14 | use quickbacktrack::{combine, BackTrackSolver, MultiBackTrackSolver, Puzzle, SolveSettings}; 15 | 16 | #[derive(Clone)] 17 | pub struct Sudoku { 18 | pub slots: [[u8; 9]; 9], 19 | } 20 | 21 | impl Puzzle for Sudoku { 22 | type Pos = [usize; 2]; 23 | type Val = u8; 24 | 25 | fn solve_simple(&mut self, mut f: F) { 26 | loop { 27 | let mut found_any = false; 28 | for y in 0..9 { 29 | for x in 0..9 { 30 | if self.slots[y][x] != 0 { continue; } 31 | let possible = self.possible([x, y]); 32 | if possible.len() == 1 { 33 | f(self, [x, y], possible[0]); 34 | found_any = true; 35 | } 36 | } 37 | } 38 | if !found_any { break; } 39 | } 40 | } 41 | 42 | fn set(&mut self, pos: [usize; 2], val: u8) { 43 | self.slots[pos[1]][pos[0]] = val; 44 | } 45 | 46 | fn get(&self, pos: [usize; 2]) -> u8 { 47 | self.slots[pos[1]][pos[0]] 48 | } 49 | 50 | fn remove(&mut self, other: &Sudoku) { 51 | for y in 0..9 { 52 | for x in 0..9 { 53 | if other.slots[y][x] != 0 { 54 | self.slots[y][x] = 0; 55 | } 56 | } 57 | } 58 | } 59 | 60 | fn print(&self) { 61 | println!(" ___ ___ ___"); 62 | for y in 0..9 { 63 | print!("|"); 64 | for x in 0..9 { 65 | let v = self.slots[y][x]; 66 | if v == 0 { 67 | print!(" "); 68 | } else { 69 | print!("{}", self.slots[y][x]); 70 | } 71 | if x % 3 == 2 { 72 | print!("|"); 73 | } 74 | } 75 | println!(""); 76 | if y % 3 == 2 { 77 | println!(" ---+---+---"); 78 | } 79 | } 80 | } 81 | 82 | fn is_solved(&self) -> bool { 83 | for y in 0..9 { 84 | for x in 0..9 { 85 | if self.slots[y][x] == 0 { return false; } 86 | } 87 | } 88 | return true; 89 | } 90 | } 91 | 92 | impl Sudoku { 93 | 94 | pub fn find_empty(&self) -> Option<[usize; 2]> { 95 | for y in 0..9 { 96 | for x in 0..9 { 97 | if self.slots[y][x] == 0 { 98 | return Some([x, y]); 99 | } 100 | } 101 | } 102 | return None; 103 | } 104 | 105 | pub fn find_min_empty(&self) -> Option<[usize; 2]> { 106 | let mut min = None; 107 | let mut min_pos = None; 108 | for y in 0..9 { 109 | for x in 0..9 { 110 | if self.slots[y][x] == 0 { 111 | let possible = self.possible([x, y]); 112 | if possible.len() == 0 {return None}; 113 | if min.is_none() || min.unwrap() > possible.len() { 114 | min = Some(possible.len()); 115 | min_pos = Some([x, y]); 116 | } 117 | } 118 | } 119 | } 120 | return min_pos; 121 | } 122 | 123 | pub fn find_min_potential(&self) -> Option<[usize; 2]> { 124 | let mut min = None; 125 | let mut min_pos = None; 126 | for y in 0..9 { 127 | for x in 0..9 { 128 | if self.slots[y][x] == 0 { 129 | let possible = self.possible_max_future([x, y]); 130 | if possible.len() > 0 { 131 | let mut experiment = self.clone(); 132 | experiment.set([x, y], possible[0]); 133 | let potential = experiment.potential(); 134 | if potential == 0 {continue;} 135 | if min.is_none() || min.unwrap() > potential { 136 | min = Some(potential); 137 | min_pos = Some([x, y]); 138 | } 139 | } 140 | } 141 | } 142 | } 143 | return min_pos; 144 | } 145 | 146 | pub fn find_freq_empty(&self) -> Option<[usize; 2]> { 147 | // Find the frequency of each numbers. 148 | let mut freq = [0; 9]; 149 | let mut mask: [[u16; 9]; 9] = [[0; 9]; 9]; 150 | for y in 0..9 { 151 | for x in 0..9 { 152 | if self.slots[y][x] == 0 { 153 | let possible = self.possible([x, y]); 154 | for p in &possible { 155 | freq[(*p - 1) as usize] += 1; 156 | mask[y][x] |= 1 << (*p - 1); 157 | } 158 | } 159 | } 160 | } 161 | 162 | // Find the number with least frequency, but bigger than 0. 163 | let mut min_freq = None; 164 | for i in 0..9 { 165 | if freq[i] > 0 && (min_freq.is_none() || freq[i] < freq[min_freq.unwrap()]) { 166 | min_freq = Some(i); 167 | } 168 | } 169 | let min_freq = if let Some(i) = min_freq { 170 | i 171 | } else { 172 | return self.find_empty(); 173 | }; 174 | 175 | for y in 0..9 { 176 | for x in 0..9 { 177 | let bit = 1 << min_freq; 178 | if self.slots[y][x] == 0 && (mask[y][x] & bit == bit) { 179 | return Some([x, y]); 180 | } 181 | } 182 | } 183 | return self.find_empty(); 184 | } 185 | 186 | pub fn possible(&self, pos: [usize; 2]) -> Vec { 187 | let mut res = vec![]; 188 | if self.slots[pos[1]][pos[0]] != 0 { 189 | return res; 190 | } 191 | 'next_val: for v in 1..10 { 192 | for x in 0..9 { 193 | if self.slots[pos[1]][x] == v { 194 | continue 'next_val; 195 | } 196 | if self.slots[x][pos[0]] == v { 197 | continue 'next_val; 198 | } 199 | } 200 | let block_x = 3 * (pos[0] / 3); 201 | let block_y = 3 * (pos[1] / 3); 202 | for y in block_y..block_y + 3 { 203 | for x in block_x..block_x + 3 { 204 | if self.slots[y][x] == v { 205 | continue 'next_val; 206 | } 207 | } 208 | } 209 | res.push(v); 210 | } 211 | return res; 212 | } 213 | 214 | pub fn potential(&self) -> usize { 215 | let mut sum_possible = 0; 216 | for y in 0..9 { 217 | for x in 0..9 { 218 | let n = self.possible([x, y]).len(); 219 | if n == 0 { 220 | return 0; 221 | } 222 | sum_possible += n; 223 | } 224 | } 225 | sum_possible 226 | } 227 | 228 | pub fn possible_max_future(&self, pos: [usize; 2]) -> Vec { 229 | let choices = self.possible(pos); 230 | if choices.len() == 1 {return choices;} 231 | let mut potential = vec![]; 232 | 'choice: for &choice in &choices { 233 | let mut experiment = self.clone(); 234 | experiment.set(pos, choice); 235 | let mut sum_possible = 0; 236 | for y in 0..9 { 237 | for x in 0..9 { 238 | let n = experiment.possible([x, y]).len(); 239 | if n == 0 { 240 | potential.push(0); 241 | continue 'choice; 242 | } 243 | sum_possible += n; 244 | } 245 | } 246 | potential.push(sum_possible); 247 | } 248 | 249 | let mut inds: Vec = (0..choices.len()).collect(); 250 | inds.sort_by_key(|&i| potential[i]); 251 | inds.reverse(); 252 | let mut new_choices = Vec::with_capacity(choices.len()); 253 | for &ind in &inds { 254 | new_choices.push(choices[ind]); 255 | } 256 | new_choices 257 | } 258 | 259 | pub fn possible_maxmin_future(&self, pos: [usize; 2]) -> Vec { 260 | let choices = self.possible(pos); 261 | if choices.len() == 1 {return choices;} 262 | let mut potential = vec![]; 263 | 'choice: for &choice in &choices { 264 | let mut experiment = self.clone(); 265 | experiment.set(pos, choice); 266 | let mut maxmin = None; 267 | for y in 0..9 { 268 | for x in 0..9 { 269 | let n = experiment.possible([x, y]).len(); 270 | if n == 0 { 271 | potential.push(0); 272 | continue 'choice; 273 | } 274 | if maxmin.is_none() || maxmin.unwrap() > n { 275 | maxmin = Some(n); 276 | } 277 | } 278 | } 279 | potential.push(maxmin.unwrap_or(0)); 280 | } 281 | 282 | let mut inds: Vec = (0..choices.len()).collect(); 283 | inds.sort_by_key(|&i| potential[i]); 284 | inds.reverse(); 285 | let mut new_choices = Vec::with_capacity(choices.len()); 286 | for &ind in &inds { 287 | new_choices.push(choices[ind]); 288 | } 289 | new_choices 290 | } 291 | 292 | pub fn possible_max_future2(&self, pos: [usize; 2]) -> Vec { 293 | let choices = self.possible(pos); 294 | if choices.len() == 1 {return choices;} 295 | let mut potential = vec![]; 296 | 'choice: for &choice in &choices { 297 | let mut experiment = self.clone(); 298 | experiment.set(pos, choice); 299 | let mut sum_possible = 0; 300 | for y in 0..9 { 301 | for x in 0..9 { 302 | let possible = experiment.possible([x, y]); 303 | if possible.len() == 0 { 304 | potential.push(0); 305 | continue 'choice; 306 | } 307 | let weight = possible.len(); 308 | for &val in &possible { 309 | let mut experiment2 = experiment.clone(); 310 | experiment2.set([x, y], val); 311 | for y2 in 0..9 { 312 | for x2 in 0..9 { 313 | sum_possible += weight * experiment2.possible([x2, y2]).len(); 314 | } 315 | } 316 | } 317 | 318 | } 319 | } 320 | potential.push(sum_possible); 321 | } 322 | 323 | let mut inds: Vec = (0..choices.len()).collect(); 324 | inds.sort_by_key(|&i| potential[i]); 325 | // inds.reverse(); 326 | let mut new_choices = Vec::with_capacity(choices.len()); 327 | for &ind in &inds { 328 | new_choices.push(choices[ind]); 329 | } 330 | new_choices 331 | } 332 | } 333 | 334 | fn main() { 335 | let x = example10(); 336 | x.print(); 337 | 338 | let settings = SolveSettings::new() 339 | .solve_simple(true) 340 | .debug(true) 341 | .difference(true) 342 | .sleep_ms(500) 343 | ; 344 | 345 | let use_multi = false; 346 | 347 | let solution = if use_multi { 348 | let solver = MultiBackTrackSolver::new(settings); 349 | let strategies: Vec<(fn(&_) -> _, fn(&_, _) -> _)> = vec![ 350 | (Sudoku::find_min_empty, Sudoku::possible), 351 | (Sudoku::find_min_empty, Sudoku::possible_max_future), 352 | (Sudoku::find_min_empty, Sudoku::possible_maxmin_future), 353 | (Sudoku::find_min_empty, Sudoku::possible_max_future2), 354 | (Sudoku::find_min_potential, Sudoku::possible), 355 | (Sudoku::find_min_potential, Sudoku::possible_max_future), 356 | (Sudoku::find_min_potential, Sudoku::possible_maxmin_future), 357 | (Sudoku::find_min_potential, Sudoku::possible_max_future2), 358 | (Sudoku::find_empty, Sudoku::possible), 359 | (Sudoku::find_empty, Sudoku::possible_max_future), 360 | (Sudoku::find_empty, Sudoku::possible_maxmin_future), 361 | (Sudoku::find_empty, Sudoku::possible_max_future2), 362 | (Sudoku::find_min_empty, |s: &Sudoku, p: [usize; 2]| combine(vec![ 363 | s.possible(p), 364 | s.possible_max_future(p), 365 | s.possible_maxmin_future(p), 366 | s.possible_max_future2(p), 367 | ])), 368 | (Sudoku::find_min_potential, |s: &Sudoku, p: [usize; 2]| combine(vec![ 369 | s.possible(p), 370 | s.possible_max_future(p), 371 | s.possible_maxmin_future(p), 372 | s.possible_max_future2(p), 373 | ])), 374 | (Sudoku::find_empty, |s: &Sudoku, p: [usize; 2]| combine(vec![ 375 | s.possible(p), 376 | s.possible_max_future(p), 377 | s.possible_maxmin_future(p), 378 | s.possible_max_future2(p), 379 | ])), 380 | ]; 381 | solver.solve(x, &strategies) 382 | } else { 383 | let solver = BackTrackSolver::new(x, settings); 384 | solver.solve(Sudoku::find_min_empty, Sudoku::possible) 385 | }; 386 | 387 | let solution = solution.expect("Expected solution"); 388 | 389 | println!("Difference:"); 390 | solution.puzzle.print(); 391 | println!("Non-trivial moves: {}", solution.iterations); 392 | println!("Strategy: {}", solution.strategy.unwrap_or(0)); 393 | } 394 | 395 | /* 396 | 397 | example best 398 | 1 1 399 | 2 4 400 | 3 5 401 | 4 7 402 | 5 29 403 | 6 4 404 | 7 13 405 | 8 3 406 | 9 5 407 | 10 23 408 | 409 | */ 410 | 411 | pub fn example1() -> Sudoku { 412 | Sudoku { 413 | slots: [ 414 | [0, 4, 1, 0, 9, 0, 2, 0, 0], 415 | [9, 2, 6, 5, 0, 0, 1, 0, 0], 416 | [0, 0, 0, 1, 0, 0, 3, 0, 6], 417 | [6, 3, 0, 0, 4, 0, 0, 8, 9], 418 | [7, 0, 0, 0, 0, 0, 0, 0, 1], 419 | [1, 5, 0, 0, 8, 0, 0, 2, 7], 420 | [2, 0, 9, 0, 0, 7, 0, 0, 0], 421 | [0, 0, 5, 0, 0, 8, 9, 1, 2], 422 | [0, 0, 3, 0, 1, 0, 7, 5, 0], 423 | ] 424 | } 425 | } 426 | 427 | pub fn example2() -> Sudoku { 428 | Sudoku { 429 | slots: [ 430 | // [8, 3, 0, 0, 0, 0, 7, 0, 0], 431 | // [0, 0, 6, 0, 3, 4, 0, 2, 0], 432 | // [4, 7, 0, 9, 0, 0, 0, 6, 0], 433 | [0, 0, 0, 0, 0, 0, 0, 0, 0], 434 | [0, 0, 0, 0, 3, 4, 0, 0, 0], 435 | [0, 0, 0, 0, 0, 0, 0, 0, 0], 436 | 437 | [9, 6, 0, 0, 5, 0, 0, 8, 7], 438 | [2, 0, 0, 0, 0, 0, 0, 0, 6], 439 | [7, 1, 0, 0, 2, 0, 0, 4, 5], 440 | 441 | [0, 2, 0, 0, 0, 9, 0, 7, 8], 442 | [0, 4, 0, 6, 1, 0, 5, 0, 0], 443 | [0, 0, 8, 0, 0, 0, 0, 1, 3], 444 | ] 445 | } 446 | } 447 | 448 | pub fn example3() -> Sudoku { 449 | Sudoku { 450 | slots: [ 451 | [0, 0, 3, 2, 0, 1, 0, 5, 0], 452 | [0, 0, 0, 8, 0, 0, 9, 0, 0], 453 | [0, 4, 5, 0, 0, 3, 0, 0, 1], 454 | 455 | [0, 0, 7, 0, 0, 0, 0, 0, 6], 456 | [4, 0, 0, 0, 0, 0, 0, 0, 8], 457 | [6, 0, 0, 0, 0, 0, 3, 0, 0], 458 | 459 | [5, 0, 0, 7, 0, 0, 8, 9, 0], 460 | [0, 0, 1, 0, 0, 9, 0, 0, 0], 461 | [0, 6, 0, 5, 0, 8, 2, 0, 0], 462 | ] 463 | } 464 | } 465 | 466 | pub fn example4() -> Sudoku { 467 | Sudoku { 468 | slots: [ 469 | [0, 5, 0, 0, 9, 6, 0, 7, 0], 470 | [2, 0, 9, 8, 0, 0, 0, 0, 0], 471 | [0, 0, 0, 0, 0, 0, 6, 0, 1], 472 | 473 | [0, 1, 0, 0, 6, 2, 0, 0, 5], 474 | [0, 0, 0, 0, 0, 0, 0, 0, 0], 475 | [8, 0, 0, 5, 1, 0, 0, 6, 0], 476 | 477 | [4, 0, 1, 0, 0, 0, 0, 0, 0], 478 | [0, 0, 0, 0, 0, 7, 3, 0, 9], 479 | [0, 9, 0, 1, 8, 0, 0, 2, 0], 480 | ] 481 | } 482 | } 483 | 484 | pub fn example5() -> Sudoku { 485 | Sudoku { 486 | slots: [ 487 | [8, 0, 0, 6, 9, 0, 3, 0, 0], 488 | [0, 0, 1, 0, 0, 8, 0, 0, 0], 489 | [0, 3, 0, 5, 0, 0, 0, 9, 0], 490 | 491 | [1, 0, 0, 0, 0, 0, 4, 0, 0], 492 | [7, 0, 0, 0, 8, 0, 0, 0, 2], 493 | [0, 0, 6, 0, 0, 0, 0, 0, 1], 494 | 495 | [0, 1, 0, 0, 0, 2, 0, 3, 0], 496 | [0, 0, 0, 8, 0, 0, 2, 0, 0], 497 | [0, 0, 2, 0, 7, 6, 0, 0, 4], 498 | ] 499 | } 500 | } 501 | 502 | pub fn example6() -> Sudoku { 503 | Sudoku { 504 | slots: [ 505 | [0, 5, 0, 9, 7, 0, 2, 0, 0], 506 | [0, 0, 8, 0, 0, 4, 0, 0, 3], 507 | [1, 4, 0, 0, 0, 0, 0, 0, 0], 508 | 509 | [2, 0, 0, 0, 9, 0, 0, 0, 0], 510 | [0, 1, 0, 3, 0, 2, 0, 5, 0], 511 | [0, 0, 0, 0, 5, 0, 0, 0, 8], 512 | 513 | [0, 0, 0, 0, 0, 0, 0, 1, 2], 514 | [9, 0, 0, 8, 0, 0, 7, 0, 0], 515 | [0, 0, 1, 0, 4, 7, 0, 3, 0], 516 | ] 517 | } 518 | } 519 | 520 | pub fn example7() -> Sudoku { 521 | Sudoku { 522 | slots: [ 523 | [4, 0, 0, 7, 8, 0, 0, 0, 2], 524 | [8, 5, 0, 0, 0, 0, 0, 3, 0], 525 | [0, 0, 0, 0, 0, 2, 6, 0, 0], 526 | 527 | [0, 2, 0, 0, 0, 0, 0, 0, 0], 528 | [0, 3, 0, 5, 0, 6, 0, 1, 0], 529 | [0, 0, 0, 0, 0, 0, 0, 4, 0], 530 | 531 | [0, 0, 5, 6, 0, 0, 0, 0, 0], 532 | [0, 9, 0, 0, 0, 0, 0, 6, 1], 533 | [2, 0, 0, 0, 7, 9, 0, 0, 5], 534 | ] 535 | } 536 | } 537 | 538 | pub fn example8() -> Sudoku { 539 | Sudoku { 540 | slots: [ 541 | [0, 0, 0, 4, 0, 0, 0, 0, 7], 542 | [1, 0, 6, 0, 0, 0, 9, 0, 5], 543 | [0, 4, 0, 9, 0, 0, 0, 0, 8], 544 | 545 | [0, 0, 7, 0, 8, 0, 0, 6, 0], 546 | [0, 0, 0, 7, 0, 9, 0, 0, 0], 547 | [0, 8, 0, 0, 3, 0, 1, 0, 0], 548 | 549 | [9, 0, 0, 0, 0, 5, 0, 8, 0], 550 | [5, 0, 1, 0, 0, 0, 2, 0, 6], 551 | [8, 0, 0, 0, 0, 2, 0, 0, 0], 552 | ] 553 | } 554 | } 555 | 556 | pub fn example9() -> Sudoku { 557 | Sudoku { 558 | slots: [ 559 | [0, 0, 0, 0, 0, 0, 0, 0, 3], 560 | [9, 3, 0, 8, 0, 0, 0, 0, 5], 561 | [0, 0, 0, 0, 7, 0, 6, 1, 0], 562 | 563 | [0, 0, 0, 0, 2, 1, 5, 0, 0], 564 | [0, 6, 0, 4, 0, 8, 0, 7, 0], 565 | [0, 0, 4, 7, 9, 0, 0, 0, 0], 566 | 567 | [0, 8, 5, 0, 3, 0, 0, 0, 0], 568 | [1, 0, 0, 0, 0, 2, 0, 8, 9], 569 | [6, 0, 0, 0, 0, 0, 0, 0, 0], 570 | ] 571 | } 572 | } 573 | 574 | pub fn example10() -> Sudoku { 575 | Sudoku { 576 | slots: [ 577 | [0, 2, 0, 0, 0, 0, 0, 0, 0], 578 | [0, 0, 0, 0, 0, 4, 5, 0, 0], 579 | [0, 6, 0, 0, 0, 0, 0, 0, 0], 580 | 581 | [0, 0, 4, 0, 0, 0, 0, 0, 0], 582 | [9, 0, 3, 0, 1, 0, 0, 7, 0], 583 | [0, 0, 0, 0, 0, 0, 0, 0, 0], 584 | 585 | [0, 0, 0, 0, 0, 0, 0, 0, 0], 586 | [0, 8, 0, 0, 0, 0, 3, 0, 0], 587 | [0, 0, 0, 1, 0, 0, 0, 9, 0], 588 | ] 589 | } 590 | } 591 | -------------------------------------------------------------------------------- /examples/magic_square.rs: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Fill an odd NxN square with numbers 1-(N*N) such that 4 | the sum on each row and column and across diagonals 5 | is the same everywhere. 6 | 7 | A partial sum is when you add things together and some 8 | of the numbers are unknown, but you know the sum must 9 | be at least something because you do not add negative numbers. 10 | 11 | Here I try an approach where the solver focuses on 12 | a position that has the largest partial sum. 13 | 14 | */ 15 | 16 | extern crate quickbacktrack; 17 | 18 | use quickbacktrack::{BackTrackSolver, Puzzle, SolveSettings}; 19 | 20 | #[derive(Clone)] 21 | pub struct MagicSquare { 22 | pub slots: Vec>, 23 | pub exact: u16, 24 | } 25 | 26 | impl Puzzle for MagicSquare { 27 | type Pos = [usize; 2]; 28 | type Val = u16; 29 | 30 | fn set(&mut self, pos: [usize; 2], val: u16) { 31 | self.slots[pos[1]][pos[0]] = val; 32 | } 33 | 34 | fn get(&self, pos: [usize; 2]) -> u16 { 35 | self.slots[pos[1]][pos[0]] 36 | } 37 | 38 | fn remove(&mut self, other: &MagicSquare) { 39 | let n = self.slots.len(); 40 | for y in 0..n { 41 | for x in 0..n { 42 | if other.slots[y][x] != 0 { 43 | self.slots[y][x] = 0; 44 | } 45 | } 46 | } 47 | } 48 | 49 | fn print(&self) { 50 | let n = self.slots.len(); 51 | for y in 0..n { 52 | for x in 0..n { 53 | let val = self.slots[y][x]; 54 | if val == 0 { 55 | print!(" ,") 56 | } else { 57 | if val < 10 { 58 | print!(" {},", val); 59 | } else { 60 | print!("{},", val); 61 | } 62 | } 63 | } 64 | println!(""); 65 | } 66 | } 67 | 68 | fn is_solved(&self) -> bool { 69 | let n = self.slots.len(); 70 | 71 | for y in 0..n { 72 | for x in 0..n { 73 | if self.slots[y][x] == 0 {return false;} 74 | } 75 | } 76 | 77 | let mut find_sum: Option = None; 78 | 79 | for y in 0..n { 80 | let mut sum = 0; 81 | for x in 0..n { 82 | sum += self.slots[y][x]; 83 | } 84 | 85 | if let Some(find_sum) = find_sum { 86 | if sum != find_sum {return false;} 87 | } else { 88 | find_sum = Some(sum); 89 | } 90 | } 91 | 92 | let mut sum1 = 0; 93 | let mut sum2 = 0; 94 | for i in 0..n { 95 | sum1 += self.slots[i][i]; 96 | sum2 += self.slots[i][n - 1 - i]; 97 | } 98 | 99 | if let Some(find_sum) = find_sum { 100 | if sum1 != find_sum {return false;} 101 | if sum2 != find_sum {return false;} 102 | } 103 | 104 | true 105 | } 106 | } 107 | 108 | impl MagicSquare { 109 | pub fn new(n: u16) -> MagicSquare { 110 | MagicSquare { 111 | slots: vec![vec![0; n as usize]; n as usize], 112 | exact: (n * n + 1) / 2 * n, 113 | } 114 | } 115 | 116 | pub fn find_empty(&self) -> Option<[usize; 2]> { 117 | let n = self.slots.len(); 118 | for y in 0..n { 119 | for x in 0..n { 120 | if self.slots[y][x] == 0 {return Some([x, y]);} 121 | } 122 | } 123 | None 124 | } 125 | 126 | // Seems to have no improvement over `find_empty`. 127 | pub fn find_min_empty(&self) -> Option<[usize; 2]> { 128 | let mut min = None; 129 | let mut min_pos = None; 130 | let n = self.slots.len(); 131 | for y in 0..n { 132 | for x in 0..n { 133 | if self.slots[y][x] == 0 { 134 | let possible = self.possible([x, y]); 135 | if min.is_none() || min.unwrap() > possible.len() { 136 | min = Some(possible.len()); 137 | min_pos = Some([x, y]); 138 | } 139 | } 140 | } 141 | } 142 | return min_pos; 143 | } 144 | 145 | pub fn find_max_partial_sum_empty(&self) -> Option<[usize; 2]> { 146 | use PartialSum::*; 147 | 148 | let mut max = None; 149 | let mut max_pos = None; 150 | let n = self.slots.len(); 151 | for y in 0..n { 152 | for x in 0..n { 153 | if self.slots[y][x] == 0 { 154 | let mut sum = 0; 155 | let mut any_zero = false; 156 | for i in 0..n { 157 | let val = self.slots[i][x]; 158 | if val == 0 { 159 | any_zero = true; 160 | sum += 1; 161 | } else { 162 | sum += val; 163 | } 164 | } 165 | match PartialSum::new(sum, any_zero) { 166 | Exact(_) => unreachable!(), 167 | AtLeast(v) => { 168 | if max.is_none() || max.unwrap() < v { 169 | max = Some(v); 170 | max_pos = Some([x, y]); 171 | } 172 | } 173 | } 174 | 175 | let mut sum = 0; 176 | let mut any_zero = false; 177 | for i in 0..n { 178 | let val = self.slots[y][i]; 179 | if val == 0 { 180 | any_zero = true; 181 | sum += 1; 182 | } else { 183 | sum += val; 184 | } 185 | } 186 | match PartialSum::new(sum, any_zero) { 187 | Exact(_) => unreachable!(), 188 | AtLeast(v) => { 189 | if max.is_none() || max.unwrap() < v { 190 | max = Some(v); 191 | max_pos = Some([x, y]); 192 | } 193 | } 194 | } 195 | 196 | if x == y { 197 | let mut sum = 0; 198 | let mut any_zero = false; 199 | for i in 0..n { 200 | let val = self.slots[i][i]; 201 | if val == 0 { 202 | any_zero = true; 203 | sum += 1; 204 | } else { 205 | sum += val; 206 | } 207 | } 208 | match PartialSum::new(sum, any_zero) { 209 | Exact(_) => unreachable!(), 210 | AtLeast(v) => { 211 | if max.is_none() || max.unwrap() < v { 212 | max = Some(v); 213 | max_pos = Some([x, y]); 214 | } 215 | } 216 | } 217 | } 218 | 219 | if n - 1 - x == y { 220 | let mut sum = 0; 221 | let mut any_zero = false; 222 | for i in 0..n { 223 | let val = self.slots[i][n - 1 - i]; 224 | if val == 0 { 225 | any_zero = true; 226 | sum += 1; 227 | } else { 228 | sum += val; 229 | } 230 | } 231 | match PartialSum::new(sum, any_zero) { 232 | Exact(_) => unreachable!(), 233 | AtLeast(v) => { 234 | if max.is_none() || max.unwrap() < v { 235 | max = Some(v); 236 | max_pos = Some([x, y]); 237 | } 238 | } 239 | } 240 | } 241 | } 242 | } 243 | } 244 | return max_pos; 245 | } 246 | 247 | // Worse than `find_max_partial_sum_empty`. 248 | pub fn find_min_partial_sum_empty(&self) -> Option<[usize; 2]> { 249 | use PartialSum::*; 250 | 251 | let mut min = None; 252 | let mut min_pos = None; 253 | let n = self.slots.len(); 254 | for y in 0..n { 255 | for x in 0..n { 256 | if self.slots[y][x] == 0 { 257 | let mut sum = 0; 258 | let mut any_zero = false; 259 | for i in 0..n { 260 | let val = self.slots[i][x]; 261 | if val == 0 { 262 | any_zero = true; 263 | sum += 1; 264 | } else { 265 | sum += val; 266 | } 267 | } 268 | match PartialSum::new(sum, any_zero) { 269 | Exact(_) => unreachable!(), 270 | AtLeast(v) => { 271 | if min.is_none() || min.unwrap() > v { 272 | min = Some(v); 273 | min_pos = Some([x, y]); 274 | } 275 | } 276 | } 277 | 278 | let mut sum = 0; 279 | let mut any_zero = false; 280 | for i in 0..n { 281 | let val = self.slots[y][i]; 282 | if val == 0 { 283 | any_zero = true; 284 | sum += 1; 285 | } else { 286 | sum += val; 287 | } 288 | } 289 | match PartialSum::new(sum, any_zero) { 290 | Exact(_) => unreachable!(), 291 | AtLeast(v) => { 292 | if min.is_none() || min.unwrap() > v { 293 | min = Some(v); 294 | min_pos = Some([x, y]); 295 | } 296 | } 297 | } 298 | 299 | if x == y { 300 | let mut sum = 0; 301 | let mut any_zero = false; 302 | for i in 0..n { 303 | let val = self.slots[i][i]; 304 | if val == 0 { 305 | any_zero = true; 306 | sum += 1; 307 | } else { 308 | sum += val; 309 | } 310 | } 311 | match PartialSum::new(sum, any_zero) { 312 | Exact(_) => unreachable!(), 313 | AtLeast(v) => { 314 | if min.is_none() || min.unwrap() > v { 315 | min = Some(v); 316 | min_pos = Some([x, y]); 317 | } 318 | } 319 | } 320 | } 321 | 322 | if n - 1 - x == y { 323 | let mut sum = 0; 324 | let mut any_zero = false; 325 | for i in 0..n { 326 | let val = self.slots[i][n - 1 - i]; 327 | if val == 0 { 328 | any_zero = true; 329 | sum += 1; 330 | } else { 331 | sum += val; 332 | } 333 | } 334 | match PartialSum::new(sum, any_zero) { 335 | Exact(_) => unreachable!(), 336 | AtLeast(v) => { 337 | if min.is_none() || min.unwrap() > v { 338 | min = Some(v); 339 | min_pos = Some([x, y]); 340 | } 341 | } 342 | } 343 | } 344 | } 345 | } 346 | } 347 | return min_pos; 348 | } 349 | 350 | pub fn possible(&self, pos: [usize; 2]) -> Vec { 351 | let mut res = vec![]; 352 | if self.slots[pos[1]][pos[0]] != 0 { 353 | res.push(self.slots[pos[1]][pos[0]]); 354 | return res; 355 | } 356 | 357 | match self.find_partial_sum() { 358 | Some(PartialSum::Exact(sum)) => { 359 | if self.exact != sum {return vec![];} 360 | } 361 | Some(PartialSum::AtLeast(sum)) => { 362 | if self.exact < sum {return vec![];} 363 | } 364 | None => { 365 | // If partial sum is inconsistent, then there are no options. 366 | return vec![]; 367 | } 368 | } 369 | 370 | let n = self.slots.len(); 371 | 'outer: for i in 0..n * n { 372 | let val = (i + 1) as u16; 373 | for y in 0..n { 374 | for x in 0..n { 375 | if [x, y] == pos {continue;} 376 | if self.slots[y][x] == val {continue 'outer;} 377 | } 378 | } 379 | res.push(val); 380 | } 381 | res 382 | } 383 | 384 | pub fn find_partial_sum(&self) -> Option { 385 | let mut find_sum: Option = None; 386 | let n = self.slots.len(); 387 | 388 | for i in 0..n { 389 | let mut sum = 0; 390 | let mut any_zero = false; 391 | for x in 0..n { 392 | let val = self.slots[i][x]; 393 | if val == 0 { 394 | any_zero = true; 395 | sum += 1; 396 | } else { 397 | sum += val; 398 | } 399 | } 400 | let row = PartialSum::new(sum, any_zero); 401 | find_sum = if let Some(ref find_sum) = find_sum { 402 | if let Some(new_find_sum) = find_sum.improve(&row) { 403 | Some(new_find_sum) 404 | } else { 405 | return None; 406 | } 407 | } else { 408 | Some(row) 409 | }; 410 | 411 | let mut sum = 0; 412 | let mut any_zero = false; 413 | for y in 0..n { 414 | let val = self.slots[y][i]; 415 | if val == 0 { 416 | any_zero = true; 417 | sum += 1; 418 | } else { 419 | sum += val; 420 | } 421 | } 422 | let col = PartialSum::new(sum, any_zero); 423 | find_sum = if let Some(ref find_sum) = find_sum { 424 | if let Some(new_find_sum) = find_sum.improve(&col) { 425 | Some(new_find_sum) 426 | } else { 427 | return None; 428 | } 429 | } else { 430 | Some(col) 431 | }; 432 | } 433 | 434 | let mut sum = 0; 435 | let mut any_zero = false; 436 | for i in 0..n { 437 | let val = self.slots[i][i]; 438 | if val == 0 { 439 | any_zero = true; 440 | sum += 1; 441 | } else { 442 | sum += val; 443 | } 444 | } 445 | let diag1 = PartialSum::new(sum, any_zero); 446 | find_sum = if let Some(ref find_sum) = find_sum { 447 | if let Some(new_find_sum) = find_sum.improve(&diag1) { 448 | Some(new_find_sum) 449 | } else { 450 | return None; 451 | } 452 | } else { 453 | Some(diag1) 454 | }; 455 | 456 | let mut sum = 0; 457 | let mut any_zero = false; 458 | for i in 0..n { 459 | let val = self.slots[i][n - 1 - i]; 460 | if val == 0 { 461 | any_zero = true; 462 | sum += 1; 463 | } else { 464 | sum += val; 465 | } 466 | } 467 | let diag2 = PartialSum::new(sum, any_zero); 468 | find_sum = if let Some(ref find_sum) = find_sum { 469 | if let Some(new_find_sum) = find_sum.improve(&diag2) { 470 | Some(new_find_sum) 471 | } else { 472 | return None; 473 | } 474 | } else { 475 | Some(diag2) 476 | }; 477 | 478 | find_sum 479 | } 480 | } 481 | 482 | #[derive(Clone)] 483 | pub enum PartialSum { 484 | /// The sum is known exactly. 485 | Exact(u16), 486 | /// The sum must be at least something. 487 | AtLeast(u16), 488 | } 489 | 490 | impl PartialSum { 491 | pub fn new(sum: u16, any_zero: bool) -> PartialSum { 492 | if any_zero { 493 | PartialSum::AtLeast(sum) 494 | } else { 495 | PartialSum::Exact(sum) 496 | } 497 | } 498 | 499 | /// Returns `Some(true)` is equal, `Some(false)` is not equal, 500 | /// and `None` if it is unknown whether they are equal. 501 | pub fn equal(&self, other: &PartialSum) -> Option { 502 | use PartialSum::*; 503 | 504 | match (self, other) { 505 | (&Exact(a), &Exact(b)) => Some(a == b), 506 | (&AtLeast(a), &Exact(b)) => { 507 | if b > a {None} 508 | else {Some(false)} 509 | } 510 | (&Exact(a), &AtLeast(b)) => { 511 | if a > b {None} 512 | else {Some(false)} 513 | } 514 | (&AtLeast(_), &AtLeast(_)) => None, 515 | } 516 | } 517 | 518 | /// Improves knowledge using new evidence. 519 | /// Returns `None` if new evidence is conflicting with exiting one. 520 | pub fn improve(&self, new: &PartialSum) -> Option { 521 | use PartialSum::*; 522 | 523 | match (self, new) { 524 | (&Exact(a), &Exact(b)) => { 525 | if a == b {Some(self.clone())} 526 | else {None} 527 | } 528 | (&AtLeast(a), &Exact(b)) => { 529 | if b >= a {Some(new.clone())} 530 | else {None} 531 | } 532 | (&Exact(a), &AtLeast(b)) => { 533 | if a >= b {Some(self.clone())} 534 | else {None} 535 | } 536 | (&AtLeast(a), &AtLeast(b)) => {Some(AtLeast( 537 | if a > b {a} else {b} 538 | ))} 539 | } 540 | } 541 | } 542 | 543 | fn main() { 544 | let x = MagicSquare::new(5); 545 | let settings = SolveSettings::new() 546 | .debug(false) 547 | .sleep_ms(1); 548 | let solver = BackTrackSolver::new(x, settings); 549 | let answer = solver.solve(|s| s.find_max_partial_sum_empty(), |s, p| s.possible(p)); 550 | if let Some(answer) = answer { 551 | answer.puzzle.print(); 552 | println!("Iterations: {}", answer.iterations); 553 | } else { 554 | println!("Found no solution"); 555 | } 556 | } 557 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![doc = include_str!("../README.md")] 2 | 3 | #![deny(missing_docs)] 4 | 5 | extern crate fnv; 6 | 7 | use std::fmt::Debug; 8 | 9 | /// Implemented by puzzles. 10 | /// 11 | /// A puzzle stores the state of the problem, and can be modified by inserting a value at a 12 | /// position within the puzzle. The solver does not understand the internal structure of the 13 | /// puzzle, but is still able to find a solution (if any exists). 14 | /// 15 | /// The initial state does not have to empty, and you can get the difference at the end 16 | /// by setting `SolveSettings::difference(true)`. 17 | pub trait Puzzle: Clone { 18 | /// The type of position. 19 | type Pos: Copy + Debug; 20 | /// The type of values stored in the puzzle. 21 | type Val: Copy + Debug + PartialEq; 22 | /// Solve simple stuff faster. 23 | /// This will reduce the number of steps in solution. 24 | /// If you do not know how to solve this, leave it empty. 25 | /// 26 | /// Call the closure when making a simple choice. 27 | fn solve_simple(&mut self, _f: F) {} 28 | /// Sets a value at position. 29 | fn set(&mut self, pos: Self::Pos, val: Self::Val); 30 | /// Gets value at position. 31 | fn get(&self, pos: Self::Pos) -> Self::Val; 32 | /// Print puzzle out to standard output. 33 | fn print(&self); 34 | /// Whether puzzle is solved. 35 | fn is_solved(&self) -> bool; 36 | /// Removes values from other puzzle to show changes. 37 | fn remove(&mut self, other: &Self); 38 | } 39 | 40 | /// Stores settings for solver. 41 | /// 42 | /// Default settings: 43 | /// 44 | /// - solve_simple: `true` 45 | /// - debug: `false` 46 | /// - difference: `false` 47 | /// - sleep_ms: `None` 48 | pub struct SolveSettings { 49 | /// Whether to solve simple steps. 50 | pub solve_simple: bool, 51 | /// Whether to output debug prints. 52 | pub debug: bool, 53 | /// Show difference from original puzzle. 54 | pub difference: bool, 55 | /// The number of milliseconds to sleep before each debug print. 56 | pub sleep_ms: Option, 57 | /// The number of maximum iterations. 58 | pub max_iterations: Option, 59 | /// Whether to print every million iteration. 60 | pub print_millions: bool, 61 | } 62 | 63 | impl SolveSettings { 64 | /// Creates new solve settings. 65 | pub fn new() -> SolveSettings { 66 | SolveSettings { 67 | solve_simple: true, 68 | debug: false, 69 | difference: false, 70 | sleep_ms: None, 71 | max_iterations: None, 72 | print_millions: false, 73 | } 74 | } 75 | 76 | /// Sets wheter to solve simple moves between each step. 77 | pub fn set_solve_simple(&mut self, val: bool) { 78 | self.solve_simple = val; 79 | } 80 | 81 | /// Whether to solve simple moves between each step. 82 | pub fn solve_simple(mut self, val: bool) -> Self { 83 | self.set_solve_simple(val); 84 | self 85 | } 86 | 87 | /// Sets whether to debug by printing out to standard output. 88 | pub fn set_debug(&mut self, val: bool) { 89 | self.debug = val; 90 | } 91 | 92 | /// Whether to debug by printing out to standard output. 93 | pub fn debug(mut self, val: bool) -> Self { 94 | self.set_debug(val); 95 | self 96 | } 97 | 98 | /// Sets whether to return the difference from initial puzzle. 99 | pub fn set_difference(&mut self, val: bool) { 100 | self.difference = val; 101 | } 102 | 103 | /// Whether to return the difference from initial puzzle. 104 | pub fn difference(mut self, val: bool) -> Self { 105 | self.set_difference(val); 106 | self 107 | } 108 | 109 | /// Sets how many milliseconds to sleep between each step, if any. 110 | pub fn set_maybe_sleep_ms(&mut self, val: Option) { 111 | self.sleep_ms = val; 112 | } 113 | 114 | /// Sets how many milliseconds to sleep between each step, if any. 115 | pub fn maybe_sleep_ms(mut self, val: Option) -> Self { 116 | self.set_maybe_sleep_ms(val); 117 | self 118 | } 119 | 120 | /// Sets how many milliseconds to sleep between each step. 121 | pub fn set_sleep_ms(&mut self, val: u64) { 122 | self.sleep_ms = Some(val); 123 | } 124 | 125 | /// How many milliseconds to sleep between each step. 126 | pub fn sleep_ms(mut self, val: u64) -> Self { 127 | self.set_sleep_ms(val); 128 | self 129 | } 130 | 131 | /// Sets the maximum number of iterations before giving up. 132 | pub fn set_maybe_max_iterations(&mut self, val: Option) { 133 | self.max_iterations = val; 134 | } 135 | 136 | /// The maximum number of iterations before giving up. 137 | pub fn maybe_max_iterations(mut self, val: Option) -> Self { 138 | self.set_maybe_max_iterations(val); 139 | self 140 | } 141 | 142 | /// Sets the maximum number of iterations before giving up. 143 | pub fn set_max_iterations(&mut self, val: u64) { 144 | self.max_iterations = Some(val); 145 | } 146 | 147 | /// The maximum number of iterations before giving up. 148 | pub fn max_iterations(mut self, val: u64) -> Self { 149 | self.set_max_iterations(val); 150 | self 151 | } 152 | 153 | /// Sets printing of every million iteration to standard error output. 154 | pub fn set_print_millions(&mut self, val: bool) { 155 | self.print_millions = val; 156 | } 157 | 158 | /// Prints every million iteration to standard error output. 159 | pub fn print_millions(mut self, val: bool) -> Self { 160 | self.set_print_millions(val); 161 | self 162 | } 163 | } 164 | 165 | /// Contains solution. 166 | pub struct Solution { 167 | /// The solved puzzle. 168 | pub puzzle: T, 169 | /// The number of iterations used to solve the puzzle. 170 | pub iterations: u64, 171 | /// The strategy that found the solution. 172 | pub strategy: Option, 173 | } 174 | 175 | /// Solves puzzles using back tracking. 176 | pub struct BackTrackSolver 177 | where T: Puzzle 178 | { 179 | /// Stores the original state. 180 | pub original: T, 181 | /// Stores the state. 182 | pub state: T, 183 | /// Stores the previous values of a position before making a choice. 184 | /// If the flag is true, the value was inserted due to a simple choice. 185 | pub prevs: Vec<(T::Pos, T::Val, bool)>, 186 | /// Stores the choices for the states. 187 | pub choice: Vec<(T::Pos, Vec)>, 188 | /// Stores solve settings. 189 | pub settings: SolveSettings, 190 | } 191 | 192 | impl BackTrackSolver 193 | where T: Puzzle 194 | { 195 | /// Creates a new solver. 196 | pub fn new(puzzle: T, settings: SolveSettings) -> BackTrackSolver { 197 | BackTrackSolver { 198 | original: puzzle.clone(), 199 | state: puzzle, 200 | prevs: vec![], 201 | choice: vec![], 202 | settings: settings, 203 | } 204 | } 205 | 206 | /// Solves puzzle, using a closure to look for best position to set a value next, 207 | /// and a closure for picking options in preferred order. 208 | /// 209 | /// The second closure returns possible values at a given position. 210 | /// The last move in the list has highest priority, because the solver pops the values in turn. 211 | pub fn solve(mut self, mut f: F, mut g: G) -> Option> 212 | where F: FnMut(&T) -> Option, 213 | G: FnMut(&T, T::Pos) -> Vec 214 | { 215 | use std::thread::sleep; 216 | use std::time::Duration; 217 | 218 | let mut iterations: u64 = 0; 219 | loop { 220 | if self.settings.debug { 221 | if let Some(ms) = self.settings.sleep_ms { 222 | sleep(Duration::from_millis(ms)); 223 | } 224 | } 225 | if self.settings.solve_simple { 226 | let ref mut prevs = self.prevs; 227 | self.state.solve_simple(|state, pos, val| { 228 | prevs.push((pos, state.get(pos), true)); 229 | state.set(pos, val); 230 | }); 231 | } 232 | if self.settings.debug { 233 | self.state.print(); 234 | } 235 | iterations += 1; 236 | if let Some(max_iterations) = self.settings.max_iterations { 237 | if iterations > max_iterations { 238 | return None; 239 | } 240 | } 241 | if self.state.is_solved() { 242 | if self.settings.debug { 243 | eprintln!("Solved! Iterations: {}", iterations); 244 | } 245 | if self.settings.difference { 246 | self.state.remove(&self.original); 247 | } 248 | return Some(Solution { puzzle: self.state, iterations: iterations, strategy: None }); 249 | } 250 | 251 | let empty = f(&self.state); 252 | let mut possible = match empty { 253 | None => vec![], 254 | Some(x) => g(&self.state, x) 255 | }; 256 | if possible.len() == 0 { 257 | loop { 258 | if self.choice.len() == 0 { 259 | if self.settings.debug { 260 | // No more possible choices. 261 | eprintln!("No more possible choices"); 262 | } 263 | return None; 264 | } 265 | let (pos, mut possible) = self.choice.pop().unwrap(); 266 | if let Some(new_val) = possible.pop() { 267 | // Try next choice. 268 | while let Some((old_pos, old_val, simple)) = self.prevs.pop() { 269 | self.state.set(old_pos, old_val); 270 | if !simple {break} 271 | } 272 | self.prevs.push((pos, self.state.get(pos), false)); 273 | self.state.set(pos, new_val); 274 | self.choice.push((pos, possible)); 275 | if self.settings.debug { 276 | eprintln!("Try {:?}, {:?} depth ch: {} prev: {} (failed at {:?}) it: {}", 277 | pos, new_val, self.choice.len(), self.prevs.len(), empty, iterations); 278 | } else if self.settings.print_millions && (iterations % 1_000_000 == 0) { 279 | eprintln!("Iteration: {}mill", iterations / 1_000_000); 280 | } 281 | break; 282 | } else { 283 | let mut undo = false; 284 | while let Some((old_pos, old_val, simple)) = self.prevs.pop() { 285 | self.state.set(old_pos, old_val); 286 | undo = true; 287 | if !simple {break} 288 | } 289 | if !undo { 290 | // No more possible choices. 291 | return None; 292 | } 293 | } 294 | } 295 | } else { 296 | let empty = empty.unwrap(); 297 | // Put in the first guess. 298 | let v = possible.pop().unwrap(); 299 | self.prevs.push((empty, self.state.get(empty), false)); 300 | self.state.set(empty, v); 301 | self.choice.push((empty, possible)); 302 | if self.settings.debug { 303 | eprintln!("Guess {:?}, {:?} depth ch: {} prev: {} it: {}", 304 | empty, v, self.choice.len(), self.prevs.len(), iterations); 305 | } else if self.settings.print_millions && (iterations % 1_000_000 == 0) { 306 | eprintln!("Iteration: {}mill", iterations / 1_000_000); 307 | } 308 | } 309 | } 310 | } 311 | } 312 | 313 | /// Solves puzzle using multiple strategies at the same time. 314 | /// Each strategy is evaluated one step by turn until a solution is found. 315 | pub struct MultiBackTrackSolver 316 | where T: Puzzle 317 | { 318 | /// Stores the states. 319 | pub states: Vec, 320 | /// Stores previous values before making choices. 321 | /// The flags is true when made a simple choice. 322 | pub prevs: Vec>, 323 | /// Stores the choices for the states. 324 | pub choice: Vec)>>, 325 | /// Stores solve settings. 326 | pub settings: SolveSettings, 327 | } 328 | 329 | impl MultiBackTrackSolver 330 | where T: Puzzle 331 | { 332 | /// Creates a new solver. 333 | pub fn new(settings: SolveSettings) -> MultiBackTrackSolver { 334 | MultiBackTrackSolver { 335 | states: vec![], 336 | prevs: vec![], 337 | choice: vec![], 338 | settings: settings, 339 | } 340 | } 341 | 342 | /// Solves puzzle, using a closure to look for best position to set a value next, 343 | /// and a closure for picking options in preferred order. 344 | /// 345 | /// The second closure returns possible values at a given position. 346 | /// The last move in the list has highest priority, because the solver pops the values in turn. 347 | /// 348 | /// If you have problems compiling, annotate type `(fn(&_) -> _, fn(&_, _) -> _)` to 349 | /// the list of strategies, e.g. `Vec<(fn(&_) -> _, fn(&_, _) -> _)>` or 350 | /// `&[(fn(&_) -> _, fn(&_, _) -> _)]`. 351 | pub fn solve( 352 | mut self, 353 | puzzle: T, 354 | strategies: &[(fn(&T) -> Option, fn(&T, T::Pos) -> Vec)] 355 | ) -> Option> { 356 | use std::thread::sleep; 357 | use std::time::Duration; 358 | 359 | let origin = puzzle.clone(); 360 | self.states = vec![puzzle; strategies.len()]; 361 | self.prevs = vec![vec![]; strategies.len()]; 362 | self.choice = vec![vec![]; strategies.len()]; 363 | let mut iterations: u64 = 0; 364 | loop { 365 | if self.settings.debug { 366 | if let Some(ms) = self.settings.sleep_ms { 367 | sleep(Duration::from_millis(ms)); 368 | } 369 | } 370 | 371 | iterations += 1; 372 | if let Some(max_iterations) = self.settings.max_iterations { 373 | if iterations > max_iterations { 374 | return None; 375 | } 376 | } 377 | 378 | for i in 0..strategies.len() { 379 | let ref mut state = self.states[i]; 380 | let ref mut prevs = self.prevs[i]; 381 | let ref mut choice = self.choice[i]; 382 | let (f, g) = strategies[i]; 383 | 384 | if self.settings.solve_simple { 385 | state.solve_simple(|state, pos, val| { 386 | prevs.push((pos, state.get(pos), true)); 387 | state.set(pos, val) 388 | }); 389 | } 390 | if self.settings.debug { 391 | println!("Strategy {}", i); 392 | state.print(); 393 | } 394 | if state.is_solved() { 395 | if self.settings.debug { 396 | println!("Solved! Iterations: {}", iterations); 397 | } 398 | if self.settings.difference { 399 | state.remove(&origin); 400 | } 401 | return Some(Solution { puzzle: state.clone(), iterations: iterations, strategy: Some(i) }); 402 | } 403 | 404 | let empty = f(&state); 405 | let mut possible = match empty { 406 | None => vec![], 407 | Some(x) => g(&state, x) 408 | }; 409 | if possible.len() == 0 { 410 | // println!("No possible at {:?}", empty); 411 | loop { 412 | if choice.len() == 0 { 413 | if self.settings.debug { 414 | // No more possible choices. 415 | println!("No more possible choices"); 416 | } 417 | return None; 418 | } 419 | let (pos, mut possible) = choice.pop().unwrap(); 420 | if let Some(new_val) = possible.pop() { 421 | // Try next choice. 422 | while let Some((old_pos, old_val, simple)) = prevs.pop() { 423 | state.set(old_pos, old_val); 424 | if !simple {break} 425 | } 426 | prevs.push((pos, state.get(pos), false)); 427 | state.set(pos, new_val); 428 | choice.push((pos, possible)); 429 | if self.settings.debug { 430 | eprintln!("Try {:?}, {:?} depth ch: {} prev: {} (failed at {:?}) it: {}", 431 | pos, new_val, self.choice.len(), self.prevs.len(), empty, iterations); 432 | } else if self.settings.print_millions && (iterations % 1_000_000 == 0) { 433 | eprintln!("Iteration: {}mill", iterations / 1_000_000); 434 | } 435 | break; 436 | } else { 437 | let mut undo = false; 438 | while let Some((old_pos, old_val, simple)) = prevs.pop() { 439 | state.set(old_pos, old_val); 440 | undo = true; 441 | if !simple {break} 442 | } 443 | if !undo { 444 | // No more possible choices. 445 | return None; 446 | } 447 | } 448 | } 449 | } else { 450 | let empty = empty.unwrap(); 451 | // Put in the first guess. 452 | let v = possible.pop().unwrap(); 453 | prevs.push((empty, state.get(empty), false)); 454 | state.set(empty, v); 455 | choice.push((empty, possible)); 456 | if self.settings.debug { 457 | eprintln!("Guess {:?}, {:?} depth ch: {} prev: {} it: {}", 458 | empty, v, self.choice.len(), self.prevs.len(), iterations); 459 | } else if self.settings.print_millions && (iterations % 1_000_000 == 0) { 460 | eprintln!("Iteration: {}mill", iterations / 1_000_000); 461 | } 462 | } 463 | } 464 | } 465 | } 466 | } 467 | 468 | /// Combines multiple priority lists together. 469 | /// 470 | /// This is used to combine strategies into a new one. 471 | /// Sometimes this is better than using either strategy. 472 | pub fn combine(lists: Vec>) -> Vec 473 | where T: Clone + ::std::hash::Hash + Eq 474 | { 475 | let mut priority: fnv::FnvHashMap = fnv::FnvHashMap::default(); 476 | for list in &lists { 477 | for (i, ch) in list.iter().enumerate() { 478 | if priority.contains_key(ch) { 479 | let old = priority[ch]; 480 | priority.insert(ch.clone(), old + i); 481 | } else { 482 | priority.insert(ch.clone(), i); 483 | } 484 | } 485 | } 486 | 487 | let keys: Vec<&T> = priority.keys().collect(); 488 | let mut inds: Vec = (0..keys.len()).collect(); 489 | inds.sort_by_key(|&ind| priority[keys[ind]]); 490 | let mut res = Vec::with_capacity(keys.len()); 491 | for &ind in &inds { 492 | res.push(keys[ind].clone()); 493 | } 494 | res 495 | } 496 | 497 | /// Stores settings for entropy solver. 498 | pub struct EntropySolveSettings { 499 | /// The number of solve attempts. 500 | pub attempts: u64, 501 | /// Whether to sample randomly (1) or converge (0). 502 | pub noise: f64, 503 | /// Make one final attempt with maximum iterations setting. 504 | pub final_attempt: Option>, 505 | } 506 | 507 | impl EntropySolveSettings { 508 | /// Creates new entropy settings. 509 | pub fn new() -> EntropySolveSettings { 510 | EntropySolveSettings { 511 | attempts: 1, 512 | noise: 0.0, 513 | final_attempt: None, 514 | } 515 | } 516 | 517 | /// Sets number of attempts. 518 | pub fn set_attempts(&mut self, val: u64) { 519 | self.attempts = val; 520 | } 521 | 522 | /// The number of attempts. 523 | pub fn attempts(mut self, val: u64) -> Self { 524 | self.set_attempts(val); 525 | self 526 | } 527 | 528 | /// Sets the noise (0 = converge, 1 = random sampling). 529 | pub fn set_noise(&mut self, val: f64) { 530 | self.noise = val; 531 | } 532 | 533 | /// The noise (0 = converge, 1 = random sampling). 534 | pub fn noise(mut self, val: f64) -> Self { 535 | self.set_noise(val); 536 | self 537 | } 538 | 539 | /// Sets one final attempt with maximum iterations setting. 540 | pub fn set_final_attempt(&mut self, val: Option>) { 541 | self.final_attempt = val; 542 | } 543 | 544 | /// The final attempt with maximum iterations setting. 545 | pub fn final_attempt(mut self, val: Option>) -> Self { 546 | self.set_final_attempt(val); 547 | self 548 | } 549 | } 550 | 551 | /// Solves puzzles using minimum entropy search. 552 | /// 553 | /// This solver learns from repeatedly attempting to solve the puzzle. 554 | /// The algorithm is inspired by [WaveFunctionCollapse](https://github.com/mxgmn/WaveFunctionCollapse). 555 | /// 556 | /// This solver is general and guaranteed to find a solution, if any. 557 | /// It also uses custom priority of choices in the initial attempts. 558 | /// 559 | /// The search works by attempting normal backtrack solving, 560 | /// but increasing weights to choices each time they are made. 561 | /// When the algorithm is stuck, it minimizes entropy of common choices. 562 | /// At later attempts, the algorithm will try these common choices first. 563 | /// 564 | /// When `EntropySettings::noise` is non-zero, the choices will occationally be shuffled. 565 | /// For more information, see `EntropySolveSettings`. 566 | pub struct EntropyBackTrackSolver where T: Puzzle { 567 | /// Stores the original state. 568 | pub original: T, 569 | /// Stores the state. 570 | pub state: T, 571 | /// Stores the previous values of a position before making a choice. 572 | /// If the flag is true, the value was inserted due to a simple choice. 573 | pub prevs: Vec<(T::Pos, T::Val, bool)>, 574 | /// Stores the choices for the states. 575 | pub choice: Vec<(T::Pos, Vec)>, 576 | /// The initial choices. 577 | pub start_choice: Vec<(T::Pos, Vec)>, 578 | /// Stores weights of choices. 579 | pub weights: Vec>, 580 | /// Stores solve settings. 581 | pub settings: SolveSettings, 582 | /// Stores entropy solve settings. 583 | pub entropy_settings: EntropySolveSettings, 584 | } 585 | 586 | impl EntropyBackTrackSolver where T: Puzzle { 587 | /// Creates a new collapse solver. 588 | pub fn new( 589 | puzzle: T, 590 | start_choice: Vec<(T::Pos, Vec)>, 591 | entropy_settings: EntropySolveSettings, 592 | settings: SolveSettings 593 | ) -> Self { 594 | let weights = start_choice.iter().map(|n| vec![1.0; n.1.len()]).collect(); 595 | EntropyBackTrackSolver { 596 | original: puzzle.clone(), 597 | prevs: vec![], 598 | state: puzzle, 599 | choice: vec![], 600 | start_choice, 601 | weights, 602 | entropy_settings, 603 | settings, 604 | } 605 | } 606 | 607 | /// Calculates the entropy of a choice. 608 | pub fn entropy(&self, i: usize) -> f64 { 609 | let sum: f64 = self.weights[i].iter().sum(); 610 | self.weights[i].iter().map(|&w| { 611 | let p: f64 = w / sum; 612 | -(p * p.ln()) 613 | }).sum() 614 | } 615 | 616 | /// Finds the position with least entropy. 617 | pub fn min_entropy(&self, g: &mut G) -> Option<(usize, T::Pos)> 618 | where G: FnMut(&T, T::Pos) -> Vec 619 | { 620 | let mut min: Option<(usize, f64)> = None; 621 | for i in 0..self.weights.len() { 622 | if self.weights.len() == 0 {continue}; 623 | if g(&self.state, self.start_choice[i].0).len() == 0 {continue}; 624 | let e = self.entropy(i); 625 | if min.is_none() || min.unwrap().1 > e { 626 | min = Some((i, e)); 627 | } 628 | } 629 | min.map(|(i, _)| (i, self.start_choice[i].0)) 630 | } 631 | 632 | /// Increase weight of observed state. 633 | pub fn observe(&mut self, pos: T::Pos, new_val: T::Val) 634 | where T::Pos: PartialEq, 635 | { 636 | for (i, ch) in self.start_choice.iter().enumerate() { 637 | if ch.0 == pos { 638 | for (j, val) in self.start_choice[i].1.iter().enumerate() { 639 | if *val == new_val { 640 | self.weights[i][j] += 1.0; 641 | return; 642 | } 643 | } 644 | } 645 | } 646 | } 647 | 648 | /// Attempts to solve puzzle repeatedly, using `SolveSettings::max_iterations`. 649 | /// 650 | /// The solver learns by reusing weights from previous attempts. 651 | pub fn solve(&mut self, g: G) -> (u64, Option>) 652 | where G: Copy + FnMut(&T, T::Pos) -> Vec, 653 | T::Pos: PartialEq 654 | { 655 | let mut solution = None; 656 | let mut i = 0; 657 | if self.settings.max_iterations.is_some() { 658 | loop { 659 | if i >= self.entropy_settings.attempts {break}; 660 | 661 | if solution.is_none() { 662 | solution = self.solve_single_attempt(g); 663 | } else { 664 | break; 665 | } 666 | 667 | i += 1; 668 | } 669 | } 670 | if solution.is_none() { 671 | if let Some(new_max_iter) = self.entropy_settings.final_attempt { 672 | let max_iter = self.settings.max_iterations; 673 | let noise = self.entropy_settings.noise; 674 | self.entropy_settings.noise = 0.0; 675 | self.settings.max_iterations = new_max_iter; 676 | solution = self.solve_single_attempt(g); 677 | // Reset old settings. 678 | self.settings.max_iterations = max_iter; 679 | self.entropy_settings.noise = noise; 680 | } 681 | } 682 | (i, solution) 683 | } 684 | 685 | /// Solves puzzle, using a closure for picking options in preferred order. 686 | /// 687 | /// This can be called repeated times, limited by `SolveSettings::max_iterations` 688 | /// to reuse weights from previous attempts. 689 | pub fn solve_single_attempt(&mut self, mut g: G) -> Option> 690 | where G: FnMut(&T, T::Pos) -> Vec, 691 | T::Pos: PartialEq 692 | { 693 | use std::thread::sleep; 694 | use std::time::Duration; 695 | 696 | let mut rng = rand::thread_rng(); 697 | let mut iterations: u64 = 0; 698 | loop { 699 | if self.settings.debug { 700 | if let Some(ms) = self.settings.sleep_ms { 701 | sleep(Duration::from_millis(ms)); 702 | } 703 | } 704 | if self.settings.solve_simple { 705 | let ref mut prevs = self.prevs; 706 | self.state.solve_simple(|state, pos, val| { 707 | prevs.push((pos, state.get(pos), true)); 708 | state.set(pos, val); 709 | }); 710 | } 711 | if self.settings.debug { 712 | self.state.print(); 713 | } 714 | iterations += 1; 715 | if let Some(max_iterations) = self.settings.max_iterations { 716 | if iterations > max_iterations { 717 | return None; 718 | } 719 | } 720 | if self.state.is_solved() { 721 | if self.settings.debug { 722 | eprintln!("Solved! Iterations: {}", iterations); 723 | } 724 | if self.settings.difference { 725 | self.state.remove(&self.original); 726 | } 727 | return Some(Solution { puzzle: self.state.clone(), iterations: iterations, strategy: None }); 728 | } 729 | 730 | let empty = self.min_entropy(&mut g); 731 | let mut possible = match empty { 732 | None => vec![], 733 | Some((ind, x)) => { 734 | use rand::Rng; 735 | 736 | let mut possible = g(&self.state, x); 737 | if rng.gen::() < self.entropy_settings.noise { 738 | use rand::seq::SliceRandom; 739 | possible.shuffle(&mut rng); 740 | possible 741 | } else { 742 | let mut keys = vec![]; 743 | for (j, p) in possible.iter().enumerate() { 744 | for i in 0..self.start_choice[ind].1.len() { 745 | if self.start_choice[ind].1[i] == *p { 746 | keys.push((j, self.weights[ind][i])); 747 | break; 748 | } 749 | } 750 | } 751 | keys.sort_by(|&(_, a), &(_, b)| a.partial_cmp(&b).unwrap()); 752 | let new_possible = keys.iter().map(|&(i, _)| possible[i]).collect::>(); 753 | new_possible 754 | } 755 | } 756 | }; 757 | if possible.len() == 0 { 758 | loop { 759 | if self.choice.len() == 0 { 760 | if self.settings.debug { 761 | // No more possible choices. 762 | eprintln!("No more possible choices"); 763 | } 764 | return None; 765 | } 766 | let (pos, mut possible) = self.choice.pop().unwrap(); 767 | if let Some(new_val) = possible.pop() { 768 | // Try next choice. 769 | while let Some((old_pos, old_val, simple)) = self.prevs.pop() { 770 | self.state.set(old_pos, old_val); 771 | if !simple {break} 772 | } 773 | self.prevs.push((pos, self.state.get(pos), false)); 774 | self.state.set(pos, new_val); 775 | self.observe(pos, new_val); 776 | self.choice.push((pos, possible)); 777 | if self.settings.debug { 778 | eprintln!("Try {:?}, {:?} depth ch: {} prev: {} (failed at {:?}) it: {}", 779 | pos, new_val, self.choice.len(), self.prevs.len(), empty, iterations); 780 | } else if self.settings.print_millions && (iterations % 1_000_000 == 0) { 781 | eprintln!("Iteration: {}mill", iterations / 1_000_000); 782 | } 783 | break; 784 | } else { 785 | let mut undo = false; 786 | while let Some((old_pos, old_val, simple)) = self.prevs.pop() { 787 | self.state.set(old_pos, old_val); 788 | undo = true; 789 | if !simple {break} 790 | } 791 | if !undo { 792 | // No more possible choices. 793 | return None; 794 | } 795 | } 796 | } 797 | } else { 798 | let empty = empty.unwrap().1; 799 | // Put in the first guess. 800 | let v = possible.pop().unwrap(); 801 | self.prevs.push((empty, self.state.get(empty), false)); 802 | self.state.set(empty, v); 803 | self.observe(empty, v); 804 | self.choice.push((empty, possible)); 805 | if self.settings.debug { 806 | eprintln!("Guess {:?}, {:?} depth ch: {} prev: {} it: {}", 807 | empty, v, self.choice.len(), self.prevs.len(), iterations); 808 | } else if self.settings.print_millions && (iterations % 1_000_000 == 0) { 809 | eprintln!("Iteration: {}mill", iterations / 1_000_000); 810 | } 811 | } 812 | } 813 | } 814 | } 815 | --------------------------------------------------------------------------------