sudoku/strategy/strategies/
avoidable_rectangles.rs1use super::prelude::*;
3
4#[allow(unused)]
5fn find_avoidable_rectangles(
6 filled_cells: Sudoku,
7 clues: Sudoku,
8 cell_poss_digits: &CellArray<Set<Digit>>,
9 stop_after_first: bool,
10 mut on_avoidable_rectangle: impl FnMut(
11 Set<Line>,
13 Candidate,
15 ),
16) -> Result<(), Unsolvable> {
17 let cell = |row: u8, col: u8| row * 9 + col;
18 for row1 in 0..8 {
19 for row2 in row1 + 1..9 {
20 let rows_in_same_chute = row1 / 3 == row2 / 3;
21 for col1 in 0..8 {
22 for col2 in col1 + 1..9 {
23 let cols_in_same_chute = col1 / 3 == col2 / 3;
24 if !(rows_in_same_chute ^ cols_in_same_chute) {
25 continue;
26 }
27
28 let cells = [
31 cell(row1, col1),
32 cell(row1, col2),
33 cell(row2, col1),
34 cell(row2, col2),
35 ];
36 let mut n_cells_set = 0;
37 let mut n_cells_clues = 0;
38 let mut set_digits = Set::NONE;
39 let mut free_cell = 0;
40 for &cell in &cells {
41 match filled_cells.0[cell as usize] {
42 0 => free_cell = cell,
43 digit => {
44 set_digits |= Digit::new(digit);
45 n_cells_set += 1;
46 if clues.0[cell as usize] != 0 {
47 n_cells_clues += 1;
48 }
49 }
50 }
51 }
52
53 if n_cells_set == 3 && n_cells_clues == 0 && set_digits.len() == 2 {
54 let candidates_remaining_cell = cell_poss_digits[Cell::new(free_cell)];
55 if candidates_remaining_cell.overlaps(set_digits) {
56 let row1 = Row::new(row1);
58 let row2 = Row::new(row2);
59 let col1 = Col::new(col1);
60 let col2 = Col::new(col2);
61 if let Some(digit) = (candidates_remaining_cell & set_digits).unique()? {
62 on_avoidable_rectangle(
63 Line::from(row1).as_set()
64 | Line::from(row2)
65 | Line::from(col1)
66 | Line::from(col2),
67 Candidate {
68 cell: Cell::new(free_cell),
69 digit,
70 },
71 )
72 }
73 }
74 }
75 }
76 }
77 }
78 }
79 Ok(())
80}