|
|
|
@ -1,39 +1,57 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
use std::collections::HashSet;
|
|
|
|
|
use crate::solver::Solver;
|
|
|
|
|
use crate::playground::Playground;
|
|
|
|
|
use crate::utils::Locatable;
|
|
|
|
|
use crate::utils::LocatableVec;
|
|
|
|
|
use crate::utils::FsVec;
|
|
|
|
|
use crate::board::Board;
|
|
|
|
|
use std::hash::{Hash, Hasher};
|
|
|
|
|
use std::ops::ControlFlow;
|
|
|
|
|
|
|
|
|
|
static CELLS : usize = 81;
|
|
|
|
|
|
|
|
|
|
pub struct HechtSolver {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[derive(Hash, Clone, Copy, Eq, PartialEq, Debug, Default)]
|
|
|
|
|
#[derive(Hash, Clone, Eq, PartialEq, Debug)]
|
|
|
|
|
struct Point {
|
|
|
|
|
pub x: usize,
|
|
|
|
|
pub y: usize,
|
|
|
|
|
pub s: usize,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Locatable for Point {
|
|
|
|
|
fn get_xy(&self) -> (usize, usize) {
|
|
|
|
|
(self.x,self.y)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
|
struct Action {
|
|
|
|
|
pub p : Point,
|
|
|
|
|
pub value: u16
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Clone)]
|
|
|
|
|
pub struct SolverPlayground {
|
|
|
|
|
#[derive(Clone, Eq)]
|
|
|
|
|
struct SolverBoard {
|
|
|
|
|
arr: [[u16; 9]; 9],
|
|
|
|
|
todos: LocatableVec<Point, 81>,
|
|
|
|
|
todos: HashSet<Point>,
|
|
|
|
|
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 {
|
|
|
|
@ -43,33 +61,55 @@ impl HechtSolver {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Solver for HechtSolver {
|
|
|
|
|
fn solve(&self, pg: &Playground) -> Option<Playground> {
|
|
|
|
|
SolverPlayground::new(&pg)
|
|
|
|
|
.solve()
|
|
|
|
|
fn solve(&self, pg: &Board) -> Option<Board> {
|
|
|
|
|
SolverBoardIterator::new(pg)
|
|
|
|
|
.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 {
|
|
|
|
|
let points : LocatableVec<_, 81> = [0usize..81].into_iter().flatten()
|
|
|
|
|
pub fn new() -> SolverBoard {
|
|
|
|
|
let points = [0usize..CELLS].into_iter().flatten()
|
|
|
|
|
.map(|idx| [idx%9, idx/9])
|
|
|
|
|
.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}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for p in points.iter() {
|
|
|
|
|
pub fn from(pg: &Board) -> SolverBoard {
|
|
|
|
|
let mut spg = SolverBoard::new();
|
|
|
|
|
|
|
|
|
|
for p in spg.todos.clone().iter() {
|
|
|
|
|
if let Some(value) = pg.get_value(p.x, p.y) {
|
|
|
|
|
spg.set_value(&p, value);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
spg.solve_logically();
|
|
|
|
|
|
|
|
|
|
spg
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn to_playground(&self) -> Option<Playground> {
|
|
|
|
|
let mut pg = Playground::new();
|
|
|
|
|
fn to_board(&self) -> Option<Board> {
|
|
|
|
|
let mut pg = Board::new();
|
|
|
|
|
|
|
|
|
|
for x in 0..9 {
|
|
|
|
|
for y in 0..9 {
|
|
|
|
@ -85,16 +125,18 @@ impl SolverPlayground {
|
|
|
|
|
Some(pg)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn solve(&mut self) -> Option<Playground> {
|
|
|
|
|
while self.valid && self.todos.len() > 0 {
|
|
|
|
|
fn solve_logically(&mut self) {
|
|
|
|
|
while self.valid {
|
|
|
|
|
if let Some(action) = self.get_simple_action() {
|
|
|
|
|
self.apply(&action);
|
|
|
|
|
self.set_bit_value(&action.p, action.value);
|
|
|
|
|
} 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) {
|
|
|
|
@ -116,7 +158,7 @@ impl SolverPlayground {
|
|
|
|
|
// Filter positions that were known not to hold the value
|
|
|
|
|
.filter(|&pos| (self.arr[pos.y][pos.x] & bit_value) != 0)
|
|
|
|
|
.cloned()
|
|
|
|
|
.collect::<FsVec::<_,81>>()
|
|
|
|
|
.collect::<Vec::<_>>()
|
|
|
|
|
.iter()
|
|
|
|
|
.for_each(|pos| self.remove_value(&pos, bit_value));
|
|
|
|
|
|
|
|
|
@ -128,8 +170,8 @@ impl SolverPlayground {
|
|
|
|
|
}
|
|
|
|
|
self.arr[p.y][p.x] &= !bit_value;
|
|
|
|
|
|
|
|
|
|
if let Some(action) = SolverPlayground::create_action(p, self.arr[p.y][p.x]) {
|
|
|
|
|
self.apply(&action);
|
|
|
|
|
if let Some(action) = SolverBoard::create_action(p, self.arr[p.y][p.x]) {
|
|
|
|
|
self.set_bit_value(&action.p, action.value);
|
|
|
|
|
} else if self.arr[p.y][p.x] == 0 {
|
|
|
|
|
self.valid = false;
|
|
|
|
|
}
|
|
|
|
@ -144,6 +186,7 @@ impl SolverPlayground {
|
|
|
|
|
|
|
|
|
|
fn apply(&mut self, action : &Action) {
|
|
|
|
|
self.set_bit_value(&action.p, action.value);
|
|
|
|
|
self.solve_logically();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
@ -169,11 +212,11 @@ impl SolverPlayground {
|
|
|
|
|
// println!("Simple Action");
|
|
|
|
|
self.todos.iter()
|
|
|
|
|
.find_map(|lhs| {
|
|
|
|
|
let own_value = self.get_value(&lhs);
|
|
|
|
|
let own_value = self.get_value(lhs);
|
|
|
|
|
self.todos.iter()
|
|
|
|
|
.filter(|&rhs| lhs.x == rhs.x || lhs.y == rhs.y || lhs.s == rhs.s)
|
|
|
|
|
.filter(|&rhs| lhs != rhs)
|
|
|
|
|
.map(|&rhs| {
|
|
|
|
|
.map(|rhs| {
|
|
|
|
|
let value = self.get_value(&rhs) & own_value;
|
|
|
|
|
let row_value = if lhs.x == rhs.x {value} else {0};
|
|
|
|
|
let col_value = if lhs.y == rhs.y {value} else {0};
|
|
|
|
@ -186,26 +229,111 @@ impl SolverPlayground {
|
|
|
|
|
.flatten()
|
|
|
|
|
.map(|value| value ^ own_value)
|
|
|
|
|
.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> {
|
|
|
|
|
// println!("Complex Action");
|
|
|
|
|
let result = self.todos.iter()
|
|
|
|
|
.min_by_key(|x| self.get_value(x).count_ones());
|
|
|
|
|
fn get_all_actions(&self) -> Vec<Action> {
|
|
|
|
|
if self.valid && !self.is_solved() {
|
|
|
|
|
let mut vec = self.todos.iter()
|
|
|
|
|
.map(|point| Action{p: point.clone(), value: self.get_value(point)})
|
|
|
|
|
.collect::<Vec<_>>(); // collect into the vector so we can (optionally) apply sorting
|
|
|
|
|
|
|
|
|
|
if let Some(point) = result {
|
|
|
|
|
return SolverPlayground::get_bitvalue_sequence().iter()
|
|
|
|
|
.filter(|&value| value & self.get_value(point) != 0)
|
|
|
|
|
.find_map(|&value| {
|
|
|
|
|
let mut spg = self.clone();
|
|
|
|
|
spg.rec_level += 1;
|
|
|
|
|
spg.set_bit_value(&point, value);
|
|
|
|
|
spg.solve()
|
|
|
|
|
})
|
|
|
|
|
// 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()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl SolverBoardIterator {
|
|
|
|
|
fn new(board : &Board) -> SolverBoardIterator {
|
|
|
|
|
SolverBoardIterator::from_board(SolverBoard::from(board))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn from_board(board: SolverBoard) -> SolverBoardIterator {
|
|
|
|
|
SolverBoardIterator{cache: HashSet::with_capacity(2048), stack: vec![SolverBoardItem::Initial(board)]}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Iterator for SolverBoardIterator {
|
|
|
|
|
type Item = SolverBoard;
|
|
|
|
|
|
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
|
|
|
self.next_board()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|