|
|
|
@ -1,16 +1,15 @@
|
|
|
|
|
|
|
|
|
|
use std::collections::HashMap;
|
|
|
|
|
|
|
|
|
|
use crate::solver::Solver;
|
|
|
|
|
use crate::playground::Playground;
|
|
|
|
|
use crate::utils::Locatable;
|
|
|
|
|
use crate::utils::LocatableVec;
|
|
|
|
|
use crate::utils::FsVec;
|
|
|
|
|
|
|
|
|
|
pub struct HechtSolver {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[derive(Hash, Clone, Copy, Eq, PartialEq, Debug)]
|
|
|
|
|
#[derive(Hash, Clone, Copy, Eq, PartialEq, Debug, Default)]
|
|
|
|
|
struct Point {
|
|
|
|
|
pub x: usize,
|
|
|
|
|
pub y: usize,
|
|
|
|
@ -32,8 +31,7 @@ struct Action {
|
|
|
|
|
#[derive(Clone)]
|
|
|
|
|
pub struct SolverPlayground {
|
|
|
|
|
arr: [[u16; 9]; 9],
|
|
|
|
|
// todos : HashSet<Point>,
|
|
|
|
|
todos: LocatableVec<Point>,
|
|
|
|
|
todos: LocatableVec<Point, 81>,
|
|
|
|
|
valid: bool,
|
|
|
|
|
rec_level: usize,
|
|
|
|
|
}
|
|
|
|
@ -54,15 +52,13 @@ impl Solver for HechtSolver {
|
|
|
|
|
impl SolverPlayground {
|
|
|
|
|
|
|
|
|
|
pub fn new(pg: &Playground) -> SolverPlayground {
|
|
|
|
|
let mut points : LocatableVec<Point> = LocatableVec::new();
|
|
|
|
|
for x in 0..9 {
|
|
|
|
|
for y in 0..9 {
|
|
|
|
|
points.put(Point{x, y, s: y / 3 * 3 + x / 3});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
let points : LocatableVec<_, 81> = [0usize..81].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();
|
|
|
|
|
|
|
|
|
|
let mut spg = SolverPlayground { arr: [[0x1FFu16; 9]; 9], todos: points.clone(), valid: true, rec_level: 0};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for p in points.iter() {
|
|
|
|
|
if let Some(value) = pg.get_value(p.x, p.y) {
|
|
|
|
|
spg.set_value(&p, value);
|
|
|
|
@ -75,15 +71,14 @@ impl SolverPlayground {
|
|
|
|
|
fn to_playground(&self) -> Option<Playground> {
|
|
|
|
|
let mut pg = Playground::new();
|
|
|
|
|
|
|
|
|
|
let bitmap = SolverPlayground::get_bitvalue_mapping();
|
|
|
|
|
|
|
|
|
|
for x in 0..9 {
|
|
|
|
|
for y in 0..9 {
|
|
|
|
|
let value = self.arr[y][x];
|
|
|
|
|
if value == 0 {
|
|
|
|
|
if value.count_ones() != 1 {
|
|
|
|
|
return None
|
|
|
|
|
}
|
|
|
|
|
pg.set_value(x, y, *bitmap.get(&value).unwrap_or(&0u8));
|
|
|
|
|
|
|
|
|
|
pg.set_value(x, y, (value.trailing_zeros() + 1) as u8);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -92,13 +87,10 @@ impl SolverPlayground {
|
|
|
|
|
|
|
|
|
|
pub fn solve(&mut self) -> Option<Playground> {
|
|
|
|
|
while self.valid && self.todos.len() > 0 {
|
|
|
|
|
let actions = self.get_simple_action();
|
|
|
|
|
if actions.len() == 0 {
|
|
|
|
|
return self.get_complex_action();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for action in actions {
|
|
|
|
|
if let Some(action) = self.get_simple_action() {
|
|
|
|
|
self.apply(&action);
|
|
|
|
|
} else {
|
|
|
|
|
return self.get_complex_action();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -118,19 +110,16 @@ impl SolverPlayground {
|
|
|
|
|
|
|
|
|
|
self.arr[p.y][p.x] = bit_value;
|
|
|
|
|
|
|
|
|
|
let toprocess : Vec::<_> = self.todos.iter()
|
|
|
|
|
self.todos.iter()
|
|
|
|
|
// Filter positions that do not have the right coordinates
|
|
|
|
|
.filter(|&pos| pos.x == p.x || pos.y == p.y || pos.s == p.s)
|
|
|
|
|
// Filter positions that were known not to hold the value
|
|
|
|
|
.filter(|&pos| (self.arr[pos.y][pos.x] & bit_value) != 0)
|
|
|
|
|
.cloned()
|
|
|
|
|
.collect();
|
|
|
|
|
|
|
|
|
|
toprocess.iter().next();
|
|
|
|
|
.collect::<FsVec::<_,81>>()
|
|
|
|
|
.iter()
|
|
|
|
|
.for_each(|pos| self.remove_value(&pos, bit_value));
|
|
|
|
|
|
|
|
|
|
for pos in toprocess {
|
|
|
|
|
self.remove_value(&pos, bit_value);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn remove_value(&mut self, p : &Point, bit_value: u16) {
|
|
|
|
@ -170,27 +159,16 @@ impl SolverPlayground {
|
|
|
|
|
0b1_0000_0000u16]; // 9
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
fn get_bitvalue_mapping() -> HashMap<u16, u8> {
|
|
|
|
|
let sequence = SolverPlayground::get_bitvalue_sequence();
|
|
|
|
|
let mut result : HashMap<u16, u8> = HashMap::with_capacity(sequence.len());
|
|
|
|
|
|
|
|
|
|
for (index, value) in sequence.iter().enumerate() {
|
|
|
|
|
result.insert(*value, (index + 1) as u8);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
result
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
fn get_value(&self, p : &Point) -> u16 {
|
|
|
|
|
return self.arr[p.y][p.x];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn get_simple_action(&self) -> Vec<Action> {
|
|
|
|
|
fn get_simple_action(&self) -> Option<Action> {
|
|
|
|
|
|
|
|
|
|
// println!("Simple Action");
|
|
|
|
|
self.todos.iter()
|
|
|
|
|
.filter_map(|lhs| {
|
|
|
|
|
.find_map(|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)
|
|
|
|
@ -210,7 +188,6 @@ impl SolverPlayground {
|
|
|
|
|
.filter(|value| value.count_ones() == 1)
|
|
|
|
|
.find_map(|value| SolverPlayground::create_action(lhs, value))
|
|
|
|
|
} )
|
|
|
|
|
.collect()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn get_complex_action(&self) -> Option<Playground> {
|
|
|
|
|