Simplified the solution

master
Hecht 2 years ago
parent 1bf495d9dc
commit d16ac39071

@ -4,7 +4,6 @@ use std::collections::HashSet;
use crate::solver::{Solver, Generator, SodokuComplexity}; use crate::solver::{Solver, Generator, SodokuComplexity};
use crate::board::Board; use crate::board::Board;
use crate::utils::*; use crate::utils::*;
use std::borrow::Borrow;
use std::rc::Rc; use std::rc::Rc;
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
@ -42,14 +41,14 @@ struct SolverBoard {
} }
enum SolverBoardItem { enum SolverBoardItem {
Prepare(Rc<SolverBoard>, Rc<HashSet<Action>>, Rc<Vec<Action>>, usize), Process(Rc<SolverBoard>, Action),
Process(Rc<SolverBoard>, Rc<HashSet<Action>>, Action),
Initial(SolverBoard), Initial(SolverBoard),
} }
struct SolverBoardIterator { struct SolverBoardIterator {
cache: HashSet<[[u16; VALUES]; VALUES]>, // to avoid processing the same board twice cache: HashSet<[[u16; VALUES]; VALUES]>, // to avoid processing the same board twice
stack: Vec<SolverBoardItem>, stack: Vec<SolverBoardItem>,
solve: bool,
} }
impl PartialEq for SolverBoard { impl PartialEq for SolverBoard {
@ -70,24 +69,12 @@ impl HechtSolver {
} }
pub fn test(&self, board: &Board) { pub fn test(&self, board: &Board) {
let mut invalid_counter = 0;
let mut unsolved_counter = 0;
let mut solved_counter = 0;
let count = 1024;
let mut boards : HashSet<Board> = HashSet::with_capacity(count);
let count = SolverBoardIterator::new(board) let count = SolverBoardIterator::new(board)
.inspect(|_| invalid_counter += 1)
.filter(|x| x.valid)
.inspect(|_| unsolved_counter += 1)
.filter(|x| x.is_solved()) .filter(|x| x.is_solved())
.inspect(|_| solved_counter += 1) .inspect(|_| println!("Solved Board detected"))
.filter_map(|x| x.to_board() ) .count();
.take(1024) println!("Count: {}", count);
.for_each(|board| {boards.insert(board); });
println!("I: {}, U: {}, S: {}, B: {}", invalid_counter, unsolved_counter, solved_counter, boards.len())
} }
@ -298,24 +285,16 @@ impl SolverBoard {
} ) } )
} }
fn get_all_actions(&self) -> Vec<Action> { fn get_probe_actions(&self) -> Vec<Action> {
if self.valid && !self.is_solved() { let result = self.todos.iter()
let mut vec = self.todos.iter() .min_by_key(|point| self.get_value(point).count_ones());
.map(|point| (point, self.get_value(point)))
.collect::<Vec<_>>(); // collect into the vector so we can (optionally) apply sorting
vec.sort_unstable_by_key(|action| action.1.count_ones());
// println!(" {} --> {:?} has only {} possibilities", self.todos.len(), vec[0].0, vec[0].1.count_ones()); if let Some(point) = result {
let p_value = self.get_value(point);
return vec.iter() return SolverBoard::get_bitvalue_sequence().iter()
.map(|action| SolverBoard::get_bitvalue_sequence().iter() .filter(|&value| (p_value & value ) != 0)
.filter(|&value| (action.1 & value) != 0) .map(|&value| Action::Probe(point.clone(), value))
.map(|&value| Action::Probe(action.0.clone(), value)) .collect();
.collect::<Vec<_>>()
)
.flatten()
.collect::<Vec<_>>();
} }
Vec::new() Vec::new()
} }
@ -328,12 +307,12 @@ impl SolverBoardIterator {
} }
fn from_board(board: SolverBoard) -> SolverBoardIterator { fn from_board(board: SolverBoard) -> SolverBoardIterator {
SolverBoardIterator{cache: HashSet::with_capacity(128), stack: vec![SolverBoardItem::Initial(board)]} SolverBoardIterator{cache: HashSet::with_capacity(128), stack: vec![SolverBoardItem::Initial(board)], solve: true}
} }
fn next_board(&mut self) -> Option<SolverBoard> { fn next_board(&mut self) -> Option<SolverBoard> {
while let Some(item) = self.stack.pop() { while let Some(item) = self.stack.pop() {
// println!("Stack size {}, cache size {}", self.stack.len(), self.cache.len()); println!("Stack size {}, cache size {}", self.stack.len(), self.cache.len());
if let Some(board) = self.pop_board(item) { if let Some(board) = self.pop_board(item) {
return Some(board); return Some(board);
} }
@ -347,43 +326,20 @@ impl SolverBoardIterator {
SolverBoardItem::Initial(board) => { SolverBoardItem::Initial(board) => {
self.handle_initial(board) self.handle_initial(board)
} }
SolverBoardItem::Process(board, excludes, action) => { SolverBoardItem::Process(board, action) => {
self.handle_process(board, excludes, action) self.handle_process(board, action)
}
SolverBoardItem::Prepare(board, excludes, actions, index) => {
self.handle_prepare(board, excludes, actions, index)
} }
} }
} }
fn handle_initial(&mut self, board: SolverBoard) -> Option<SolverBoard> { fn handle_initial(&mut self, board: SolverBoard) -> Option<SolverBoard> {
if board.valid { if board.valid {
return self.handle_board(Rc::new(board), Rc::new(HashSet::with_capacity(CELLS * VALUES))) return self.handle_board(Rc::new(board))
} }
None None
} }
/** fn handle_process(&mut self, board_ref: Rc<SolverBoard>, action: Action) -> Option<SolverBoard> {
* The preparation step is quite memory and time consuming.
* For this reason it has been extracted into a separate computing step.
* Best case is, that only the last process step requires preparation.
*/
fn handle_prepare(&mut self, board_ref: Rc<SolverBoard>, excludes_ref: Rc<HashSet<Action>>, actions: Rc<Vec<Action>>, index : usize) -> Option<SolverBoard> {
let mut excludes_ref = excludes_ref; // re-label
let excludes = Rc::make_mut(&mut excludes_ref);
// we always start with a high index??
assert!(board_ref.valid);
// extend the current exclude list by the exceeded actions in the list (before the own index)
actions.iter().take(index)
.for_each(|action| {excludes.insert(action.clone());});
self.stack.push(SolverBoardItem::Process(Rc::clone(&board_ref), Rc::clone(&excludes_ref), actions[index].clone()));
None
}
fn handle_process(&mut self, board_ref: Rc<SolverBoard>, excludes: Rc<HashSet<Action>>, action: Action) -> Option<SolverBoard> {
let mut board_ref = board_ref; // re-label let mut board_ref = board_ref; // re-label
let board = Rc::make_mut(&mut board_ref); let board = Rc::make_mut(&mut board_ref);
@ -394,19 +350,16 @@ impl SolverBoardIterator {
return None; return None;
} }
return self.handle_board(board_ref, excludes); return self.handle_board(board_ref);
} }
fn handle_board(&mut self, board: Rc<SolverBoard>, excludes: Rc<HashSet<Action>>)-> Option<SolverBoard> { fn handle_board(&mut self, board: Rc<SolverBoard>)-> Option<SolverBoard> {
if !board.is_solved() { if !board.is_solved() {
let actions = Rc::new(board.get_all_actions()); let actions = board.get_probe_actions();
actions.iter() actions.into_iter()
.enumerate() .for_each(|action| self.stack.push(SolverBoardItem::Process(Rc::clone(&board), action)))
.rev() //
.filter(|it| !excludes.contains(it.1))
.for_each(|it| self.stack.push(SolverBoardItem::Prepare(Rc::clone(&board), Rc::clone(&excludes), Rc::clone(&actions), it.0)))
} }
Some((*board).clone()) Some((*board).clone())
} }

Loading…
Cancel
Save