parent
830cc81bc9
commit
d16676c4c4
@ -0,0 +1,234 @@
|
|||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use crate::solver::Solver;
|
||||||
|
use crate::playground::Playground;
|
||||||
|
use crate::utils::Locatable;
|
||||||
|
use crate::utils::LocatableVec;
|
||||||
|
|
||||||
|
pub struct HechtSolver {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Hash, Clone, Copy, 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 {
|
||||||
|
arr: [[u16; 9]; 9],
|
||||||
|
// todos : HashSet<Point>,
|
||||||
|
todos: LocatableVec<Point>,
|
||||||
|
valid: bool,
|
||||||
|
rec_level: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HechtSolver {
|
||||||
|
pub fn new() -> HechtSolver {
|
||||||
|
return HechtSolver {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Solver for HechtSolver {
|
||||||
|
fn solve(&self, pg: &Playground) -> Option<Playground> {
|
||||||
|
SolverPlayground::new(&pg)
|
||||||
|
.solve()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
spg
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
return None
|
||||||
|
}
|
||||||
|
pg.set_value(x, y, *bitmap.get(&value).unwrap_or(&0u8));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(pg)
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
self.apply(&action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.to_playground()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_value(&mut self, p : &Point, value : u8) {
|
||||||
|
let bit_value = 1u16 << (value - 1);
|
||||||
|
self.set_bit_value(p, bit_value)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_bit_value(&mut self, p : &Point, bit_value : u16) {
|
||||||
|
if !self.todos.remove(p) {
|
||||||
|
// Point was not in todo-list -> no further action required
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.arr[p.y][p.x] = bit_value;
|
||||||
|
|
||||||
|
let toprocess : Vec::<_> = 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();
|
||||||
|
|
||||||
|
for pos in toprocess {
|
||||||
|
self.remove_value(&pos, bit_value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn remove_value(&mut self, p : &Point, bit_value: u16) {
|
||||||
|
if (self.get_value(p) & bit_value) == 0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
} else if self.arr[p.y][p.x] == 0 {
|
||||||
|
self.valid = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_action(p : &Point, bit_value: u16) -> Option<Action> {
|
||||||
|
if bit_value.count_ones() != 1 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Some(Action{p : p.clone(), value : bit_value})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply(&mut self, action : &Action) {
|
||||||
|
self.set_bit_value(&action.p, action.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn get_bitvalue_sequence() -> &'static[u16; 9] {
|
||||||
|
return &[0b0_0000_0001u16, // 1
|
||||||
|
0b0_0000_0010u16, // 2
|
||||||
|
0b0_0000_0100u16, // 3
|
||||||
|
0b0_0000_1000u16, // 4
|
||||||
|
0b0_0001_0000u16, // 5
|
||||||
|
0b0_0010_0000u16, // 6
|
||||||
|
0b0_0100_0000u16, // 7
|
||||||
|
0b0_1000_0000u16, // 8
|
||||||
|
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> {
|
||||||
|
// println!("Simple Action");
|
||||||
|
self.todos.iter()
|
||||||
|
.filter_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)
|
||||||
|
.filter(|&rhs| lhs != 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};
|
||||||
|
let sec_value = if lhs.s == rhs.s {value} else {0};
|
||||||
|
|
||||||
|
[row_value, col_value, sec_value]
|
||||||
|
} )
|
||||||
|
.reduce(|a,b| [a[0]|b[0], a[1]|b[1], a[2]|b[2]])
|
||||||
|
.iter()
|
||||||
|
.flatten()
|
||||||
|
.map(|value| value ^ own_value)
|
||||||
|
.filter(|value| value.count_ones() == 1)
|
||||||
|
.find_map(|value| SolverPlayground::create_action(lhs, value))
|
||||||
|
} )
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
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());
|
||||||
|
|
||||||
|
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()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,72 @@
|
|||||||
|
|
||||||
|
|
||||||
|
pub trait Locatable {
|
||||||
|
fn get_xy(&self) -> (usize, usize);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait LocatableFactory<T:Locatable> {
|
||||||
|
fn create(x:usize, y:usize) -> T;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct LocatableVec<T:Locatable + std::marker::Copy> {
|
||||||
|
arr: [Option<T>; 81],
|
||||||
|
len: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct LocatableVecIter<'a, T:Locatable + std::marker::Copy> {
|
||||||
|
vec : &'a LocatableVec<T>,
|
||||||
|
idx: usize,
|
||||||
|
} // (&'a LocatableVec<T>, usize);
|
||||||
|
|
||||||
|
|
||||||
|
impl<T:Locatable + std::marker::Copy> LocatableVec<T> {
|
||||||
|
|
||||||
|
pub fn new() -> LocatableVec<T> {
|
||||||
|
LocatableVec{arr: [None; 81], len: 0}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn iter(&self) -> LocatableVecIter<'_, T> {
|
||||||
|
LocatableVecIter{vec: self, idx: 0}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
self.len
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn put(&mut self, value : T) {
|
||||||
|
let (x,y) = value.get_xy();
|
||||||
|
let idx = y * 9 + x;
|
||||||
|
if self.arr[idx].is_none() {
|
||||||
|
self.len += 1;
|
||||||
|
}
|
||||||
|
self.arr[idx] = Some(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove(&mut self, value : &T) -> bool{
|
||||||
|
let (x,y) = value.get_xy();
|
||||||
|
let idx = y * 9 + x;
|
||||||
|
if self.arr[idx].is_some() {
|
||||||
|
self.arr[idx] = None;
|
||||||
|
self.len -= 1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T:Locatable + std::marker::Copy> Iterator for LocatableVecIter<'a, T> {
|
||||||
|
type Item = &'a T;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
for i in self.idx..self.vec.arr.len() {
|
||||||
|
let pos = &self.vec.arr[i];
|
||||||
|
if pos.is_some() {
|
||||||
|
self.idx = i + 1;
|
||||||
|
return pos.as_ref();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in new issue