soku/solve/
brute_force.rs1use crate::prelude::{Candidates, Coord, Digit, Sudoku, SudokuIndex, HOUSE_INDICES};
2
3use super::Solve;
4
5pub struct BruteForceSolver;
9
10impl BruteForceSolver {
11 pub const fn new() -> Self {
12 Self
13 }
14}
15
16impl Solve for BruteForceSolver {
17 fn solve(self, sudoku: &mut Sudoku) -> bool {
18 let all_candidates = sudoku.all_candidates();
19 Self::solve_inner(sudoku, all_candidates)
20 }
25}
26
27impl BruteForceSolver {
28 fn solve_inner(sudoku: &mut Sudoku, mut all_candidates: Vec<Candidates>) -> bool {
29 if let Some((index, candidates)) = Self::cell_with_least_candidates(sudoku, &all_candidates)
30 {
31 for digit in candidates.digits() {
32 sudoku.set_cell(index, digit);
33
34 Self::recalculate_all_candidates(&mut all_candidates, index, digit);
35
36 if Self::solve_inner(sudoku, all_candidates.clone()) {
37 return true;
38 }
39 }
40
41 sudoku.clear_cell(index);
42
43 false
44 } else {
45 true
46 }
47 }
48
49 fn cell_with_least_candidates(
50 sudoku: &Sudoku,
51 all_candidates: &[Candidates],
52 ) -> Option<(usize, Candidates)> {
53 let mut best_candidates_count = usize::MAX;
54 let mut result = None;
55
56 for (i, _) in sudoku
57 .cells()
58 .enumerate()
59 .filter(|(_, cell)| cell.digit.is_none())
60 {
61 let candidates = all_candidates[i];
63 let candidates_count = candidates.count();
64
65 if candidates_count < best_candidates_count {
66 best_candidates_count = candidates_count;
67 result = Some((i, candidates));
68
69 if best_candidates_count <= 1 {
70 return result;
71 }
72 }
73 }
74
75 result
76 }
77
78 fn recalculate_all_candidates(all_candidates: &mut [Candidates], index: usize, digit: Digit) {
79 let coord @ Coord(row, col) = Coord::from_index(index);
80
81 for r in HOUSE_INDICES {
83 if r != row {
84 let index = Coord(r, col).into_index();
85 all_candidates[index].remove(digit);
86 }
87 }
88
89 for c in HOUSE_INDICES {
91 if c != col {
92 let index = Coord(row, c).into_index();
93 all_candidates[index].remove(digit);
94 }
95 }
96
97 for i in Sudoku::square_indices_of_cell(coord) {
98 if i != index {
99 all_candidates[i].remove(digit);
100 }
101 }
102 }
103}