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::board::Board;
use crate::utils::*;
use std::borrow::Borrow;
use std::rc::Rc;
use std::hash::{Hash, Hasher};
@ -42,14 +41,14 @@ struct SolverBoard {
}
enum SolverBoardItem {
Prepare(Rc<SolverBoard>, Rc<HashSet<Action>>, Rc<Vec<Action>>, usize),
Process(Rc<SolverBoard>, Rc<HashSet<Action>>, Action),
Process(Rc<SolverBoard>, Action),
Initial(SolverBoard),
}
struct SolverBoardIterator {
cache: HashSet<[[u16; VALUES]; VALUES]>, // to avoid processing the same board twice
stack: Vec<SolverBoardItem>,
solve: bool,
}
impl PartialEq for SolverBoard {
@ -70,24 +69,12 @@ impl HechtSolver {
}
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)
.inspect(|_| invalid_counter += 1)
.filter(|x| x.valid)
.inspect(|_| unsolved_counter += 1)
.filter(|x| x.is_solved())
.inspect(|_| solved_counter += 1)
.filter_map(|x| x.to_board() )
.take(1024)
.for_each(|board| {boards.insert(board); });
.inspect(|_| println!("Solved Board detected"))
.count();
println!("Count: {}", count);
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> {
if self.valid && !self.is_solved() {
let mut vec = self.todos.iter()
.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());
fn get_probe_actions(&self) -> Vec<Action> {
let result = self.todos.iter()
.min_by_key(|point| self.get_value(point).count_ones());
// println!(" {} --> {:?} has only {} possibilities", self.todos.len(), vec[0].0, vec[0].1.count_ones());
return vec.iter()
.map(|action| SolverBoard::get_bitvalue_sequence().iter()
.filter(|&value| (action.1 & value) != 0)
.map(|&value| Action::Probe(action.0.clone(), value))
.collect::<Vec<_>>()
)
.flatten()
.collect::<Vec<_>>();
if let Some(point) = result {
let p_value = self.get_value(point);
return SolverBoard::get_bitvalue_sequence().iter()
.filter(|&value| (p_value & value ) != 0)
.map(|&value| Action::Probe(point.clone(), value))
.collect();
}
Vec::new()
}
@ -328,12 +307,12 @@ impl 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> {
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) {
return Some(board);
}
@ -347,43 +326,20 @@ impl SolverBoardIterator {
SolverBoardItem::Initial(board) => {
self.handle_initial(board)
}
SolverBoardItem::Process(board, excludes, action) => {
self.handle_process(board, excludes, action)
}
SolverBoardItem::Prepare(board, excludes, actions, index) => {
self.handle_prepare(board, excludes, actions, index)
SolverBoardItem::Process(board, action) => {
self.handle_process(board, action)
}
}
}
fn handle_initial(&mut self, board: SolverBoard) -> Option<SolverBoard> {
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
}
/**
* 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> {
fn handle_process(&mut self, board_ref: Rc<SolverBoard>, action: Action) -> Option<SolverBoard> {
let mut board_ref = board_ref; // re-label
let board = Rc::make_mut(&mut board_ref);
@ -394,19 +350,16 @@ impl SolverBoardIterator {
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() {
let actions = Rc::new(board.get_all_actions());
actions.iter()
.enumerate()
.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)))
let actions = board.get_probe_actions();
actions.into_iter()
.for_each(|action| self.stack.push(SolverBoardItem::Process(Rc::clone(&board), action)))
}
Some((*board).clone())
}

Loading…
Cancel
Save