Add a hidden single strategy.

This commit is contained in:
Drew Galbraith 2024-06-26 23:38:21 -07:00
parent a6b35d6bf3
commit ea1d345a4e
3 changed files with 105 additions and 2 deletions

View File

@ -1,5 +1,5 @@
use crate::board::Board;
use crate::strategy::{NakedSingle, Strategy, StrategyFn};
use crate::strategy::{HiddenSingle, NakedSingle, Strategy, StrategyFn};
use crate::validator;
fn try_strategies(strategies: &[StrategyFn], sudoku_board: &Board) -> Option<Box<dyn Strategy>> {
@ -21,7 +21,7 @@ pub fn solve_board(mut sudoku_board: Board) -> Result<Board, Board> {
);
}
let strategies: [StrategyFn; 1] = [NakedSingle::find_instance];
let strategies: [StrategyFn; 2] = [NakedSingle::find_instance, HiddenSingle::find_instance];
while let Some(ns) = try_strategies(&strategies, &sudoku_board) {
sudoku_board = ns.apply(sudoku_board);

View File

@ -0,0 +1,101 @@
use crate::board::Board;
use crate::square::Square;
use crate::strategy::Strategy;
pub struct HiddenSingle {
index: u8,
value: u8,
}
enum Seen {
NotSeen,
SeenOnce(u8),
SeenTwice,
}
impl Strategy for HiddenSingle {
fn find_instance(board: &Board) -> Option<Box<dyn Strategy>> {
for r in 0..9 {
for n in 1..=9 {
let seen = board
.row(r)
.fold(Seen::NotSeen, |curr, square| match square {
Square::Marks(i, opts) => {
if opts.get(n as usize) {
match curr {
Seen::NotSeen => Seen::SeenOnce(i),
_ => Seen::SeenTwice,
}
} else {
curr
}
}
_ => curr,
});
match seen {
Seen::SeenOnce(i) => {
return Some(Box::new(HiddenSingle { index: i, value: n }))
}
_ => {}
}
}
}
for c in 0..9 {
for n in 1..=9 {
let seen = board
.col(c)
.fold(Seen::NotSeen, |curr, square| match square {
Square::Marks(i, opts) => {
if opts.get(n as usize) {
match curr {
Seen::NotSeen => Seen::SeenOnce(i),
_ => Seen::SeenTwice,
}
} else {
curr
}
}
_ => curr,
});
match seen {
Seen::SeenOnce(i) => {
return Some(Box::new(HiddenSingle { index: i, value: n }))
}
_ => {}
}
}
}
for b in 0..9 {
for n in 1..=9 {
let seen = board
.boxn(b)
.fold(Seen::NotSeen, |curr, square| match square {
Square::Marks(i, opts) => {
if opts.get(n as usize) {
match curr {
Seen::NotSeen => Seen::SeenOnce(i),
_ => Seen::SeenTwice,
}
} else {
curr
}
}
_ => curr,
});
match seen {
Seen::SeenOnce(i) => {
return Some(Box::new(HiddenSingle { index: i, value: n }))
}
_ => {}
}
}
}
None
}
fn apply(&self, mut board: Board) -> Board {
board.squares[self.index as usize] = Square::Value(self.index, self.value);
board.restrict_marks();
board
}
}

View File

@ -1,8 +1,10 @@
pub mod base;
pub mod hidden_single;
pub mod naked_single;
pub use base::Strategy;
pub use base::StrategyFn;
pub use hidden_single::HiddenSingle;
pub use naked_single::NakedSingle;