You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

212 lines
6.1 KiB

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, Default)]
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: LocatableVec<Point, 81>,
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 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);
}
}
spg
}
fn to_playground(&self) -> Option<Playground> {
let mut pg = Playground::new();
for x in 0..9 {
for y in 0..9 {
let value = self.arr[y][x];
if value.count_ones() != 1 {
return None
}
pg.set_value(x, y, (value.trailing_zeros() + 1) as u8);
}
}
Some(pg)
}
pub fn solve(&mut self) -> Option<Playground> {
while self.valid && self.todos.len() > 0 {
if let Some(action) = self.get_simple_action() {
self.apply(&action);
} else {
return self.get_complex_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;
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::<FsVec::<_,81>>()
.iter()
.for_each(|pos| 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_value(&self, p : &Point) -> u16 {
return self.arr[p.y][p.x];
}
fn get_simple_action(&self) -> Option<Action> {
// println!("Simple Action");
self.todos.iter()
.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)
.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))
} )
}
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
}
}