-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathsolver.rs
185 lines (153 loc) · 5.23 KB
/
solver.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
use std::cmp::Ordering;
#[derive(Clone, Default)]
pub struct Square {
pub value: String,
pub show_text: bool,
pub solved_cell: bool,
pub focus: bool,
}
pub type SGrid = [[Square; 9]; 9];
pub fn verify_grid(grid: &SGrid) -> bool {
let mut row: u128 = 0;
let mut col: u128 = 0;
let mut boxes: u128 = 0;
let mut cells = 0;
for (i, srow) in grid.iter().enumerate() {
for (j, cell) in srow.iter().enumerate() {
if cell.value.is_empty() {
continue;
}
cells += 1;
let key = cell.value.chars().next().unwrap() as usize - '1' as usize;
let key_row = 1 << (i * 9 + key);
let key_col = 1 << (j * 9 + key);
// i / 3 is integer division
// We get the starting row index of the box (i / 3 * 3)
// Then we get the starting column (j / 3)
let key_boxes = 1 << ((i / 3 * 3 + j / 3) * 9 + key);
// Check if corresponding bits are already set
if row & key_row | col & key_col | boxes & key_boxes != 0 {
return false;
}
// Set the corresponding bits
row |= key_row;
col |= key_col;
boxes |= key_boxes;
}
}
// The smallest amount of Sudoku "hints" is 17
//https://phys.org/news/2012-01-mathematicians-minimum-sudoku-solution-problem.html
cells >= 17
}
pub enum SolveResult {
Unique,
NotUnique,
Invalid,
}
pub fn solve_grid(grid: &mut SGrid) -> SolveResult {
// These are the bit fields that keep track of the numbers placed in each row, column, and box of the grid
let mut row: u128 = 0;
let mut col: u128 = 0;
let mut boxes: u128 = 0;
for (r, srow) in grid.iter().enumerate() {
for (c, cell) in srow.iter().enumerate() {
if !cell.value.is_empty() {
// Calculated by left-shifting 1 by a value between 0 and 8, depending on the digit in the cell
let key = 1 << (cell.value.chars().next().unwrap() as usize - '1' as usize);
// The key value is then used to update the corresponding bit in the bit fields
row |= key << (r * 9);
col |= key << (c * 9);
boxes |= key << ((r / 3 * 3 + c / 3) * 9);
}
}
}
let mut count = 0;
let old_grid = grid.clone();
// We keep a solved_grid because we make sure that there is not a 2nd solution to the puzzle
// If another solution doesn't exits then we set the grid equal to the solved_grid
let mut solved_grid: SGrid = SGrid::default();
// Call the solving method recursively
solve(
&mut solved_grid,
grid,
&mut row,
&mut col,
&mut boxes,
0,
&mut count,
);
match count.cmp(&1) {
Ordering::Equal => {
*grid = solved_grid;
SolveResult::Unique
}
Ordering::Greater => {
*grid = old_grid;
SolveResult::NotUnique
}
Ordering::Less => {
*grid = old_grid;
SolveResult::Invalid
}
}
}
fn solve(
solved_grid: &mut SGrid,
grid: &mut SGrid,
row: &mut u128,
col: &mut u128,
boxes: &mut u128,
i: usize,
count: &mut i32,
) -> bool {
// If there is multiple solutions then automatically return true
if *count > 1 {
return true;
}
// If reached the end
if i == 81 {
// We need to save the grid in the case that we do not find another solution to the puzzle
if *count == 0 {
*solved_grid = grid.clone();
}
*count += 1;
return false;
}
// Get the index of the row and column
let (r, c) = (i / 9, i % 9);
// If the cell is not empty then move to the next cell
if !grid[r][c].value.is_empty() {
return solve(solved_grid, grid, row, col, boxes, i + 1, count);
}
// Box index
let b = (r / 3) * 3 + (c / 3);
// This is a bit mask that represents the numbers that are already present
// We shift to the right to align each bits with the corresponding row, column, and box
let mask = (*row >> (r * 9)) | (*col >> (c * 9)) | (*boxes >> (b * 9));
for x in 0..9 {
// Move the bit that 1 has to the xth bit and then check it
// to make sure that the bit has not already been set
let xmask = 1 << x;
if mask & xmask != 0 {
continue;
}
// We update the bit at the current x value using xmask
*row |= xmask << (r * 9);
*col |= xmask << (c * 9);
*boxes |= xmask << (b * 9);
// Since its 0-8 then we do x+1
grid[r][c].value = std::char::from_digit(x + 1, 10).unwrap().to_string();
grid[r][c].solved_cell = true;
// Recursively call itself with the next cell to check if the value works
if solve(solved_grid, grid, row, col, boxes, i + 1, count) {
return true;
}
// If it didnt work then we reset the changes we did to the bit fields
*row ^= xmask << (r * 9);
*col ^= xmask << (c * 9);
*boxes ^= xmask << (b * 9);
grid[r][c].value = String::new();
grid[r][c].solved_cell = false;
}
false
}