Move to a solver that takess generic strategies.
This commit is contained in:
parent
b51f47594d
commit
5c350b1ddd
31
src/main.rs
31
src/main.rs
|
@ -1,11 +1,10 @@
|
||||||
mod board;
|
mod board;
|
||||||
mod iterators;
|
mod iterators;
|
||||||
|
mod solver;
|
||||||
mod square;
|
mod square;
|
||||||
mod strategy;
|
mod strategy;
|
||||||
mod validator;
|
mod validator;
|
||||||
|
|
||||||
use strategy::Strategy;
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let nyt_hard = "3...184.9\
|
let nyt_hard = "3...184.9\
|
||||||
8.47.....\
|
8.47.....\
|
||||||
|
@ -29,28 +28,16 @@ fn main() {
|
||||||
*/
|
*/
|
||||||
let mut sudoku_board = board::Board::from_string(nyt_hard);
|
let mut sudoku_board = board::Board::from_string(nyt_hard);
|
||||||
|
|
||||||
if let validator::BoardState::Broken(ind) = validator::validate_board(&sudoku_board) {
|
sudoku_board = match solver::solver::solve_board(sudoku_board) {
|
||||||
println!("{}", sudoku_board.to_url());
|
Ok(board) => {
|
||||||
panic!(
|
println!("Solved!");
|
||||||
"Error invalid number at row {} col {}",
|
board
|
||||||
(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
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
Err(board) => {
|
||||||
|
println!("Failed to solve!");
|
||||||
|
board
|
||||||
}
|
}
|
||||||
|
};
|
||||||
println!("{:#?}", sudoku_board);
|
println!("{:#?}", sudoku_board);
|
||||||
println!("{}", sudoku_board.to_url());
|
println!("{}", sudoku_board.to_url());
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
pub mod solver;
|
|
@ -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!(),
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,9 @@
|
||||||
use crate::board::Board;
|
use crate::board::Board;
|
||||||
|
|
||||||
|
pub type StrategyFn = fn(&Board) -> Option<Box<dyn Strategy>>;
|
||||||
|
|
||||||
pub trait Strategy {
|
pub trait Strategy {
|
||||||
fn find_instance(board: &Board) -> Option<Self>
|
fn find_instance(board: &Board) -> Option<Box<dyn Strategy>>
|
||||||
where
|
where
|
||||||
Self: Sized;
|
Self: Sized;
|
||||||
|
|
||||||
|
|
|
@ -3,3 +3,6 @@ pub mod base;
|
||||||
pub mod naked_single;
|
pub mod naked_single;
|
||||||
|
|
||||||
pub use base::Strategy;
|
pub use base::Strategy;
|
||||||
|
pub use base::StrategyFn;
|
||||||
|
|
||||||
|
pub use naked_single::NakedSingle;
|
||||||
|
|
|
@ -6,7 +6,7 @@ pub struct NakedSingle {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Strategy for 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
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
|
@ -18,9 +18,11 @@ impl Strategy for NakedSingle {
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.find(|(_index, marks)| marks.len() == 1)
|
.find(|(_index, marks)| marks.len() == 1)
|
||||||
.map(|(index, marks)| NakedSingle {
|
.map(|(index, marks)| {
|
||||||
|
Box::new(NakedSingle {
|
||||||
index: *index,
|
index: *index,
|
||||||
value: marks.first_index().unwrap() as u8,
|
value: marks.first_index().unwrap() as u8,
|
||||||
|
}) as Box<dyn Strategy>
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue