diff --git a/src/hecht.rs b/src/hecht.rs index 4cf3061..be904a3 100644 --- a/src/hecht.rs +++ b/src/hecht.rs @@ -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, Rc>, Rc>, usize), - Process(Rc, Rc>, Action), + Process(Rc, Action), Initial(SolverBoard), } struct SolverBoardIterator { cache: HashSet<[[u16; VALUES]; VALUES]>, // to avoid processing the same board twice stack: Vec, + 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 = 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,28 +285,20 @@ impl SolverBoard { } ) } - fn get_all_actions(&self) -> Vec { - if self.valid && !self.is_solved() { - let mut vec = self.todos.iter() - .map(|point| (point, self.get_value(point))) - .collect::>(); // collect into the vector so we can (optionally) apply sorting + fn get_probe_actions(&self) -> Vec { + let result = self.todos.iter() + .min_by_key(|point| self.get_value(point).count_ones()); - 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()); - - 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::>() - ) - .flatten() - .collect::>(); + 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() } - + } impl SolverBoardIterator { @@ -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 { 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 { 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, excludes_ref: Rc>, actions: Rc>, index : usize) -> Option { - 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, excludes: Rc>, action: Action) -> Option { + fn handle_process(&mut self, board_ref: Rc, action: Action) -> Option { 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, excludes: Rc>)-> Option { + fn handle_board(&mut self, board: Rc)-> Option { 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()) }