1use super::board::Board;
2use super::masks::Masks;
3
4#[derive(Debug, Copy, Clone, PartialEq, Eq)]
12pub struct Candidates {
13 cache: [[u16; 9]; 9],
14}
15
16impl Candidates {
17 pub(super) fn new() -> Self {
18 Candidates { cache: [[0; 9]; 9] }
19 }
20
21 #[inline]
23 pub(super) fn get(&self, r: usize, c: usize) -> u16 {
24 self.cache[r][c]
25 }
26
27 pub fn get_candidates(&self, r: usize, c: usize) -> Vec<u8> {
29 let mask = self.get(r, c);
30 let mut candidates = Vec::new();
31 for i in 0..9 {
32 if (mask >> i) & 1 == 1 {
34 candidates.push((i + 1) as u8);
35 }
36 }
37 candidates
38 }
39
40 #[inline]
42 pub(super) fn set(&mut self, r: usize, c: usize, mask: u16) {
43 self.cache[r][c] = mask;
44 }
45
46 pub(super) fn update_affected_cells(
49 &mut self,
50 r: usize,
51 c: usize,
52 masks: &Masks,
53 board: &Board,
54 ) {
55 self.update_affected_cells_for(r, c, masks, board, None);
56 }
57
58 pub(super) fn update_affected_cells_for(
63 &mut self,
64 r: usize,
65 c: usize,
66 masks: &Masks,
67 board: &Board,
68 placed_num: Option<u8>,
69 ) {
70 if board.is_empty(r, c) {
72 self.cache[r][c] = masks.compute_candidates_mask_for_cell(r, c);
74 } else {
75 self.cache[r][c] = 0;
77 }
78
79 let num_bit = placed_num.map(|n| 1u16 << (n - 1));
80
81 for i in 0..9 {
83 if board.is_empty(r, i) && i != c {
84 if let Some(bit) = num_bit
86 && self.cache[r][i] & bit == 0
87 {
88 continue;
89 }
90 self.cache[r][i] = masks.compute_candidates_mask_for_cell(r, i);
91 }
92 if board.is_empty(i, c) && i != r {
93 if let Some(bit) = num_bit
94 && self.cache[i][c] & bit == 0
95 {
96 continue;
97 }
98 self.cache[i][c] = masks.compute_candidates_mask_for_cell(i, c);
99 }
100 }
101
102 let box_idx = Masks::get_box_idx(r, c);
104 let start_row = (box_idx / 3) * 3;
105 let start_col = (box_idx % 3) * 3;
106 for r_offset in 0..3 {
107 for c_offset in 0..3 {
108 let cur_r = start_row + r_offset;
109 let cur_c = start_col + c_offset;
110 if (cur_r == r) || (cur_c == c) {
112 continue;
113 }
114 if board.is_empty(cur_r, cur_c) {
115 if let Some(bit) = num_bit
116 && self.cache[cur_r][cur_c] & bit == 0
117 {
118 continue;
119 }
120 self.cache[cur_r][cur_c] = masks.compute_candidates_mask_for_cell(cur_r, cur_c);
121 }
122 }
123 }
124 }
125}
126
127#[cfg(test)]
128mod tests {
129 use super::*;
130
131 #[test]
132 fn test_get_candidates_empty_mask() {
133 let candidates = Candidates::new(); let r = 0;
135 let c = 0;
136 let cands: Vec<u8> = candidates.get_candidates(r, c);
137 assert_eq!(cands, Vec::<u8>::new());
138 }
139
140 #[test]
141 fn test_get_candidates_full_mask() {
142 let mut candidates = Candidates::new();
143 let r = 0;
144 let c = 0;
145 let full_mask = (1 << 9) - 1; candidates.set(r, c, full_mask);
149 let cands = candidates.get_candidates(r, c);
150 assert_eq!(cands, vec![1, 2, 3, 4, 5, 6, 7, 8, 9]);
151 }
152
153 #[test]
154 fn test_get_candidates_single_candidate() {
155 let mut candidates = Candidates::new();
156 let r = 1;
157 let c = 2;
158
159 candidates.set(r, c, 1 << 0); let cands_1 = candidates.get_candidates(r, c);
162 assert_eq!(cands_1, vec![1]);
163
164 candidates.set(r, c, 1 << 4); let cands_5 = candidates.get_candidates(r, c);
167 assert_eq!(cands_5, vec![5]);
168
169 candidates.set(r, c, 1 << 8); let cands_9 = candidates.get_candidates(r, c);
172 assert_eq!(cands_9, vec![9]);
173 }
174
175 #[test]
176 fn test_get_candidates_multiple_candidates() {
177 let mut candidates = Candidates::new();
178 let r = 3;
179 let c = 4;
180
181 let mask = (1 << 1) | (1 << 3) | (1 << 6); candidates.set(r, c, mask);
187 let cands = candidates.get_candidates(r, c);
188 assert_eq!(cands, vec![2, 4, 7]);
189
190 let mask_1_9 = (1 << 0) | (1 << 8); candidates.set(r, c, mask_1_9);
194 let cands_1_9 = candidates.get_candidates(r, c);
195 assert_eq!(cands_1_9, vec![1, 9]);
196 }
197
198 #[test]
199 fn test_get_candidates_different_cells() {
200 let mut candidates = Candidates::new();
201
202 candidates.set(0, 0, (1 << 0) | (1 << 2)); candidates.set(8, 8, (1 << 5) | (1 << 7)); assert_eq!(candidates.get_candidates(0, 0), vec![1, 3]);
208 assert_eq!(candidates.get_candidates(8, 8), vec![6, 8]);
209 assert_eq!(candidates.get_candidates(0, 1), Vec::<u8>::new()); }
211}