use crate::constraint::VarId;
use crate::domain::bitset::BitsetDomain;
use crate::{Csp, SolveConfig};
pub fn sudoku_csp_skeleton(n: u32) -> Csp<BitsetDomain> {
let m = n * n;
let total = (m * m) as usize;
let mut csp = Csp::new();
let domain = BitsetDomain::new(1..=m);
for _ in 0..total {
csp.add_variable(domain.clone());
}
for r in 0..m {
let row_vars: Vec<VarId> = (0..m).map(|c| (r * m + c) as VarId).collect();
csp.add_all_different(row_vars);
}
for c in 0..m {
let col_vars: Vec<VarId> = (0..m).map(|r| (r * m + c) as VarId).collect();
csp.add_all_different(col_vars);
}
for bi in 0..n {
for bj in 0..n {
let box_vars: Vec<VarId> = (0..n)
.flat_map(|di| (0..n).map(move |dj| ((bi * n + di) * m + (bj * n + dj)) as VarId))
.collect();
csp.add_all_different(box_vars);
}
}
csp.finalize();
csp
}
pub fn sudoku_given(board: &[u32]) -> Vec<(VarId, u32)> {
board
.iter()
.enumerate()
.filter(|&(_, &v)| v != 0)
.map(|(i, &v)| (i as VarId, v))
.collect()
}
pub fn create_sudoku_csp(board: &[u32], n: u32) -> (Csp<BitsetDomain>, Vec<(VarId, u32)>) {
let m = n * n;
let total = (m * m) as usize;
assert_eq!(
board.len(),
total,
"board must have M*M = {} elements",
total
);
let csp = sudoku_csp_skeleton(n);
let given = sudoku_given(board);
(csp, given)
}
pub fn solve_sudoku(board: &[u32], n: u32, config: &SolveConfig) -> Option<Vec<u32>> {
let (mut csp, given) = create_sudoku_csp(board, n);
let solutions = csp.solve_with_given(config, &given);
solutions.into_iter().next()
}