#[cfg(test)]
mod tests;
use std::iter::FusedIterator;
use super::board::*;
use bit_iter::BitIter;
pub fn valid(b: &Board) -> bool {
const PRECALC_MASKS: [u64; BOARD_SIZE + 1] = [
0x00_0000_0001,
0x00_0000_0010,
0x00_0000_0100,
0x00_0000_1000,
0x00_0001_0000,
0x00_0010_0000,
0x00_0100_0000,
0x00_1000_0000,
0x01_0000_0000,
0x10_0000_0000,
];
for y in 0..BOARD_SIZE {
for x in 0..BOARD_SIZE {
if b.get_cell(x, y) > 9 {
return false;
}
}
}
for y in 0..BOARD_SIZE {
let mut acc = 0;
for x in 0..BOARD_SIZE {
acc += PRECALC_MASKS[b.get_cell(x, y) as usize];
}
if (acc & 0xee_eeee_eee0) != 0 {
return false;
}
}
for x in 0..BOARD_SIZE {
let mut acc = 0;
for y in 0..BOARD_SIZE {
acc += PRECALC_MASKS[b.get_cell(x, y) as usize];
}
if (acc & 0xee_eeee_eee0) != 0 {
return false;
}
}
for square in 0..BOARD_SIZE {
let mut acc = 0;
let x = SQUARE_SIZE * (square % SQUARE_SIZE);
let y = SQUARE_SIZE * (square / SQUARE_SIZE);
for i in 0..BOARD_SIZE {
acc += PRECALC_MASKS[b.get_cell(x + (i % 3), y + (i / 3)) as usize];
}
if (acc & 0xee_eeee_eee0) != 0 {
return false;
}
}
true
}
fn valid_choices_for_cell(b: &Board, x: usize, y: usize) -> u16 {
let mut cs = 0b00_0000_0001;
let xs = SQUARE_SIZE * (x / SQUARE_SIZE);
let ys = SQUARE_SIZE * (y / SQUARE_SIZE);
for i in 0..BOARD_SIZE {
cs |= b.get_cell_as_mask(x, i);
cs |= b.get_cell_as_mask(i, y);
cs |= b.get_cell_as_mask(xs + (i % 3), ys + (i / 3));
}
cs ^ 0b11_1111_1111u16
}
fn cell_with_fewest_candidates(b: &Board) -> Option<(usize, usize, u16)> {
let mut min_x = 0;
let mut min_y = 0;
let mut min_candidates = 0;
let mut min_count = BOARD_SIZE + 1;
for y in 0..BOARD_SIZE {
for x in 0..BOARD_SIZE {
if b.get_cell_as_mask(x, y) == 1 {
let cs = valid_choices_for_cell(b, x, y);
if cs == 0 {
return None;
}
let count = cs.count_ones() as usize;
if count == 1 {
return Some((x, y, cs));
} else if count < min_count {
min_x = x;
min_y = y;
min_candidates = cs;
min_count = count;
}
}
}
}
Some((min_x, min_y, min_candidates))
}
pub fn solve(b: &Board) -> Option<Board> {
SolutionIter::new(b).next()
}
#[derive(Debug)]
pub struct SolutionIter {
first: bool,
board: Board,
stack: Vec<(usize, usize, BitIter<u16>)>,
}
impl SolutionIter {
pub fn new(board: &Board) -> Self {
Self {
first: true,
board: *board,
stack: Vec::with_capacity(BOARD_SIZE * BOARD_SIZE),
}
}
}
impl From<Board> for SolutionIter {
fn from(board: Board) -> Self {
Self::new(&board)
}
}
impl Iterator for SolutionIter {
type Item = Board;
fn next(&mut self) -> Option<Self::Item> {
if self.first {
self.first = false;
if valid(&self.board) {
if let Some((x, y, values)) = cell_with_fewest_candidates(&self.board) {
if values == 0 {
return Some(self.board);
}
self.stack.push((x, y, values.into()));
}
}
}
if let Some((mut x, mut y, mut values)) = self.stack.pop() {
loop {
if let Some(value) = values.next() {
self.board.set_cell(x, y, value as u8);
if let Some(cs) = cell_with_fewest_candidates(&self.board) {
self.stack.push((x, y, values));
if cs.2 == 0 {
return Some(self.board);
}
x = cs.0;
y = cs.1;
values = cs.2.into();
}
} else {
self.board.set_cell(x, y, 0);
if let Some(cs) = self.stack.pop() {
x = cs.0;
y = cs.1;
values = cs.2;
} else {
return None;
}
}
}
} else {
None
}
}
}
impl FusedIterator for SolutionIter {}