Applied some fixes

master
Hecht 2 years ago
parent 13643c2df3
commit a47cf2e7e4

@ -1,7 +1,7 @@
use std::collections::HashSet; use std::collections::HashSet;
#[derive(Clone)] #[derive(Clone, Hash, PartialEq, Eq)]
pub struct Board { pub struct Board {
arr: [[u8; 9]; 9] arr: [[u8; 9]; 9]
} }

@ -1,44 +1,53 @@
use std::collections::HashSet; use std::collections::HashSet;
use crate::solver::Solver; use crate::solver::{Solver, Generator, SodokuComplexity};
use crate::board::Board; use crate::board::Board;
use crate::utils::*;
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
use std::ops::ControlFlow;
static CELLS : usize = 81; const NUM : usize = 3;
const VALUES : usize = NUM * NUM;
const CELLS : usize = VALUES * VALUES;
type TodoType<T> = IndexableVec<T, CELLS>;
// type TodoType<T> = HashSet<T>;
pub struct HechtSolver { pub struct HechtSolver {
} }
#[derive(Hash, Clone, Eq, PartialEq, Debug)] #[derive(Hash, Clone, Eq, PartialEq, Debug, Copy)]
struct Point { struct Point {
pub x: usize, pub x: usize,
pub y: usize, pub y: usize,
pub s: usize, pub s: usize,
} }
#[derive(Debug)] #[derive(Debug, Clone)]
struct Action { enum Action {
pub p : Point, Trivial(Point, u16),
pub value: u16 Logic(Point, u16),
Probe(Point, u16),
} }
#[derive(Clone, Eq)]
#[derive(Clone)]
struct SolverBoard { struct SolverBoard {
arr: [[u16; 9]; 9], arr: [[u16; VALUES]; VALUES],
todos: HashSet<Point>, todos: TodoType<Point>,
valid: bool, valid: bool,
audit: Vec<Action>,
} }
enum SolverBoardItem { enum SolverBoardItem {
Recursive(SolverBoard, Vec<Action>), Recursive(Vec<Action>),
Initial(SolverBoard), Initial,
} }
struct SolverBoardIterator { struct SolverBoardIterator {
cache: HashSet<[[u16; 9]; 9]>, // to avoid processing the same board twice cache: HashSet<[[u16; VALUES]; VALUES]>, // to avoid processing the same board twice
board: SolverBoard,
stack: Vec<SolverBoardItem>, stack: Vec<SolverBoardItem>,
} }
@ -58,52 +67,79 @@ impl HechtSolver {
pub fn new() -> HechtSolver { pub fn new() -> HechtSolver {
return HechtSolver {}; return HechtSolver {};
} }
pub fn test(&self, board: &Board) -> bool {
let mut invalid_counter = 0;
let mut unsolved_counter = 0;
let mut solved_counter = 0;
SolverBoardIterator::new(board)
.inspect(|_| invalid_counter += 1)
.filter(|x| x.valid)
.inspect(|_| unsolved_counter += 1)
.filter(|x| x.is_solved())
.inspect(|_| solved_counter += 1)
.inspect(|x| x.to_board().unwrap().print() )
.nth(1024).and_then(|_| {println!("I: {}, U: {}, S: {}", invalid_counter, unsolved_counter, solved_counter); Some(true)})
.is_some()
}
} }
impl Solver for HechtSolver { impl Solver for HechtSolver {
fn solve(&self, pg: &Board) -> Option<Board> { fn solve(&self, board: &Board) -> Option<Board> {
SolverBoardIterator::new(pg) SolverBoardIterator::new(board)
.find(|x| x.is_solved()) .find(|x| x.is_solved())
.map(|x| x.to_board()) .map(|x| x.to_board())
.flatten() .flatten()
} }
fn is_unique(&self, pg: &Board) -> bool { fn is_unique(&self, board: &Board) -> bool {
let first_solution = SolverBoard::new(); SolverBoardIterator::new(board)
SolverBoardIterator::new(pg)
.filter(|x| x.is_solved()) .filter(|x| x.is_solved())
.try_fold(first_solution, |prev, x| { .nth(1).is_none()
if !prev.is_solved() || prev == x {
ControlFlow::Continue(x)
} else {
ControlFlow::Break(prev)
} }
}).is_continue()
} }
impl Generator for HechtSolver {
fn generate(&self, _complexity:SodokuComplexity) -> Board {
let board = Board::new();
SolverBoardIterator::new(&board)
.filter_map(|x| x.to_board())
.filter(|board| self.is_unique(board))
.next()
.unwrap_or(board)
}
} }
impl SolverBoard { impl SolverBoard {
pub fn new() -> SolverBoard { pub fn new() -> SolverBoard {
let points = [0usize..CELLS].into_iter().flatten() let points = [0usize..CELLS].into_iter().flatten()
.map(|idx| [idx%9, idx/9]) .map(|idx| Point::from_index(idx))
.map(|p| Point{x: p[0], y:p[1], s: p[1] / 3 * 3 + p[0] / 3}) .collect::<TodoType<_>>();
.collect::<HashSet<_>>();
SolverBoard { arr: [[0x1FFu16; 9]; 9], todos: points, valid: true} SolverBoard { arr: [[0x1FFu16; VALUES]; VALUES], todos: points, valid: true, audit: Vec::new()}
} }
pub fn from(pg: &Board) -> SolverBoard { pub fn from(pg: &Board) -> SolverBoard {
let mut spg = SolverBoard::new(); let mut spg = SolverBoard::new();
for p in spg.todos.clone().iter() { for idx in 0usize..CELLS {
let p = Point::from_index(idx);
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);
assert!(spg.valid);
} }
} }
spg.solve_logically(); spg.solve_logically();
assert!(spg.valid);
spg spg
} }
@ -111,8 +147,8 @@ impl SolverBoard {
fn to_board(&self) -> Option<Board> { fn to_board(&self) -> Option<Board> {
let mut pg = Board::new(); let mut pg = Board::new();
for x in 0..9 { for x in 0..VALUES {
for y in 0..9 { for y in 0..VALUES {
let value = self.arr[y][x]; let value = self.arr[y][x];
if value.count_ones() != 1 { if value.count_ones() != 1 {
return None return None
@ -128,7 +164,7 @@ impl SolverBoard {
fn solve_logically(&mut self) { fn solve_logically(&mut self) {
while self.valid { while self.valid {
if let Some(action) = self.get_simple_action() { if let Some(action) = self.get_simple_action() {
self.set_bit_value(&action.p, action.value); self.apply(&action);
} else { } else {
break; break;
} }
@ -144,7 +180,33 @@ impl SolverBoard {
self.set_bit_value(p, bit_value) self.set_bit_value(p, bit_value)
} }
fn get_sector(index : usize) -> usize {
static SECTOR_ARRAY : [usize; CELLS] = [
0,0,0,1,1,1,2,2,2,
0,0,0,1,1,1,2,2,2,
0,0,0,1,1,1,2,2,2,
3,3,3,4,4,4,5,5,5,
3,3,3,4,4,4,5,5,5,
3,3,3,4,4,4,5,5,5,
6,6,6,7,7,7,8,8,8,
6,6,6,7,7,7,8,8,8,
6,6,6,7,7,7,8,8,8,
];
SECTOR_ARRAY[index]
}
#[inline]
fn get_y(index : usize) -> usize {
index / VALUES
}
#[inline]
fn get_x(index : usize) -> usize {
index % VALUES
}
fn set_bit_value(&mut self, p : &Point, bit_value : u16) { fn set_bit_value(&mut self, p : &Point, bit_value : u16) {
assert!(bit_value.count_ones() == 1);
if !self.todos.remove(p) { if !self.todos.remove(p) {
// Point was not in todo-list -> no further action required // Point was not in todo-list -> no further action required
return; return;
@ -152,28 +214,36 @@ impl SolverBoard {
self.arr[p.y][p.x] = bit_value; self.arr[p.y][p.x] = bit_value;
self.todos.iter() // self.todos.iter()
// Filter positions that do not have the right coordinates // // Filter positions that do not have the right coordinates
.filter(|&pos| pos.x == p.x || pos.y == p.y || pos.s == p.s) // .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 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::<Vec::<_>>() // .collect::<Vec::<_>>()
.iter() // .iter()
.for_each(|pos| self.remove_value(&pos, bit_value)); // .for_each(|pos| self.remove_value(&pos, bit_value));
for idx in 0..CELLS {
let other = Point::from_index(idx);
if p != &other && (other.x == p.x || other.y == p.y || other.s == p.s) {
self.remove_value(other, bit_value)
}
}
} }
fn remove_value(&mut self, p : &Point, bit_value: u16) { fn remove_value(&mut self, p : Point, bit_value: u16) {
if (self.get_value(p) & bit_value) == 0 { if (self.arr[p.y][p.x] & bit_value) == 0 {
return; return;
} }
self.arr[p.y][p.x] &= !bit_value; self.arr[p.y][p.x] &= !bit_value;
let point_value = self.arr[p.y][p.x];
if let Some(action) = SolverBoard::create_action(p, self.arr[p.y][p.x]) { match point_value.count_ones() {
self.set_bit_value(&action.p, action.value); 1 => self.apply(&Action::Trivial(p, point_value)),
} else if self.arr[p.y][p.x] == 0 { 0 => self.valid = false,
self.valid = false; _ => {}
} }
} }
@ -181,16 +251,23 @@ impl SolverBoard {
if bit_value.count_ones() != 1 { if bit_value.count_ones() != 1 {
return None; return None;
} }
Some(Action{p : p.clone(), value : bit_value}) Some(Action::Logic(p.clone(), bit_value))
} }
fn apply(&mut self, action : &Action) { fn apply(&mut self, action : &Action) {
self.set_bit_value(&action.p, action.value); let (point, value) = action.get();
self.set_bit_value(point, value);
if let Action::Probe(_,_) = action {
self.solve_logically(); self.solve_logically();
} }
self.audit.push(action.clone());
}
#[inline] #[inline]
fn get_bitvalue_sequence() -> &'static[u16; 9] { fn get_bitvalue_sequence() -> &'static[u16; VALUES] {
return &[0b0_0000_0001u16, // 1 return &[0b0_0000_0001u16, // 1
0b0_0000_0010u16, // 2 0b0_0000_0010u16, // 2
0b0_0000_0100u16, // 3 0b0_0000_0100u16, // 3
@ -236,16 +313,16 @@ impl SolverBoard {
fn get_all_actions(&self) -> Vec<Action> { fn get_all_actions(&self) -> Vec<Action> {
if self.valid && !self.is_solved() { if self.valid && !self.is_solved() {
let mut vec = self.todos.iter() let mut vec = self.todos.iter()
.map(|point| Action{p: point.clone(), value: self.get_value(point)}) .map(|point| (point, self.get_value(point)))
.collect::<Vec<_>>(); // collect into the vector so we can (optionally) apply sorting .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)) // 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()); vec.sort_unstable_by_key(|action| CELLS as u32 - action.1.count_ones());
return vec.iter() return vec.iter()
.map(|action| SolverBoard::get_bitvalue_sequence().iter() .map(|action| SolverBoard::get_bitvalue_sequence().iter()
.filter(|&value| action.value & value != 0) .filter(|&value| (action.1 & value) != 0)
.map(|&value| Action{p: action.p.clone(), value}) .map(|&value| Action::Probe(action.0.clone(), value))
.collect::<Vec<_>>() .collect::<Vec<_>>()
) )
.flatten() .flatten()
@ -262,70 +339,96 @@ impl SolverBoardIterator {
} }
fn from_board(board: SolverBoard) -> SolverBoardIterator { fn from_board(board: SolverBoard) -> SolverBoardIterator {
SolverBoardIterator{cache: HashSet::with_capacity(2048), stack: vec![SolverBoardItem::Initial(board)]} SolverBoardIterator{cache: HashSet::with_capacity(128), board, stack: vec![SolverBoardItem::Initial]}
} }
fn next_board(&mut self) -> Option<SolverBoard> { fn next_board(&mut self) -> Option<SolverBoard> {
let mut result : Option<SolverBoard> = None; let mut result;
while let Some(mut item) = self.stack.pop() { while let Some(item) = self.stack.pop() {
if let Some(action) = item.pop_action() { if let SolverBoardItem::Recursive(actions) = item {
if let Some(board) = item.get_board() { result = self.push_actions(&actions);
let mut new_board = board.clone(); } else {
self.stack.push(item); // initial
new_board.apply(&action); result = self.push_actions(&Vec::new());
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() { if result.is_some() {
return result return result;
} }
} }
println!("Cache size: {}", self.cache.len());
None None
} }
fn add_to_cache(&mut self, board: &SolverBoard) -> Option<SolverBoard> { fn push_actions(&mut self, actions: &Vec<Action>) -> Option<SolverBoard> {
if !self.cache.contains(&board.arr) { if self.already_processed(actions) {
self.cache.insert(board.arr); println!("Early hit! Stack: {}, Cache: {}", self.stack.len(), self.cache.len());
return Some(board.clone()) return None;
}
let mut new_board = self.board.clone();
let mut iter = actions.iter().peekable();
let mut arr_backup : Option<[[u16; VALUES]; VALUES]>= None;
while let Some(action) = iter.next() {
if iter.peek().is_some() {
new_board.apply(&action);
} else {
arr_backup = Some(new_board.arr);
new_board.apply(&action);
} }
None
} }
fn add_recursive(&mut self, board: SolverBoard) -> Option<SolverBoard> { if !new_board.valid {
if board.valid { if let Some(mut arr) = arr_backup {
let result = self.add_to_cache(&board); if let Some(action) = actions.last() {
if result.is_some() { let (point, value) = action.get();
let actions = board.get_all_actions(); arr[point.y][point.x] = value;
self.stack.push(SolverBoardItem::Recursive(board, actions)); self.insert_to_cache(arr);
} }
return result;
} }
None return None
} }
if self.insert_to_cache(new_board.arr) {
if !new_board.is_solved() {
let mut actions_copy = actions.to_vec();
for action in new_board.get_all_actions() {
actions_copy.push(action);
self.stack.push(SolverBoardItem::Recursive(actions_copy.to_vec()));
actions_copy.pop();
} }
}
impl SolverBoardItem { return Some(new_board);
} else {
fn get_board(&self) -> Option<&SolverBoard> { println!("Late hit! Stack: {}, Cache: {}", self.stack.len(), self.cache.len())
if let SolverBoardItem::Recursive(board, _) = self {
return Some(board)
} else if let SolverBoardItem::Initial(board) = self {
return Some(board)
} }
None None
} }
fn pop_action(&mut self) -> Option<Action> { /**
if let SolverBoardItem::Recursive(_, actions) = self { * Check if we can find a board in the cache, where all actions in the
return actions.pop() * vector have been applied.
*/
fn already_processed(&mut self, actions : &Vec<Action>) -> bool {
for board in self.cache.iter() {
let applied = actions.iter()
.map(|a| a.get())
.all(|a| board[a.0.y][a.0.x] == a.1);
if applied {
return true
} }
None }
false
}
fn insert_to_cache(&mut self, mut array : [[u16; VALUES]; VALUES]) -> bool {
for x in array.iter_mut()
.flatten()
.filter(|value| value.count_ones() != 1) {
*x = 0;
}
self.cache.insert(array)
} }
} }
@ -335,5 +438,29 @@ impl Iterator for SolverBoardIterator {
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
self.next_board() self.next_board()
} }
}
impl Action {
fn get(&self) -> (&Point, u16) {
match self {
Action::Logic(point,value) | Action::Probe(point,value) | Action::Trivial(point,value) => return (point, *value)
}
} }
}
impl Indexable for Point {
fn to_index(&self) -> usize {
self.y * VALUES + self.x
}
}
impl Point {
fn from_xy(x: usize, y: usize) -> Point {
Point{x, y, s: (y / NUM) * NUM + x / NUM}
}
fn from_index(idx: usize) -> Point {
Point{x: SolverBoard::get_x(idx), y: SolverBoard::get_y(idx), s: SolverBoard::get_sector(idx)}
}
}

@ -3,13 +3,14 @@ mod board;
mod solver; mod solver;
mod mysolver; mod mysolver;
mod hecht; mod hecht;
mod utils;
use hecht::HechtSolver; use hecht::HechtSolver;
use board::Board; use board::Board;
use solver::Solver; use solver::{Solver, Generator, SodokuComplexity};
use clap::Parser; use clap::{Parser, Subcommand};
static FIELDS: [[u8;81];9] = static FIELDS: [[u8;81];10] =
[ [
[ [
0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,
@ -109,6 +110,17 @@ static FIELDS: [[u8;81];9] =
8,0,0,0,3,0,9,0,0, 8,0,0,0,3,0,9,0,0,
9,0,0,4,0,0,0,8,0, 9,0,0,4,0,0,0,8,0,
1,0,0,6,0,9,0,0,5 1,0,0,6,0,9,0,0,5
],
[ // Cannot be solved!
1,7,3,0,0,0,0,4,0,
0,0,0,0,0,0,9,0,5,
0,5,9,6,7,0,0,0,0,
0,2,0,0,8,0,0,0,7,
0,0,1,0,0,0,8,2,6,
7,0,0,0,0,0,0,0,1,
0,0,0,1,0,3,0,0,0,
0,0,0,2,5,0,0,0,0,
0,4,0,0,0,0,0,8,3
] ]
]; ];
@ -119,28 +131,72 @@ mod tests {
use rstest::*; use rstest::*;
#[rstest] #[rstest]
#[case(0)] #[case(0, true)]
#[case(1)] #[case(1, true)]
#[case(2)] #[case(2, true)]
#[case(3)] #[case(3, true)]
#[case(4)] #[case(4, true)]
#[case(5)] #[case(5, true)]
#[case(6)] #[case(6, true)]
#[case(7)] #[case(7, true)]
#[case(8)] #[case(8, true)]
fn solve_sudoku(#[case] field : usize) { #[case(9, false)]
fn solve_sudoku(#[case] field : usize, #[case] valid : bool) {
let pg = Board::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);
assert!(result.is_some()); assert!(result.is_some() == valid);
if valid {
let result_pg = result.unwrap(); let result_pg = result.unwrap();
assert!(result_pg.is_valid()); assert!(result_pg.is_valid());
assert!(result_pg.is_solved()); assert!(result_pg.is_solved());
assert!(result_pg.contains(&pg)); assert!(result_pg.contains(&pg));
} }
}
#[rstest]
#[case(0, true)]
#[case(1, false)]
#[case(2, false)]
#[case(3, false)]
#[case(4, false)]
#[case(5, false)]
#[case(6, true)]
#[case(7, false)]
#[case(8, false)]
fn uniqueness_test(#[case] field : usize, #[case] multi : bool) {
let pg = Board::from_array(&FIELDS[field]);
let solver = HechtSolver::new();
let result = solver.is_unique(&pg);
assert!(result != multi)
}
#[test]
fn generator_test_creates_valid_boards() {
let solver = HechtSolver::new();
let board = solver.generate(SodokuComplexity::Hard);
assert!(board.is_valid());
}
#[test]
fn generator_test_creates_not_solved_boards() {
let solver = HechtSolver::new();
let board = solver.generate(SodokuComplexity::Hard);
assert!(!board.is_solved());
}
}
#[derive(Subcommand, Debug)]
enum Commands {
// Simply let the solver solve the sudoku
Solve,
// Let the solver determine if there are multiple solutions
Unique,
// Instead of solving ... generate a sudoku
Generate,
} }
/// Sudoku solver program /// Sudoku solver program
@ -150,6 +206,9 @@ struct Args {
/// Sudoku index number to use /// Sudoku index number to use
#[arg(short, long, default_value_t = 1,value_parser = clap::value_parser!(u8).range(0..FIELDS.len() as i64))] #[arg(short, long, default_value_t = 1,value_parser = clap::value_parser!(u8).range(0..FIELDS.len() as i64))]
scenario: u8, scenario: u8,
#[command(subcommand)]
command: Option<Commands>,
} }
fn main() { fn main() {
@ -162,27 +221,35 @@ fn main() {
let solver = HechtSolver::new(); let solver = HechtSolver::new();
println!(""); // solver.test(&pg);
match &args.command {
Some(Commands::Unique) => {
if solver.is_unique(&pg) {
println!("Solver states, that this sudoku has only one solution!")
} else {
println!("Solver states, that this sudoku has multiple possible solutions!");
}
}
Some(Commands::Generate) => {
let board = solver.generate(SodokuComplexity::Hard);
board.print();
}
_ => {
if let Some(result) = solver.solve(&pg) { if let Some(result) = solver.solve(&pg) {
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 { } else {
println!("Solver found a solution for this sudoku!!") println!("Solver found a solution for this sudoku!!");
}
result.print(); 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!")
} }
} else { } else {
println!("Solver was not able to solve the sodoku!") println!("Solver was not able to solve the sodoku!");
}
}
} }
} }

@ -20,4 +20,5 @@ impl Solver for MySolver {
// FIXME: Implement // FIXME: Implement
false false
} }
} }

@ -2,8 +2,17 @@
use crate::board::Board; use crate::board::Board;
pub trait Solver { pub trait Solver {
/**
* Finds one solution for the board.
*/
fn solve(&self, _: &Board) -> Option<Board>; fn solve(&self, _: &Board) -> Option<Board>;
/**
* Calculates if there are multiple solutions for the board.
*/
fn is_unique(&self, _ : &Board) -> bool; fn is_unique(&self, _ : &Board) -> bool;
} }
pub enum SodokuComplexity { pub enum SodokuComplexity {
@ -16,5 +25,5 @@ pub enum SodokuComplexity {
} }
pub trait Generator{ pub trait Generator{
fn generate(&self, _complexity:&SodokuComplexity) -> Board; fn generate(&self, _complexity:SodokuComplexity) -> Board;
} }

@ -1,29 +1,29 @@
pub trait Locatable { pub trait Indexable {
fn get_xy(&self) -> (usize, usize); fn to_index(&self) -> usize;
} }
#[derive(Clone)] #[derive(Clone)]
pub struct LocatableVec<T:Locatable + Copy, const COUNT: usize> { pub struct IndexableVec<T:Indexable + Copy, const COUNT: usize> {
arr: [Option<T>; COUNT], arr: [Option<T>; COUNT],
len: usize, len: usize,
} }
pub struct LocatableVecIter<'a, T:Locatable + Copy, const COUNT: usize> { pub struct IndexableVecIter<'a, T:Indexable + Copy, const COUNT: usize> {
vec : &'a LocatableVec<T, COUNT>, vec : &'a IndexableVec<T, COUNT>,
idx: usize, idx: usize,
cnt: usize, cnt: usize,
} }
impl<T:Locatable + Copy, const COUNT: usize> LocatableVec<T, COUNT> { impl<T:Indexable + Copy, const COUNT: usize> IndexableVec<T, COUNT> {
pub fn new() -> LocatableVec<T, COUNT> { pub fn new() -> IndexableVec<T, COUNT> {
LocatableVec{arr: [None; COUNT], len: 0} IndexableVec{arr: [None; COUNT], len: 0}
} }
pub fn iter(&self) -> LocatableVecIter<'_, T, COUNT> { pub fn iter(&self) -> IndexableVecIter<'_, T, COUNT> {
LocatableVecIter{vec: self, idx: 0, cnt: 0} IndexableVecIter{vec: self, idx: 0, cnt: 0}
} }
pub fn len(&self) -> usize { pub fn len(&self) -> usize {
@ -31,8 +31,7 @@ impl<T:Locatable + Copy, const COUNT: usize> LocatableVec<T, COUNT> {
} }
pub fn put(&mut self, value : T) { pub fn put(&mut self, value : T) {
let (x,y) = value.get_xy(); let idx = value.to_index();
let idx = y * 9 + x;
if self.arr[idx].is_none() { if self.arr[idx].is_none() {
self.len += 1; self.len += 1;
} }
@ -40,8 +39,7 @@ impl<T:Locatable + Copy, const COUNT: usize> LocatableVec<T, COUNT> {
} }
pub fn remove(&mut self, value : &T) -> bool{ pub fn remove(&mut self, value : &T) -> bool{
let (x,y) = value.get_xy(); let idx = value.to_index();
let idx = y * 9 + x;
if self.arr[idx].is_some() { if self.arr[idx].is_some() {
self.arr[idx] = None; self.arr[idx] = None;
self.len -= 1; self.len -= 1;
@ -52,7 +50,7 @@ impl<T:Locatable + Copy, const COUNT: usize> LocatableVec<T, COUNT> {
} }
impl<'a, T:Locatable + Copy, const COUNT: usize> Iterator for LocatableVecIter<'a, T, COUNT> { impl<'a, T:Indexable + Copy, const COUNT: usize> Iterator for IndexableVecIter<'a, T, COUNT> {
type Item = &'a T; type Item = &'a T;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
@ -72,10 +70,10 @@ impl<'a, T:Locatable + Copy, const COUNT: usize> Iterator for LocatableVecIter<'
} }
} }
impl<'a, L:Locatable + Copy, const COUNT: usize> FromIterator<L> for LocatableVec<L, COUNT> { impl<'a, L:Indexable + Copy, const COUNT: usize> FromIterator<L> for IndexableVec<L, COUNT> {
fn from_iter<T: IntoIterator<Item = L>>(iter: T) -> Self { fn from_iter<T: IntoIterator<Item = L>>(iter: T) -> Self {
let mut x = LocatableVec{arr: [None; COUNT], len: 0}; let mut x = IndexableVec{arr: [None; COUNT], len: 0};
for p in iter { for p in iter {
x.put(p); x.put(p);
} }

Loading…
Cancel
Save