|  | @@ -1,5 +1,6 @@
 | 
	
		
			
				|  |  |  // pub mod group;
 | 
	
		
			
				|  |  |  use crate::group::*;
 | 
	
		
			
				|  |  | +use crate::bits::*;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  // use std::collections::HashSet;
 | 
	
		
			
				|  |  |  use std::string::String;
 | 
	
	
		
			
				|  | @@ -10,9 +11,6 @@ const WIDTH: u8 = SIZE*SIZE;
 | 
	
		
			
				|  |  |  /// Size (width * height) of the board.
 | 
	
		
			
				|  |  |  const MAX_SIZE: u8 = WIDTH * WIDTH; // 81;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -// Use bitfields instead of HashSets.
 | 
	
		
			
				|  |  | -use bit_field::BitField;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |  extern crate rand_chacha;
 | 
	
		
			
				|  |  |  // use rand::prelude::*;
 | 
	
		
			
				|  |  |  use rand::seq::SliceRandom;
 | 
	
	
		
			
				|  | @@ -20,135 +18,83 @@ use rand_chacha::rand_core::SeedableRng;
 | 
	
		
			
				|  |  |  use rand_chacha::ChaCha20Rng;
 | 
	
		
			
				|  |  |  use rand::distributions::{Distribution, Uniform};
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -// If I wanted to do 4x4 or 5x5, I would need more bits. (u32).
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -#[derive(Debug, Copy, Clone, PartialEq)]
 | 
	
		
			
				|  |  | -pub struct Bits(u16);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -/// Set bits number of bits to 1 (true)
 | 
	
		
			
				|  |  | -pub const fn set_bits(bits: u8) -> u16 {
 | 
	
		
			
				|  |  | -    (1 << (bits)) - 1
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | +// Used bo calculate_possible to return the solutions.
 | 
	
		
			
				|  |  | +pub type SudokuBoard = [u8; MAX_SIZE as usize];
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -impl Bits {
 | 
	
		
			
				|  |  | -    /// clear all bits
 | 
	
		
			
				|  |  | -    pub fn clear(&mut self) {
 | 
	
		
			
				|  |  | -        self.0 = 0;
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | +/*
 | 
	
		
			
				|  |  | +pub type Possible = [Bits; MAX_SIZE as usize];
 | 
	
		
			
				|  |  | +pub type SudokuPossible = [Bits; MAX_SIZE as usize];
 | 
	
		
			
				|  |  | +*/
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    /// set bit to state of value.
 | 
	
		
			
				|  |  | -    pub fn set(&mut self, bit: u8, value: bool) {
 | 
	
		
			
				|  |  | -        self.0.set_bit(bit as usize, value);
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | +#[derive(Debug, Clone, Copy)]
 | 
	
		
			
				|  |  | +pub struct Board([u8; MAX_SIZE as usize]);
 | 
	
		
			
				|  |  | +#[derive(Debug, Clone, Copy)]
 | 
	
		
			
				|  |  | +pub struct BoardPossible([Bits; MAX_SIZE as usize]);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    /// get state of bit.
 | 
	
		
			
				|  |  | -    pub fn get(&self, bit: u8) -> bool {
 | 
	
		
			
				|  |  | -        self.0.get_bit(bit as usize)
 | 
	
		
			
				|  |  | +impl Board {
 | 
	
		
			
				|  |  | +    pub fn new() -> Self {
 | 
	
		
			
				|  |  | +        let s = Self {
 | 
	
		
			
				|  |  | +            0: [0; MAX_SIZE as usize],
 | 
	
		
			
				|  |  | +        };
 | 
	
		
			
				|  |  | +        s
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    /// set bits on, given number of bits initially to set.
 | 
	
		
			
				|  |  | -    pub fn set_bits(&mut self, bits: u8) {
 | 
	
		
			
				|  |  | -        self.0 = set_bits(bits);
 | 
	
		
			
				|  |  | +    pub fn clear(&mut self) {
 | 
	
		
			
				|  |  | +        self.0 = [0; MAX_SIZE as usize];
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    /// count number of bits set.
 | 
	
		
			
				|  |  | -    pub fn count_set(&self) -> u8 {
 | 
	
		
			
				|  |  | -        let mut count = 0;
 | 
	
		
			
				|  |  | -        for i in 0..u16::BIT_LENGTH {
 | 
	
		
			
				|  |  | -            if self.get(i as u8) {
 | 
	
		
			
				|  |  | -                count += 1;
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        count
 | 
	
		
			
				|  |  | +    pub fn set(&mut self, x:u8, y:u8, value:u8) {
 | 
	
		
			
				|  |  | +        self.0[pos(x,y) as usize] = value;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -struct BitsIterator<'a> {
 | 
	
		
			
				|  |  | -    possible: &'a Bits,
 | 
	
		
			
				|  |  | -    index: u8,
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -impl Bits {
 | 
	
		
			
				|  |  | -    fn iter(&self) -> BitsIterator {
 | 
	
		
			
				|  |  | -        BitsIterator {
 | 
	
		
			
				|  |  | -            possible: self,
 | 
	
		
			
				|  |  | -            index: 1,
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | +    pub fn get(&mut self, x:u8, y:u8) -> u8 {
 | 
	
		
			
				|  |  | +        self.0[pos(x,y) as usize]
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -impl<'a> Iterator for BitsIterator<'a> {
 | 
	
		
			
				|  |  | -    type Item = u8;
 | 
	
		
			
				|  |  | +    /// Load puzzle from a string.
 | 
	
		
			
				|  |  | +    /// Note, we load from (top,left) going down, to (bottom,left) by columns.
 | 
	
		
			
				|  |  | +    pub fn load_from_tld(&mut self, start_ch: char, blank: char, s: &str) {
 | 
	
		
			
				|  |  | +        self.clear();
 | 
	
		
			
				|  |  | +        let mut x: u8 = 0;
 | 
	
		
			
				|  |  | +        let mut y: u8 = 0;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    fn next(&mut self) -> Option<u8> {
 | 
	
		
			
				|  |  | -        while (self.index < u16::BIT_LENGTH as u8) && (!self.possible.get(self.index)) {
 | 
	
		
			
				|  |  | -            self.index += 1;
 | 
	
		
			
				|  |  | -            // println!("index = {}", self.index);
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        if self.index == u16::BIT_LENGTH as u8 {
 | 
	
		
			
				|  |  | -            None
 | 
	
		
			
				|  |  | -        } else {
 | 
	
		
			
				|  |  | -            self.index += 1;
 | 
	
		
			
				|  |  | -            Some(self.index - 1)
 | 
	
		
			
				|  |  | +        for ch in s.chars() {
 | 
	
		
			
				|  |  | +            if ch != blank {
 | 
	
		
			
				|  |  | +                self.set(x,y, (ch as u8 - start_ch as u8)+1);
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +            y += 1;
 | 
	
		
			
				|  |  | +            if y >= WIDTH {
 | 
	
		
			
				|  |  | +                y = 0;
 | 
	
		
			
				|  |  | +                x += 1;
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -#[cfg(test)]
 | 
	
		
			
				|  |  | -mod tests {
 | 
	
		
			
				|  |  | -    use crate::sudoku::*;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    #[test]
 | 
	
		
			
				|  |  | -    fn check_possible_bitset() {
 | 
	
		
			
				|  |  | -        let mut p = Bits(0);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        p.clear();
 | 
	
		
			
				|  |  | +    /// Save puzzle to a string.
 | 
	
		
			
				|  |  | +    /// Note, we load from (top,left) going down, to (bottom,left) by columns.
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        for i in 0..9 {
 | 
	
		
			
				|  |  | -            let mut result = p.get(i);
 | 
	
		
			
				|  |  | -            assert_eq!(result, false);
 | 
	
		
			
				|  |  | -            p.set(i, true);
 | 
	
		
			
				|  |  | -            result = p.get(i);
 | 
	
		
			
				|  |  | -            assert_eq!(result, true);
 | 
	
		
			
				|  |  | +    pub fn save_to_tld(&mut self, start_ch: char, blank: char) -> String {
 | 
	
		
			
				|  |  | +        let mut result = String::new();
 | 
	
		
			
				|  |  | +        result.reserve(MAX_SIZE as usize);
 | 
	
		
			
				|  |  | +        let start_ch = (start_ch as u8 -1) as char;
 | 
	
		
			
				|  |  | +        let mut x:u8=0;
 | 
	
		
			
				|  |  | +        let mut y:u8=0;
 | 
	
		
			
				|  |  | +        for _i in 0..MAX_SIZE {
 | 
	
		
			
				|  |  | +            if self.0[pos(x,y) as usize] == 0 {
 | 
	
		
			
				|  |  | +                result.push(blank);
 | 
	
		
			
				|  |  | +            } else {
 | 
	
		
			
				|  |  | +                result.push((start_ch as u8 + self.0[pos(x,y) as usize]) as char); 
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +            y += 1;
 | 
	
		
			
				|  |  | +            if y >= WIDTH {
 | 
	
		
			
				|  |  | +                y = 0; 
 | 
	
		
			
				|  |  | +                x += 1;
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  | +        result
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    #[test]
 | 
	
		
			
				|  |  | -    fn check_possible_iter() {
 | 
	
		
			
				|  |  | -        let mut p = Bits(0);
 | 
	
		
			
				|  |  | -        p.set(3, true);
 | 
	
		
			
				|  |  | -        p.set(5, true);
 | 
	
		
			
				|  |  | -        p.set(6, true);
 | 
	
		
			
				|  |  | -        assert_eq!(3, p.count_set());
 | 
	
		
			
				|  |  | -        let values: Vec<u8> = p.iter().collect();
 | 
	
		
			
				|  |  | -        assert_eq!(values, vec!(3, 5, 6));
 | 
	
		
			
				|  |  | -        assert_eq!(3, p.count_set());
 | 
	
		
			
				|  |  | -        p.set(0, true);
 | 
	
		
			
				|  |  | -        assert_eq!(4, p.count_set());
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    #[test]
 | 
	
		
			
				|  |  | -    fn check_bits() {
 | 
	
		
			
				|  |  | -        // Set bits 0-5 (6 bits total)
 | 
	
		
			
				|  |  | -        let p = Bits(set_bits(6));
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        for i in 0..6 {
 | 
	
		
			
				|  |  | -            let result = p.get(i);
 | 
	
		
			
				|  |  | -            assert_eq!(result, true);
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        assert_eq!(p.get(6), false);
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -pub type SudokuBoard = [u8; MAX_SIZE as usize];
 | 
	
		
			
				|  |  | -pub type Possible = [Bits; MAX_SIZE as usize];
 | 
	
		
			
				|  |  | -pub type SudokuPossible = [Bits; MAX_SIZE as usize];
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -#[derive(Debug, Clone, Copy)]
 | 
	
		
			
				|  |  | -pub struct Board([u8; MAX_SIZE as usize]);
 | 
	
		
			
				|  |  | -#[derive(Debug, Clone, Copy)]
 | 
	
		
			
				|  |  | -pub struct BoardPossible([Bits; MAX_SIZE as usize]);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |  /*
 | 
	
		
			
				|  |  |  I probably should keep board and possible separate from one another.
 | 
	
		
			
				|  |  |  Possible is only used when solving the puzzles, and only used by the
 | 
	
	
		
			
				|  | @@ -207,18 +153,19 @@ pub struct Sudoku {
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  /// Translate x,y to position in board.
 | 
	
		
			
				|  |  | -pub const fn pos(x: u8, y: u8) -> u8 {
 | 
	
		
			
				|  |  | -    x + (y * WIDTH as u8)
 | 
	
		
			
				|  |  | +/// This is used as usize, so return that instead of u8.
 | 
	
		
			
				|  |  | +pub const fn pos(x: u8, y: u8) -> usize {
 | 
	
		
			
				|  |  | +    x as usize + (y as usize * WIDTH as usize) 
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  /// Translate x,y (with starting index of 1) to position in board.
 | 
	
		
			
				|  |  | -pub const fn pos1(x: u8, y: u8) -> u8 {
 | 
	
		
			
				|  |  | -    (x - 1) + ((y - 1) * WIDTH as u8)
 | 
	
		
			
				|  |  | +pub const fn pos1(x: u8, y: u8) -> usize {
 | 
	
		
			
				|  |  | +    (x as usize - 1) + ((y as usize - 1) * WIDTH as usize)
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  /// Translate post to x,y in board.
 | 
	
		
			
				|  |  | -pub const fn xy(pos: u8) -> (u8, u8) {
 | 
	
		
			
				|  |  | -    ((pos % WIDTH), (pos / WIDTH))
 | 
	
		
			
				|  |  | +pub const fn xy(pos: usize) -> (u8, u8) {
 | 
	
		
			
				|  |  | +    ((pos % WIDTH as usize) as u8, (pos / WIDTH as usize) as u8)
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  const DEBUG_OUTPUT: bool = false;
 | 
	
	
		
			
				|  | @@ -284,7 +231,7 @@ impl Sudoku {
 | 
	
		
			
				|  |  |      /// This loads from (top,left) going right, to (top,right), by rows.
 | 
	
		
			
				|  |  |      pub fn load_from_tlr(&mut self, start_ch: char, blank: char, s: &str) {
 | 
	
		
			
				|  |  |          self.clear();
 | 
	
		
			
				|  |  | -        let mut i: u8 = 0;
 | 
	
		
			
				|  |  | +        let mut i: usize = 0;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          for ch in s.chars() {
 | 
	
		
			
				|  |  |              if ch != blank {
 | 
	
	
		
			
				|  | @@ -471,7 +418,7 @@ impl Sudoku {
 | 
	
		
			
				|  |  |      /// - As possibilities are tried, it recursively calls itself to see
 | 
	
		
			
				|  |  |      ///   if there are any solutions with the given possibility.
 | 
	
		
			
				|  |  |      fn calculate_possible(&mut self, total_solutions: &mut u16, solutions: &mut Vec<SudokuBoard>) -> bool {
 | 
	
		
			
				|  |  | -        for idx in 0..MAX_SIZE {
 | 
	
		
			
				|  |  | +        for idx in 0..MAX_SIZE as usize {
 | 
	
		
			
				|  |  |              if self.board[idx as usize] == 0 {
 | 
	
		
			
				|  |  |                  // Ok, there's a blank here
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -576,7 +523,7 @@ impl Sudoku {
 | 
	
		
			
				|  |  |              possible: self.possible,
 | 
	
		
			
				|  |  |          };
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        for idx in 0..MAX_SIZE {
 | 
	
		
			
				|  |  | +        for idx in 0..MAX_SIZE as usize {
 | 
	
		
			
				|  |  |              if self.board[idx as usize] == 0 {
 | 
	
		
			
				|  |  |                  let (x, y) = xy(idx);
 | 
	
		
			
				|  |  |                  let mut available: [u8; WIDTH as usize] = [0; WIDTH as usize];
 | 
	
	
		
			
				|  | @@ -710,7 +657,7 @@ impl Sudoku {
 | 
	
		
			
				|  |  |          // Pass 1: Look for singles in the possible sets.
 | 
	
		
			
				|  |  |          let mut found_something = false;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        for i in 0..MAX_SIZE {
 | 
	
		
			
				|  |  | +        for i in 0..MAX_SIZE as usize {
 | 
	
		
			
				|  |  |              if self.possible[i as usize].count_set() == 1 {
 | 
	
		
			
				|  |  |                  // Get the value
 | 
	
		
			
				|  |  |                  let value = self.possible[i as usize].iter().next().unwrap();
 |