From 5c350b1dddaa1ee41001f0637ae960ac91f4dee8 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Wed, 26 Jun 2024 23:08:39 -0700 Subject: [PATCH] Move to a solver that takess generic strategies. --- src/main.rs | 33 ++++++++------------------- src/solver/mod.rs | 1 + src/solver/solver.rs | 44 ++++++++++++++++++++++++++++++++++++ src/strategy/base.rs | 4 +++- src/strategy/mod.rs | 3 +++ src/strategy/naked_single.rs | 10 ++++---- 6 files changed, 67 insertions(+), 28 deletions(-) create mode 100644 src/solver/mod.rs create mode 100644 src/solver/solver.rs diff --git a/src/main.rs b/src/main.rs index e1af7a0..ccb9ff7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -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()); } diff --git a/src/solver/mod.rs b/src/solver/mod.rs new file mode 100644 index 0000000..5062c82 --- /dev/null +++ b/src/solver/mod.rs @@ -0,0 +1 @@ +pub mod solver; diff --git a/src/solver/solver.rs b/src/solver/solver.rs new file mode 100644 index 0000000..57b8eab --- /dev/null +++ b/src/solver/solver.rs @@ -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> { + for strategy in strategies { + if let Some(strat) = strategy(&sudoku_board) { + return Some(strat); + } + } + None +} + +pub fn solve_board(mut sudoku_board: Board) -> Result { + 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!(), + } +} diff --git a/src/strategy/base.rs b/src/strategy/base.rs index c642395..c4c291b 100644 --- a/src/strategy/base.rs +++ b/src/strategy/base.rs @@ -1,7 +1,9 @@ use crate::board::Board; +pub type StrategyFn = fn(&Board) -> Option>; + pub trait Strategy { - fn find_instance(board: &Board) -> Option + fn find_instance(board: &Board) -> Option> where Self: Sized; diff --git a/src/strategy/mod.rs b/src/strategy/mod.rs index 3f03a6f..7d3c11d 100644 --- a/src/strategy/mod.rs +++ b/src/strategy/mod.rs @@ -3,3 +3,6 @@ pub mod base; pub mod naked_single; pub use base::Strategy; +pub use base::StrategyFn; + +pub use naked_single::NakedSingle; diff --git a/src/strategy/naked_single.rs b/src/strategy/naked_single.rs index c4730fb..183acf2 100644 --- a/src/strategy/naked_single.rs +++ b/src/strategy/naked_single.rs @@ -6,7 +6,7 @@ pub struct NakedSingle { } impl Strategy for NakedSingle { - fn find_instance(board: &crate::board::Board) -> Option + fn find_instance(board: &crate::board::Board) -> Option> 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 }) }