Move to a solver that takess generic strategies.

This commit is contained in:
Drew Galbraith 2024-06-26 23:08:39 -07:00
parent b51f47594d
commit 5c350b1ddd
6 changed files with 67 additions and 28 deletions

View File

@ -1,11 +1,10 @@
mod board;
mod iterators;
mod solver;
mod square;
mod strategy;
mod validator;
use strategy::Strategy;
fn main() {
let nyt_hard = "3...184.9\
8.47.....\
@ -29,28 +28,16 @@ fn main() {
*/
let mut sudoku_board = board::Board::from_string(nyt_hard);
if let validator::BoardState::Broken(ind) = validator::validate_board(&sudoku_board) {
println!("{}", sudoku_board.to_url());
panic!(
"Error invalid number at row {} col {}",
(ind / 9) + 1,
(ind % 9) + 1
);
}
while let Some(ns) = strategy::naked_single::NakedSingle::find_instance(&sudoku_board) {
println!("Applying naked single.");
sudoku_board = ns.apply(sudoku_board);
if let validator::BoardState::Broken(ind) = validator::validate_board(&sudoku_board) {
println!("{}", sudoku_board.to_url());
panic!(
"Error invalid number at row {} col {}",
(ind / 9) + 1,
(ind % 9) + 1
);
sudoku_board = match solver::solver::solve_board(sudoku_board) {
Ok(board) => {
println!("Solved!");
board
}
}
Err(board) => {
println!("Failed to solve!");
board
}
};
println!("{:#?}", sudoku_board);
println!("{}", sudoku_board.to_url());
}

1
src/solver/mod.rs Normal file
View File

@ -0,0 +1 @@
pub mod solver;

44
src/solver/solver.rs Normal file
View File

@ -0,0 +1,44 @@
use crate::board::Board;
use crate::strategy::{NakedSingle, Strategy, StrategyFn};
use crate::validator;
fn try_strategies(strategies: &[StrategyFn], sudoku_board: &Board) -> Option<Box<dyn Strategy>> {
for strategy in strategies {
if let Some(strat) = strategy(&sudoku_board) {
return Some(strat);
}
}
None
}
pub fn solve_board(mut sudoku_board: Board) -> Result<Board, Board> {
if let validator::BoardState::Broken(ind) = validator::validate_board(&sudoku_board) {
println!("{}", sudoku_board.to_url());
panic!(
"Error invalid number at row {} col {}",
(ind / 9) + 1,
(ind % 9) + 1
);
}
let strategies: [StrategyFn; 1] = [NakedSingle::find_instance];
while let Some(ns) = try_strategies(&strategies, &sudoku_board) {
sudoku_board = ns.apply(sudoku_board);
if let validator::BoardState::Broken(ind) = validator::validate_board(&sudoku_board) {
println!("{}", sudoku_board.to_url());
panic!(
"Error invalid number at row {} col {}",
(ind / 9) + 1,
(ind % 9) + 1
);
}
}
match validator::validate_board(&sudoku_board) {
validator::BoardState::Finished => Ok(sudoku_board),
validator::BoardState::InProgress => Err(sudoku_board),
_ => unreachable!(),
}
}

View File

@ -1,7 +1,9 @@
use crate::board::Board;
pub type StrategyFn = fn(&Board) -> Option<Box<dyn Strategy>>;
pub trait Strategy {
fn find_instance(board: &Board) -> Option<Self>
fn find_instance(board: &Board) -> Option<Box<dyn Strategy>>
where
Self: Sized;

View File

@ -3,3 +3,6 @@ pub mod base;
pub mod naked_single;
pub use base::Strategy;
pub use base::StrategyFn;
pub use naked_single::NakedSingle;

View File

@ -6,7 +6,7 @@ pub struct NakedSingle {
}
impl Strategy for NakedSingle {
fn find_instance(board: &crate::board::Board) -> Option<Self>
fn find_instance(board: &crate::board::Board) -> Option<Box<dyn Strategy>>
where
Self: Sized,
{
@ -18,9 +18,11 @@ impl Strategy for NakedSingle {
_ => None,
})
.find(|(_index, marks)| marks.len() == 1)
.map(|(index, marks)| NakedSingle {
index: *index,
value: marks.first_index().unwrap() as u8,
.map(|(index, marks)| {
Box::new(NakedSingle {
index: *index,
value: marks.first_index().unwrap() as u8,
}) as Box<dyn Strategy>
})
}