1use rand::Rng;
2
3pub const N: usize = 9;
4pub const SRN: usize = 3;
5
6#[derive(Clone, Copy)]
7pub struct Cell {
8 pub num: u8,
9 pub locked: bool,
10}
11type Grid = [[Cell; N]; N];
12
13pub struct SudokuBoard {
14 pub cells: Grid,
15}
16
17impl SudokuBoard {
18 pub fn new() -> Self {
20 Self {
21 cells: [[Cell {
22 num: 0,
23 locked: true,
24 }; N]; N],
25 }
26 }
27
28 pub fn fill(&mut self) {
30 self.fill_diagonal();
31 self.fill_remaining(0, SRN);
32 }
33
34 fn fill_diagonal(&mut self) {
35 for i in 0..SRN {
36 self.fill_box(i * SRN, i * SRN);
37 }
38 }
39
40 pub fn unused_in_box(grid: Grid, row_start: usize, col_start: usize, num: u8) -> bool {
42 for i in 0..SRN {
43 for j in 0..SRN {
44 if grid[row_start + i][col_start + j].num == num {
45 return false;
46 }
47 }
48 }
49 return true;
50 }
51
52 fn fill_box(&mut self, row: usize, col: usize) {
53 let mut rng = rand::thread_rng();
54 let mut num: Option<u8> = None;
55 for i in 0..SRN {
56 for j in 0..SRN {
57 while num == None || !Self::unused_in_box(self.cells, row, col, num.unwrap()) {
58 num = Some(rng.gen_range(0..=N as u8));
59 }
60 self.cells[row + i][col + j].num = num.unwrap();
61 }
62 }
63 }
64
65 pub fn check_if_safe(grid: Grid, i: usize, j: usize, num: u8) -> bool {
67 num == 0
68 || (Self::unused_in_row(grid, i, num)
69 && Self::unused_in_col(grid, j, num)
70 && Self::unused_in_box(grid, i - i % SRN, j - j % SRN, num))
71 }
72
73 pub fn unused_in_row(grid: Grid, i: usize, num: u8) -> bool {
74 for j in 0..N {
75 if grid[i][j].num == num {
76 return false;
77 }
78 }
79 return true;
80 }
81
82 pub fn unused_in_col(grid: Grid, j: usize, num: u8) -> bool {
83 for i in 0..N {
84 if grid[i][j].num == num {
85 return false;
86 }
87 }
88 return true;
89 }
90
91 pub fn fill_remaining(&mut self, mut i: usize, mut j: usize) -> bool {
94 if j >= N && i < N - 1 {
95 i += 1;
96 j = 0;
97 }
98 if i >= N && j >= N {
99 return true;
100 }
101 if i < SRN {
102 if j < SRN {
103 j = SRN;
104 }
105 } else if i < N - SRN {
106 if j == i / SRN * SRN {
107 j += SRN;
108 }
109 } else {
110 if j == N - SRN {
111 i += 1;
112 j = 0;
113 if i >= N {
114 return true;
115 }
116 }
117 }
118
119 for num in 1..=N as u8 {
120 if Self::check_if_safe(self.cells, i, j, num) {
121 self.cells[i][j].num = num;
122 self.cells[i][j].locked = true;
123 if self.fill_remaining(i, j + 1) {
124 return true;
125 }
126 self.cells[i][j].num = 0;
127 self.cells[i][j].locked = false;
128 }
129 }
130
131 false
132 }
133
134 pub fn solve(mut grid: Grid, mut counter: u32) -> u32 {
136 let mut row = 0;
137 let mut col = 0;
138 for i in 0..81 {
139 row = i / N;
140 col = i % N;
141 if grid[row][col].num == 0 {
142 for num in 1..10 {
143 if Self::check_if_safe(grid, row, col, num) {
147 grid[row][col].num = num;
152 grid[row][col].locked = true;
153 if Self::check_filled(grid) {
154 counter += 1;
155 break;
156 } else {
157 return Self::solve(grid, counter);
160 }
161 }
162 }
166 break;
167 }
168 }
169 grid[row][col].num = 0;
170 grid[row][col].locked = false;
171 return counter;
172 }
173
174 pub fn check_valid(mut grid: Grid) -> bool {
176 for i in 0..N {
177 for j in 0..N {
178 let original = grid[i][j].num;
179 grid[i][j].num = 0;
180 if !Self::check_if_safe(grid, i, j, original) {
181 return false;
182 }
183 grid[i][j].num = original;
184 }
185 }
186 true
187 }
188
189 pub fn check_solved(grid: Grid) -> bool {
191 Self::check_filled(grid) && Self::check_valid(grid)
192 }
193
194 pub fn check_filled(grid: Grid) -> bool {
196 for row in 0..N {
197 for col in 0..N {
198 if grid[row][col].num == 0 {
199 return false;
200 }
201 }
202 }
203
204 true
205 }
206
207 pub fn remove_cells(&mut self, mut attempts: u32) {
209 let mut rng = rand::thread_rng();
210
211 while attempts > 0 {
212 let mut row = rng.gen_range(0..N);
214 let mut col = rng.gen_range(0..N);
215 while self.cells[row][col].num == 0 {
216 row = rng.gen_range(0..N);
217 col = rng.gen_range(0..N);
218 }
219
220 let backup = self.cells[row][col].clone();
222 self.cells[row][col].num = 0;
223 self.cells[row][col].locked = false;
224
225 let copy_grid = self.cells.clone();
227
228 let counter = Self::solve(copy_grid, 0);
229 if counter != 1 {
232 self.cells[row][col] = backup;
233 attempts -= 1;
235 }
236 }
237 }
238
239 pub fn display(&self) {
241 Self::display_grid(&self.cells);
242 }
243
244 pub fn display_grid(grid: &Grid) {
246 println!(
247 "{}",
248 grid.map(|a| {
249 a.map(|a| match a.num {
250 0 => " ".to_string(),
251 _ => a.num.to_string(),
252 })
253 .join(" ")
254 })
255 .join("\n")
256 );
257 }
258}
259
260#[cfg(test)]
261mod tests {
262 use crate::{SudokuBoard, N};
263
264 #[test]
265 fn check_solved() {
266 let mut board = SudokuBoard::new();
267 board.fill();
268 assert!(SudokuBoard::check_solved(board.cells));
269
270 board.cells[0][0].num = N as u8 - board.cells[0][0].num;
271 assert!(!SudokuBoard::check_solved(board.cells));
272
273 board.cells[0][0].num = 0;
274 assert!(!SudokuBoard::check_solved(board.cells));
275 assert!(SudokuBoard::check_valid(board.cells));
276 }
277}