pub fn row_cells(r: usize) -> [(usize, usize); 9] {
core::array::from_fn(|c| (r, c))
}
pub fn col_cells(c: usize) -> [(usize, usize); 9] {
core::array::from_fn(|r| (r, c))
}
pub fn box_cells(box_idx: usize) -> [(usize, usize); 9] {
let start_row = (box_idx / 3) * 3;
let start_col = (box_idx % 3) * 3;
core::array::from_fn(|i| (start_row + i / 3, start_col + i % 3))
}
pub fn find_units_with_n_candidates(
candidate_bit: u16,
n: usize,
candidates: &super::super::Candidates,
board: &super::super::Board,
unit_type: UnitType,
) -> Vec<(usize, Vec<usize>)> {
let mut result = Vec::new();
for unit_idx in 0..9 {
let unit_cells = match unit_type {
UnitType::Row => row_cells(unit_idx),
UnitType::Column => col_cells(unit_idx),
};
let positions: Vec<usize> = unit_cells
.iter()
.enumerate()
.filter(|&(_, &(r, c))| {
board.is_empty(r, c) && (candidates.get(r, c) & candidate_bit) != 0
})
.map(|(pos, _)| pos)
.collect();
if positions.len() == n {
result.push((unit_idx, positions));
}
}
result
}
#[derive(Clone, Copy)]
pub enum UnitType {
Row,
Column,
}
#[cfg(test)]
mod tests {
use super::super::super::board::Board;
use super::super::super::candidates::Candidates;
use super::*;
#[test]
fn test_row_cells() {
let cells = row_cells(5);
for c in 0..9 {
assert_eq!(cells[c], (5, c));
}
}
#[test]
fn test_col_cells() {
let cells = col_cells(3);
for r in 0..9 {
assert_eq!(cells[r], (r, 3));
}
}
#[test]
fn test_box_cells() {
let box0 = box_cells(0);
assert_eq!(box0[0], (0, 0));
assert_eq!(box0[4], (1, 1));
assert_eq!(box0[8], (2, 2));
let box4 = box_cells(4);
assert_eq!(box4[0], (3, 3));
assert_eq!(box4[4], (4, 4));
assert_eq!(box4[8], (5, 5));
let box8 = box_cells(8);
assert_eq!(box8[0], (6, 6));
assert_eq!(box8[4], (7, 7));
assert_eq!(box8[8], (8, 8));
}
#[test]
fn test_find_units_with_n_candidates() {
let mut board = Board::default();
let mut candidates = Candidates::new();
let candidate_bit = 1 << 0;
candidates.set(0, 0, candidate_bit);
candidates.set(0, 1, candidate_bit);
let rows =
find_units_with_n_candidates(candidate_bit, 2, &candidates, &board, UnitType::Row);
assert_eq!(rows.len(), 1);
assert_eq!(rows[0].0, 0); assert_eq!(rows[0].1, vec![0, 1]);
let cols =
find_units_with_n_candidates(candidate_bit, 1, &candidates, &board, UnitType::Column);
assert_eq!(cols.len(), 2);
assert_eq!(cols[0].0, 0); assert_eq!(cols[1].0, 1);
let empty_rows =
find_units_with_n_candidates(candidate_bit, 3, &candidates, &board, UnitType::Row);
assert!(empty_rows.is_empty());
board.set(0, 0, 1);
let rows_after_placement =
find_units_with_n_candidates(candidate_bit, 1, &candidates, &board, UnitType::Row);
assert_eq!(rows_after_placement.len(), 1);
assert_eq!(rows_after_placement[0].0, 0);
assert_eq!(rows_after_placement[0].1, vec![1]);
}
}