Converted the project to use iterators instead of recursion

master
Hecht 2 years ago
parent 33684908d7
commit 13643c2df3

@ -2,18 +2,18 @@
use std::collections::HashSet; use std::collections::HashSet;
#[derive(Clone)] #[derive(Clone)]
pub struct Playground { pub struct Board {
arr: [[u8; 9]; 9] arr: [[u8; 9]; 9]
} }
impl Playground { impl Board {
pub fn new() -> Playground { pub fn new() -> Board {
return Playground { arr: [[0; 9]; 9] }; return Board { arr: [[0; 9]; 9] };
} }
pub fn from_array(arr: &[u8;81]) -> Playground { pub fn from_array(arr: &[u8;81]) -> Board {
let mut p = Playground::new(); let mut p = Board::new();
for y in 0..9 { for y in 0..9 {
for x in 0..9 { for x in 0..9 {
p.arr[y][x] = arr[y*9+x]; p.arr[y][x] = arr[y*9+x];
@ -61,7 +61,7 @@ impl Playground {
.all(|value| *value != 0u8); .all(|value| *value != 0u8);
} }
/** Checks if the playground has failures (not neccesary solved) */ /** Checks if the Board has failures (not neccesary solved) */
pub fn is_valid(&self) -> bool { pub fn is_valid(&self) -> bool {
self.rows_valid() && self.columns_valid() && self.sections_valid() self.rows_valid() && self.columns_valid() && self.sections_valid()
} }
@ -113,7 +113,7 @@ impl Playground {
true true
} }
pub fn contains(&self, other : &Playground) -> bool { pub fn contains(&self, other : &Board) -> bool {
for x in 0..9 { for x in 0..9 {
for y in 0..9 { for y in 0..9 {
if other.arr[y][x] != 0 && self.arr[y][x] != other.arr[y][x] { if other.arr[y][x] != 0 && self.arr[y][x] != other.arr[y][x] {

@ -1,39 +1,57 @@
use std::collections::HashSet;
use crate::solver::Solver; use crate::solver::Solver;
use crate::playground::Playground; use crate::board::Board;
use crate::utils::Locatable; use std::hash::{Hash, Hasher};
use crate::utils::LocatableVec; use std::ops::ControlFlow;
use crate::utils::FsVec;
static CELLS : usize = 81;
pub struct HechtSolver { pub struct HechtSolver {
} }
#[derive(Hash, Clone, Copy, Eq, PartialEq, Debug, Default)] #[derive(Hash, Clone, Eq, PartialEq, Debug)]
struct Point { struct Point {
pub x: usize, pub x: usize,
pub y: usize, pub y: usize,
pub s: usize, pub s: usize,
} }
impl Locatable for Point {
fn get_xy(&self) -> (usize, usize) {
(self.x,self.y)
}
}
#[derive(Debug)] #[derive(Debug)]
struct Action { struct Action {
pub p : Point, pub p : Point,
pub value: u16 pub value: u16
} }
#[derive(Clone)] #[derive(Clone, Eq)]
pub struct SolverPlayground { struct SolverBoard {
arr: [[u16; 9]; 9], arr: [[u16; 9]; 9],
todos: LocatableVec<Point, 81>, todos: HashSet<Point>,
valid: bool, valid: bool,
rec_level: usize, }
enum SolverBoardItem {
Recursive(SolverBoard, Vec<Action>),
Initial(SolverBoard),
}
struct SolverBoardIterator {
cache: HashSet<[[u16; 9]; 9]>, // to avoid processing the same board twice
stack: Vec<SolverBoardItem>,
}
impl PartialEq for SolverBoard {
fn eq(&self, other: &SolverBoard) -> bool {
self.arr == other.arr && self.valid == other.valid
}
}
impl Hash for SolverBoard {
fn hash<H: Hasher>(&self, state: &mut H) {
self.arr.hash(state);
}
} }
impl HechtSolver { impl HechtSolver {
@ -43,33 +61,55 @@ impl HechtSolver {
} }
impl Solver for HechtSolver { impl Solver for HechtSolver {
fn solve(&self, pg: &Playground) -> Option<Playground> { fn solve(&self, pg: &Board) -> Option<Board> {
SolverPlayground::new(&pg) SolverBoardIterator::new(pg)
.solve() .find(|x| x.is_solved())
.map(|x| x.to_board())
.flatten()
}
fn is_unique(&self, pg: &Board) -> bool {
let first_solution = SolverBoard::new();
SolverBoardIterator::new(pg)
.filter(|x| x.is_solved())
.try_fold(first_solution, |prev, x| {
if !prev.is_solved() || prev == x {
ControlFlow::Continue(x)
} else {
ControlFlow::Break(prev)
}
}).is_continue()
} }
} }
impl SolverPlayground { impl SolverBoard {
pub fn new(pg: &Playground) -> SolverPlayground { pub fn new() -> SolverBoard {
let points : LocatableVec<_, 81> = [0usize..81].into_iter().flatten() let points = [0usize..CELLS].into_iter().flatten()
.map(|idx| [idx%9, idx/9]) .map(|idx| [idx%9, idx/9])
.map(|p| Point{x: p[0], y:p[1], s: p[1] / 3 * 3 + p[0] / 3}) .map(|p| Point{x: p[0], y:p[1], s: p[1] / 3 * 3 + p[0] / 3})
.collect(); .collect::<HashSet<_>>();
let mut spg = SolverPlayground { arr: [[0x1FFu16; 9]; 9], todos: points.clone(), valid: true, rec_level: 0}; SolverBoard { arr: [[0x1FFu16; 9]; 9], todos: points, valid: true}
}
pub fn from(pg: &Board) -> SolverBoard {
let mut spg = SolverBoard::new();
for p in points.iter() { for p in spg.todos.clone().iter() {
if let Some(value) = pg.get_value(p.x, p.y) { if let Some(value) = pg.get_value(p.x, p.y) {
spg.set_value(&p, value); spg.set_value(&p, value);
} }
} }
spg.solve_logically();
spg spg
} }
fn to_playground(&self) -> Option<Playground> { fn to_board(&self) -> Option<Board> {
let mut pg = Playground::new(); let mut pg = Board::new();
for x in 0..9 { for x in 0..9 {
for y in 0..9 { for y in 0..9 {
@ -85,16 +125,18 @@ impl SolverPlayground {
Some(pg) Some(pg)
} }
pub fn solve(&mut self) -> Option<Playground> { fn solve_logically(&mut self) {
while self.valid && self.todos.len() > 0 { while self.valid {
if let Some(action) = self.get_simple_action() { if let Some(action) = self.get_simple_action() {
self.apply(&action); self.set_bit_value(&action.p, action.value);
} else { } else {
return self.get_complex_action(); break;
}
} }
} }
self.to_playground() fn is_solved(&self) -> bool {
self.valid && self.todos.len() == 0
} }
fn set_value(&mut self, p : &Point, value : u8) { fn set_value(&mut self, p : &Point, value : u8) {
@ -116,7 +158,7 @@ impl SolverPlayground {
// Filter positions that were known not to hold the value // Filter positions that were known not to hold the value
.filter(|&pos| (self.arr[pos.y][pos.x] & bit_value) != 0) .filter(|&pos| (self.arr[pos.y][pos.x] & bit_value) != 0)
.cloned() .cloned()
.collect::<FsVec::<_,81>>() .collect::<Vec::<_>>()
.iter() .iter()
.for_each(|pos| self.remove_value(&pos, bit_value)); .for_each(|pos| self.remove_value(&pos, bit_value));
@ -128,8 +170,8 @@ impl SolverPlayground {
} }
self.arr[p.y][p.x] &= !bit_value; self.arr[p.y][p.x] &= !bit_value;
if let Some(action) = SolverPlayground::create_action(p, self.arr[p.y][p.x]) { if let Some(action) = SolverBoard::create_action(p, self.arr[p.y][p.x]) {
self.apply(&action); self.set_bit_value(&action.p, action.value);
} else if self.arr[p.y][p.x] == 0 { } else if self.arr[p.y][p.x] == 0 {
self.valid = false; self.valid = false;
} }
@ -144,6 +186,7 @@ impl SolverPlayground {
fn apply(&mut self, action : &Action) { fn apply(&mut self, action : &Action) {
self.set_bit_value(&action.p, action.value); self.set_bit_value(&action.p, action.value);
self.solve_logically();
} }
#[inline] #[inline]
@ -169,11 +212,11 @@ impl SolverPlayground {
// println!("Simple Action"); // println!("Simple Action");
self.todos.iter() self.todos.iter()
.find_map(|lhs| { .find_map(|lhs| {
let own_value = self.get_value(&lhs); let own_value = self.get_value(lhs);
self.todos.iter() self.todos.iter()
.filter(|&rhs| lhs.x == rhs.x || lhs.y == rhs.y || lhs.s == rhs.s) .filter(|&rhs| lhs.x == rhs.x || lhs.y == rhs.y || lhs.s == rhs.s)
.filter(|&rhs| lhs != rhs) .filter(|&rhs| lhs != rhs)
.map(|&rhs| { .map(|rhs| {
let value = self.get_value(&rhs) & own_value; let value = self.get_value(&rhs) & own_value;
let row_value = if lhs.x == rhs.x {value} else {0}; let row_value = if lhs.x == rhs.x {value} else {0};
let col_value = if lhs.y == rhs.y {value} else {0}; let col_value = if lhs.y == rhs.y {value} else {0};
@ -186,26 +229,111 @@ impl SolverPlayground {
.flatten() .flatten()
.map(|value| value ^ own_value) .map(|value| value ^ own_value)
.filter(|value| value.count_ones() == 1) .filter(|value| value.count_ones() == 1)
.find_map(|value| SolverPlayground::create_action(lhs, value)) .find_map(|value| SolverBoard::create_action(lhs, value))
} ) } )
} }
fn get_complex_action(&self) -> Option<Playground> { fn get_all_actions(&self) -> Vec<Action> {
// println!("Complex Action"); if self.valid && !self.is_solved() {
let result = self.todos.iter() let mut vec = self.todos.iter()
.min_by_key(|x| self.get_value(x).count_ones()); .map(|point| Action{p: point.clone(), value: self.get_value(point)})
.collect::<Vec<_>>(); // collect into the vector so we can (optionally) apply sorting
// now sort it (lowest value should be at the end (we use it as a stack))
vec.sort_unstable_by_key(|action| CELLS as u32 - action.value.count_ones());
return vec.iter()
.map(|action| SolverBoard::get_bitvalue_sequence().iter()
.filter(|&value| action.value & value != 0)
.map(|&value| Action{p: action.p.clone(), value})
.collect::<Vec<_>>()
)
.flatten()
.collect::<Vec<_>>();
}
Vec::new()
}
}
if let Some(point) = result { impl SolverBoardIterator {
return SolverPlayground::get_bitvalue_sequence().iter() fn new(board : &Board) -> SolverBoardIterator {
.filter(|&value| value & self.get_value(point) != 0) SolverBoardIterator::from_board(SolverBoard::from(board))
.find_map(|&value| { }
let mut spg = self.clone();
spg.rec_level += 1; fn from_board(board: SolverBoard) -> SolverBoardIterator {
spg.set_bit_value(&point, value); SolverBoardIterator{cache: HashSet::with_capacity(2048), stack: vec![SolverBoardItem::Initial(board)]}
spg.solve() }
})
fn next_board(&mut self) -> Option<SolverBoard> {
let mut result : Option<SolverBoard> = None;
while let Some(mut item) = self.stack.pop() {
if let Some(action) = item.pop_action() {
if let Some(board) = item.get_board() {
let mut new_board = board.clone();
self.stack.push(item);
new_board.apply(&action);
result = self.add_recursive(new_board);
}
} else if let Some(board) = item.get_board() { // initial
result = self.add_recursive(board.clone());
}
if result.is_some() {
return result
}
}
println!("Cache size: {}", self.cache.len());
None
}
fn add_to_cache(&mut self, board: &SolverBoard) -> Option<SolverBoard> {
if !self.cache.contains(&board.arr) {
self.cache.insert(board.arr);
return Some(board.clone())
}
None
}
fn add_recursive(&mut self, board: SolverBoard) -> Option<SolverBoard> {
if board.valid {
let result = self.add_to_cache(&board);
if result.is_some() {
let actions = board.get_all_actions();
self.stack.push(SolverBoardItem::Recursive(board, actions));
}
return result;
}
None
}
}
impl SolverBoardItem {
fn get_board(&self) -> Option<&SolverBoard> {
if let SolverBoardItem::Recursive(board, _) = self {
return Some(board)
} else if let SolverBoardItem::Initial(board) = self {
return Some(board)
}
None
}
fn pop_action(&mut self) -> Option<Action> {
if let SolverBoardItem::Recursive(_, actions) = self {
return actions.pop()
} }
None None
} }
} }
impl Iterator for SolverBoardIterator {
type Item = SolverBoard;
fn next(&mut self) -> Option<Self::Item> {
self.next_board()
}
}

@ -1,12 +1,11 @@
mod utils; mod board;
mod playground;
mod solver; mod solver;
mod mysolver; mod mysolver;
mod hecht; mod hecht;
use hecht::HechtSolver; use hecht::HechtSolver;
use playground::Playground; use board::Board;
use solver::Solver; use solver::Solver;
use clap::Parser; use clap::Parser;
@ -130,7 +129,7 @@ mod tests {
#[case(7)] #[case(7)]
#[case(8)] #[case(8)]
fn solve_sudoku(#[case] field : usize) { fn solve_sudoku(#[case] field : usize) {
let pg = Playground::from_array(&FIELDS[field]); let pg = Board::from_array(&FIELDS[field]);
let solver = HechtSolver::new(); let solver = HechtSolver::new();
let result = solver.solve(&pg); let result = solver.solve(&pg);
@ -157,7 +156,7 @@ fn main() {
let args = Args::parse(); let args = Args::parse();
let pg = Playground::from_array(&FIELDS[args.scenario as usize]); let pg = Board::from_array(&FIELDS[args.scenario as usize]);
pg.print(); pg.print();
@ -166,17 +165,24 @@ fn main() {
println!(""); println!("");
if let Some(result) = solver.solve(&pg) { if let Some(result) = solver.solve(&pg) {
result.print();
if !result.contains(&pg) { if !result.contains(&pg) {
println!("Solver modified predefined fields!") println!("Solver modified predefined fields!")
} if !result.is_valid() { } if !result.is_valid() {
println!("Solver has not correctly solved the sudoku!") println!("Solver has not correctly solved the sudoku!")
} else if !result.is_solved() { } else if !result.is_solved() {
println!("Solver was not able to solve the sudoku!") println!("Solver was not able to solve the sudoku!")
} else {
println!("Solver found a solution for this sudoku!!")
}
result.print();
if solver.is_unique(&pg) {
println!("Solver states, that this sudoku has only one solution!")
} else {
println!("Solver states, that this sudoku has multiple solutions!")
} }
assert!(result.contains(&pg));
} else { } else {
println!("Solver was not able to resolve the sodoku!") println!("Solver was not able to solve the sodoku!")
} }
} }

@ -1,5 +1,5 @@
use crate::solver::Solver; use crate::solver::Solver;
use crate::playground::Playground; use crate::board::Board;
pub struct MySolver { pub struct MySolver {
} }
@ -11,8 +11,13 @@ impl MySolver {
} }
impl Solver for MySolver { impl Solver for MySolver {
fn solve(&self, _pg: &Playground) -> Option<Playground> { fn solve(&self, _pg: &Board) -> Option<Board> {
// FIXME: Implement! // FIXME: Implement!
None None
} }
fn is_unique(&self, _ : &Board) -> bool {
// FIXME: Implement
false
}
} }

@ -1,11 +1,12 @@
use crate::playground::Playground; use crate::board::Board;
pub trait Solver { pub trait Solver {
fn solve(&self, _: &Playground) -> Option<Playground>; fn solve(&self, _: &Board) -> Option<Board>;
fn is_unique(&self, _ : &Board) -> bool;
} }
enum SodokuComplexity { pub enum SodokuComplexity {
Trivial, Trivial,
Easy, Easy,
Average, Average,
@ -15,5 +16,5 @@ enum SodokuComplexity {
} }
pub trait Generator{ pub trait Generator{
fn generate(&self, _complexity:&SodokuComplexity) -> Playground; fn generate(&self, _complexity:&SodokuComplexity) -> Board;
} }
Loading…
Cancel
Save