|  | @@ -1,22 +1,26 @@
 | 
	
		
			
				|  |  |  // pub mod group;
 | 
	
		
			
				|  |  | -use crate::group::*;
 | 
	
		
			
				|  |  |  use crate::bits::*;
 | 
	
		
			
				|  |  | +use crate::group::*;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  // use std::collections::HashSet;
 | 
	
		
			
				|  |  |  use std::string::String;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  const SIZE: u8 = 3;
 | 
	
		
			
				|  |  |  /// Width of the sudoku board.
 | 
	
		
			
				|  |  | -const WIDTH: u8 = SIZE*SIZE;
 | 
	
		
			
				|  |  | +const WIDTH: u8 = SIZE * SIZE;
 | 
	
		
			
				|  |  |  /// Size (width * height) of the board.
 | 
	
		
			
				|  |  |  const MAX_SIZE: u8 = WIDTH * WIDTH; // 81;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  extern crate rand_chacha;
 | 
	
		
			
				|  |  |  // use rand::prelude::*;
 | 
	
		
			
				|  |  | +use rand::distributions::{Distribution, Uniform};
 | 
	
		
			
				|  |  |  use rand::seq::SliceRandom;
 | 
	
		
			
				|  |  |  use rand_chacha::rand_core::SeedableRng;
 | 
	
		
			
				|  |  |  use rand_chacha::ChaCha20Rng;
 | 
	
		
			
				|  |  | -use rand::distributions::{Distribution, Uniform};
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// For custom error
 | 
	
		
			
				|  |  | +use std::error;
 | 
	
		
			
				|  |  | +use std::fmt;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  // Used bo calculate_possible to return the solutions.
 | 
	
		
			
				|  |  |  pub type SudokuBoard = [u8; MAX_SIZE as usize];
 | 
	
	
		
			
				|  | @@ -29,9 +33,6 @@ pub type SudokuPossible = [Bits; MAX_SIZE as usize];
 | 
	
		
			
				|  |  |  #[derive(Debug, Clone, Copy)]
 | 
	
		
			
				|  |  |  pub struct Board([u8; MAX_SIZE as usize]);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |  impl Board {
 | 
	
		
			
				|  |  |      pub fn new() -> Self {
 | 
	
		
			
				|  |  |          let s = Self {
 | 
	
	
		
			
				|  | @@ -44,12 +45,12 @@ impl Board {
 | 
	
		
			
				|  |  |          self.0 = [0; MAX_SIZE as usize];
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    pub fn set(&mut self, x:u8, y:u8, value:u8) {
 | 
	
		
			
				|  |  | -        self.0[pos(x,y) as usize] = value;
 | 
	
		
			
				|  |  | +    pub fn set(&mut self, x: u8, y: u8, value: u8) {
 | 
	
		
			
				|  |  | +        self.0[pos(x, y) as usize] = value;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    pub fn get(&mut self, x:u8, y:u8) -> u8 {
 | 
	
		
			
				|  |  | -        self.0[pos(x,y) as usize]
 | 
	
		
			
				|  |  | +    pub fn get(&mut self, x: u8, y: u8) -> u8 {
 | 
	
		
			
				|  |  | +        self.0[pos(x, y) as usize]
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      /// Load puzzle from a string.
 | 
	
	
		
			
				|  | @@ -61,7 +62,7 @@ impl Board {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          for ch in s.chars() {
 | 
	
		
			
				|  |  |              if ch != blank {
 | 
	
		
			
				|  |  | -                self.set(x,y, (ch as u8 - start_ch as u8)+1);
 | 
	
		
			
				|  |  | +                self.set(x, y, (ch as u8 - start_ch as u8) + 1);
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |              y += 1;
 | 
	
		
			
				|  |  |              if y >= WIDTH {
 | 
	
	
		
			
				|  | @@ -77,31 +78,43 @@ impl Board {
 | 
	
		
			
				|  |  |      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;
 | 
	
		
			
				|  |  | +        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 {
 | 
	
		
			
				|  |  | +            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); 
 | 
	
		
			
				|  |  | +                result.push((start_ch as u8 + self.0[pos(x, y) as usize]) as char);
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |              y += 1;
 | 
	
		
			
				|  |  |              if y >= WIDTH {
 | 
	
		
			
				|  |  | -                y = 0; 
 | 
	
		
			
				|  |  | +                y = 0;
 | 
	
		
			
				|  |  |                  x += 1;
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |          result
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +#[derive(Debug, Clone)]
 | 
	
		
			
				|  |  | +struct GameLoadError {
 | 
	
		
			
				|  |  | +    message: String,
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +impl fmt::Display for GameLoadError {
 | 
	
		
			
				|  |  | +    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 | 
	
		
			
				|  |  | +        write!(f, "Game load error: {}", self.message)
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +impl error::Error for GameLoadError {}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  // Vec doesn't implement Copy ...
 | 
	
		
			
				|  |  |  #[derive(Debug, Clone)]
 | 
	
		
			
				|  |  |  pub struct AnyBoard {
 | 
	
		
			
				|  |  | -    pub size : u8,
 | 
	
		
			
				|  |  | -    pub board : Vec<u8>,
 | 
	
		
			
				|  |  | +    pub size: u8,
 | 
	
		
			
				|  |  | +    pub board: Vec<u8>,
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  impl AnyBoard {
 | 
	
	
		
			
				|  | @@ -110,13 +123,286 @@ impl AnyBoard {
 | 
	
		
			
				|  |  |              panic!("Board size must be 3-5.");
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        let s = AnyBoard{
 | 
	
		
			
				|  |  | +        let n = board_size as usize;
 | 
	
		
			
				|  |  | +        let s = AnyBoard {
 | 
	
		
			
				|  |  |              size: board_size,
 | 
	
		
			
				|  |  | -            board: vec![0, board_size*board_size*2],
 | 
	
		
			
				|  |  | +            board: vec![0; n * n * n * n],
 | 
	
		
			
				|  |  |          };
 | 
	
		
			
				|  |  |          s
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    /// Max board width (size*size)
 | 
	
		
			
				|  |  | +    pub fn width(&self) -> u8 {
 | 
	
		
			
				|  |  | +        self.size * self.size
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    /// Max board index (width*width)
 | 
	
		
			
				|  |  | +    pub fn max_index(&self) -> usize {
 | 
	
		
			
				|  |  | +        self.width() as usize * self.width() as usize
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    /// Clear out the board
 | 
	
		
			
				|  |  | +    pub fn clear(&mut self) {
 | 
	
		
			
				|  |  | +        self.board.fill(0);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    /// Calculate index position of (x,y)
 | 
	
		
			
				|  |  | +    pub fn pos(&self, x: u8, y: u8) -> usize {
 | 
	
		
			
				|  |  | +        x as usize + y as usize * self.width() as usize
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    /// Set a position in the board with a value
 | 
	
		
			
				|  |  | +    pub fn set(&mut self, x: u8, y: u8, value: u8) {
 | 
	
		
			
				|  |  | +        assert!(value <= self.size * self.size);
 | 
	
		
			
				|  |  | +        let index = self.pos(x, y);
 | 
	
		
			
				|  |  | +        assert!(index <= self.board.capacity());
 | 
	
		
			
				|  |  | +        self.board[index] = value;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    /// Get value at position (x,y)
 | 
	
		
			
				|  |  | +    pub fn get(&self, x: u8, y: u8) -> u8 {
 | 
	
		
			
				|  |  | +        let index = self.pos(x, y);
 | 
	
		
			
				|  |  | +        assert!(index <= self.board.capacity());
 | 
	
		
			
				|  |  | +        self.board[index]
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    /// Load puzzle from string (top,left) going down.
 | 
	
		
			
				|  |  | +    pub fn load_from_tld(
 | 
	
		
			
				|  |  | +        &mut self,
 | 
	
		
			
				|  |  | +        start_ch: char,
 | 
	
		
			
				|  |  | +        blank: char,
 | 
	
		
			
				|  |  | +        s: &str,
 | 
	
		
			
				|  |  | +    ) -> Result<(), Box<dyn error::Error>> {
 | 
	
		
			
				|  |  | +        self.clear();
 | 
	
		
			
				|  |  | +        let mut x: u8 = 0;
 | 
	
		
			
				|  |  | +        let mut y: u8 = 0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        if s.len() != self.max_index() {
 | 
	
		
			
				|  |  | +            // self.size * self.size*self.size*self.size {
 | 
	
		
			
				|  |  | +            return Err(Box::new(GameLoadError {
 | 
	
		
			
				|  |  | +                message: format!(
 | 
	
		
			
				|  |  | +                    "String exceeds ({}) expected length {}.",
 | 
	
		
			
				|  |  | +                    s.len(),
 | 
	
		
			
				|  |  | +                    self.size * self.size
 | 
	
		
			
				|  |  | +                ),
 | 
	
		
			
				|  |  | +            }));
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        for ch in s.chars() {
 | 
	
		
			
				|  |  | +            if ch != blank {
 | 
	
		
			
				|  |  | +                let value = (ch as u8 - start_ch as u8) + 1;
 | 
	
		
			
				|  |  | +                if value == 0 || value > self.width() {
 | 
	
		
			
				|  |  | +                    return Err(Box::new(GameLoadError {
 | 
	
		
			
				|  |  | +                        message: format!(
 | 
	
		
			
				|  |  | +                            "String symbol ({}) represents value {}, expecting 1 to {}.",
 | 
	
		
			
				|  |  | +                            ch,
 | 
	
		
			
				|  |  | +                            value,
 | 
	
		
			
				|  |  | +                            self.size * self.size
 | 
	
		
			
				|  |  | +                        ),
 | 
	
		
			
				|  |  | +                    }));
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +                self.set(x, y, value);
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +            y += 1;
 | 
	
		
			
				|  |  | +            if y >= self.size * self.size {
 | 
	
		
			
				|  |  | +                y = 0;
 | 
	
		
			
				|  |  | +                x += 1;
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        Ok(())
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    /// Save puzzle to a string (top,left) going down.
 | 
	
		
			
				|  |  | +    pub fn save_to_tld(&self, start_ch: char, blank: char) -> String {
 | 
	
		
			
				|  |  | +        let mut result = String::new();
 | 
	
		
			
				|  |  | +        result.reserve(self.max_index());
 | 
	
		
			
				|  |  | +        let start_ch = (start_ch as u8 - 1) as char;
 | 
	
		
			
				|  |  | +        let mut x: u8 = 0;
 | 
	
		
			
				|  |  | +        let mut y: u8 = 0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        for _i in 0..self.max_index() {
 | 
	
		
			
				|  |  | +            let value = self.get(x, y);
 | 
	
		
			
				|  |  | +            if value == 0 {
 | 
	
		
			
				|  |  | +                result.push(blank);
 | 
	
		
			
				|  |  | +            } else {
 | 
	
		
			
				|  |  | +                result.push((start_ch as u8 + value) as char);
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +            y += 1;
 | 
	
		
			
				|  |  | +            if y >= self.width() {
 | 
	
		
			
				|  |  | +                y = 0;
 | 
	
		
			
				|  |  | +                x += 1;
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        result
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    pub fn display(&self) {
 | 
	
		
			
				|  |  | +        let line = "═".repeat(self.size as usize);
 | 
	
		
			
				|  |  | +        let alpha_display = self.width() >= 10;
 | 
	
		
			
				|  |  | +        // println!("╔{}╦{}╦{}╗", line, line, line);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        println!("alpha = {}", alpha_display);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // Top
 | 
	
		
			
				|  |  | +        for i in 0..self.size {
 | 
	
		
			
				|  |  | +            if i == 0 {
 | 
	
		
			
				|  |  | +                print!("╔{}", line);
 | 
	
		
			
				|  |  | +            } else {
 | 
	
		
			
				|  |  | +                print!("╦{}", line);
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        println!("╗");
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        for y in 0..self.width() {
 | 
	
		
			
				|  |  | +            print!("║");
 | 
	
		
			
				|  |  | +            for x in 0..self.width() {
 | 
	
		
			
				|  |  | +                let value = self.get(x, y);
 | 
	
		
			
				|  |  | +                if value == 0 {
 | 
	
		
			
				|  |  | +                    print!(" ");
 | 
	
		
			
				|  |  | +                } else {
 | 
	
		
			
				|  |  | +                    if alpha_display {
 | 
	
		
			
				|  |  | +                        print!("{}", (value - 1 + 'A' as u8) as char);
 | 
	
		
			
				|  |  | +                    } else {
 | 
	
		
			
				|  |  | +                        print!("{}", value);
 | 
	
		
			
				|  |  | +                    }
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +                if x % self.size == self.size - 1 {
 | 
	
		
			
				|  |  | +                    print!("║");
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +            println!("");
 | 
	
		
			
				|  |  | +            if y % self.size == self.size - 1 {
 | 
	
		
			
				|  |  | +                if y + 1 == self.width() {
 | 
	
		
			
				|  |  | +                    // Bottom
 | 
	
		
			
				|  |  | +                    for i in 0..self.size {
 | 
	
		
			
				|  |  | +                        if i == 0 {
 | 
	
		
			
				|  |  | +                            print!("╚{}", line);
 | 
	
		
			
				|  |  | +                        } else {
 | 
	
		
			
				|  |  | +                            print!("╩{}", line);
 | 
	
		
			
				|  |  | +                        }
 | 
	
		
			
				|  |  | +                    }
 | 
	
		
			
				|  |  | +                    println!("╝");
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                    // println("╚═══╩═══╩═══╝");
 | 
	
		
			
				|  |  | +                } else {
 | 
	
		
			
				|  |  | +                    // Middle
 | 
	
		
			
				|  |  | +                    for i in 0..self.size {
 | 
	
		
			
				|  |  | +                        if i == 0 {
 | 
	
		
			
				|  |  | +                            print!("╠{}", line);
 | 
	
		
			
				|  |  | +                        } else {
 | 
	
		
			
				|  |  | +                            print!("╬{}", line);
 | 
	
		
			
				|  |  | +                        }
 | 
	
		
			
				|  |  | +                    }
 | 
	
		
			
				|  |  | +                    println!("╣");
 | 
	
		
			
				|  |  | +                    // println("╠═══╬═══╬═══╣");
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// Need to use u32, so 5*5=25, 25 bits can be accessed.
 | 
	
		
			
				|  |  | +// u16 is fine for 3*3=9.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#[derive(Debug, Clone)]
 | 
	
		
			
				|  |  | +pub struct AnyPossible {
 | 
	
		
			
				|  |  | +    pub size: u8,
 | 
	
		
			
				|  |  | +    pub possible: Vec<GenBits<u32>>,
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +impl AnyPossible {
 | 
	
		
			
				|  |  | +    pub fn new(board_size: u8) -> Self {
 | 
	
		
			
				|  |  | +        let mut initial = GenBits::<u32>(0);
 | 
	
		
			
				|  |  | +        initial.set_bits(1..board_size);
 | 
	
		
			
				|  |  | +        Self {
 | 
	
		
			
				|  |  | +            size: board_size,
 | 
	
		
			
				|  |  | +            possible: vec![initial; board_size as usize * board_size as usize],
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    pub fn clear(&mut self) {
 | 
	
		
			
				|  |  | +        let mut initial = GenBits::<u32>(0);
 | 
	
		
			
				|  |  | +        initial.set_bits(1..self.size);
 | 
	
		
			
				|  |  | +        self.possible = vec![initial; self.size as usize * self.size as usize];
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    pub fn set(&mut self, index: usize, value: usize, state: bool) {
 | 
	
		
			
				|  |  | +        self.possible[index].set(value, state);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#[derive(Debug, Clone)]
 | 
	
		
			
				|  |  | +pub struct AnySolver {
 | 
	
		
			
				|  |  | +    pub board: AnyBoard,
 | 
	
		
			
				|  |  | +    pub possible: AnyPossible,
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +impl AnySolver {
 | 
	
		
			
				|  |  | +    pub fn new(initial_board: &AnyBoard) -> Self {
 | 
	
		
			
				|  |  | +        let mut s = AnySolver {
 | 
	
		
			
				|  |  | +            board: initial_board.clone(),
 | 
	
		
			
				|  |  | +            possible: AnyPossible::new(initial_board.max_index() as u8),
 | 
	
		
			
				|  |  | +        };
 | 
	
		
			
				|  |  | +        s.reset_possible();
 | 
	
		
			
				|  |  | +        s
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    /// Process a move
 | 
	
		
			
				|  |  | +    /// - Remove value from rows, columns, and cells.
 | 
	
		
			
				|  |  | +    /// - Clear possibles from (x,y) position, it's filled.
 | 
	
		
			
				|  |  | +    pub fn process_move(&mut self, x: u8, y: u8, value: u8) {
 | 
	
		
			
				|  |  | +        let mut g = for_row(y);
 | 
	
		
			
				|  |  | +        let value: usize = value as usize;
 | 
	
		
			
				|  |  | +        for g in g.0 {
 | 
	
		
			
				|  |  | +            self.possible.set(g, value, false);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        g = for_column(x);
 | 
	
		
			
				|  |  | +        for g in g.0 {
 | 
	
		
			
				|  |  | +            self.possible.set(g, value, false);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        g = for_cell(which_cell(x, y));
 | 
	
		
			
				|  |  | +        for g in g.0 {
 | 
	
		
			
				|  |  | +            self.possible.set(g, value, false);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        self.possible.possible[self.board.pos(x, y)] = GenBits::<u32>(0); // .clear();
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    /// Reset the possible
 | 
	
		
			
				|  |  | +    /// - For when a new puzzle has been loaded.
 | 
	
		
			
				|  |  | +    /// - When something has changed, and the possibles are out of sync.
 | 
	
		
			
				|  |  | +    pub fn reset_possible(&mut self) {
 | 
	
		
			
				|  |  | +        self.possible.clear();
 | 
	
		
			
				|  |  | +        for y in 0..self.board.width() {
 | 
	
		
			
				|  |  | +            for x in 0..self.board.width() {
 | 
	
		
			
				|  |  | +                let value = self.board.get(x, y);
 | 
	
		
			
				|  |  | +                if value != 0 {
 | 
	
		
			
				|  |  | +                    self.process_move(x, y, value);
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#[cfg(test)]
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +mod tests {
 | 
	
		
			
				|  |  | +    use crate::sudoku::*;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    #[test]
 | 
	
		
			
				|  |  | +    fn display_board() {
 | 
	
		
			
				|  |  | +        let mut board: AnyBoard = AnyBoard::new(5);
 | 
	
		
			
				|  |  | +        println!("{:?}", board);
 | 
	
		
			
				|  |  | +        board.load_from_tld('b', '_', "_m_kzg____h_s_n____ftd_u_u_dh_____f_b_t_w_____yg_c_rl_o_tdhy__m__uvig_w_sk_eg___p_q_jikouys_r_d___mlq_t_sb_emcwg_dlzyo_kp_i_ng__ir_b_fp_vhz_ce_y_jm__w__m__o_k_xul_qbt_d_s__e____otv_dhegn___mfkpz_blr____s_dv_n_mjx_ckg_w_bo_p___kqyelwjcz_____nxumoisdh_z__fp_vbi_______dkx_eg__r_y_mlwf_u__q_i__o_chdv_j_i_he_r_____________p_zl_k_d_vbjh_y__e_p__s_tguc_q_s__qj_kpn_______ufw_hx__i_hvntirfxw_____lbckympjg___u_kz_m_bfn_yvx_h_ir_o____rgm_otlnx___ipfes_kwc____p__c_v_ugh_krj_m_w__x__x__ci_j_qk_mpo_dr_u_zb__ht_i_qe_wjvcy_bhkzx_ng_u_syv___u_c_hsfrlqo_t_e___pj_cn_h_slzr__j__mqgp_y_vd_m_bs_____t_o_n_h_____ez_f_e_ufd____p_g_z____cqr_x_");
 | 
	
		
			
				|  |  | +        println!("{:?}", board);
 | 
	
		
			
				|  |  | +        board.display();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        board = AnyBoard::new(4);
 | 
	
		
			
				|  |  | +        board.load_from_tld('b', '_', "_bo_j_m_f__dp__ge_h_pcfdo___q__n___qio______df___f__l___hpnm_i___obig_p_qhl__k_m_dq_cn______o_g_p_____bi_kc__jn______fo____gi______eb____jd______jk__ml_bn_____i_m_b______oq_nj_d_n__jck_m_fgbq___i_medp___n__b___dg______qjk___j__p___fgohl_d_qo__mq__g_d_p_le_");
 | 
	
		
			
				|  |  | +        board.display();
 | 
	
		
			
				|  |  | +        assert!(false);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  /*
 | 
	
		
			
				|  |  |  I probably should keep board and possible separate from one another.
 | 
	
		
			
				|  |  |  Possible is only used when solving the puzzles, and only used by the
 | 
	
	
		
			
				|  | @@ -135,7 +421,7 @@ funcs on just that, rather then having them in BoardPossible (wrong
 | 
	
		
			
				|  |  |  place for Possible's implementation).
 | 
	
		
			
				|  |  |   */
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | - /*
 | 
	
		
			
				|  |  | +/*
 | 
	
		
			
				|  |  |  #[derive(Debug, Clone, Copy)]
 | 
	
		
			
				|  |  |  pub struct SudokuPossible {
 | 
	
		
			
				|  |  |      pub possible: [Possible; MAX_SIZE as usize];
 | 
	
	
		
			
				|  | @@ -155,12 +441,12 @@ pub struct SudokuPossible {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  #[derive(Debug)]
 | 
	
		
			
				|  |  |  pub struct BoardPossible<'a> {
 | 
	
		
			
				|  |  | -    board: &'a mut Board, 
 | 
	
		
			
				|  |  | +    board: &'a mut Board,
 | 
	
		
			
				|  |  |      possible: [Bits; MAX_SIZE as usize],
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -impl <'a>BoardPossible<'a> {
 | 
	
		
			
				|  |  | -    pub fn new(board : &'a mut Board) -> Self {
 | 
	
		
			
				|  |  | +impl<'a> BoardPossible<'a> {
 | 
	
		
			
				|  |  | +    pub fn new(board: &'a mut Board) -> Self {
 | 
	
		
			
				|  |  |          // 10 = WIDTH + 1
 | 
	
		
			
				|  |  |          // This would need to be changed in order to handle 4x4 or 5x5.
 | 
	
		
			
				|  |  |          // NOTE: We ignore bit 0, we use bits 1-9 (for 3x3).
 | 
	
	
		
			
				|  | @@ -185,8 +471,8 @@ impl <'a>BoardPossible<'a> {
 | 
	
		
			
				|  |  |      /// - This updates the board.
 | 
	
		
			
				|  |  |      /// - this updates all the possible (row,column,cell).
 | 
	
		
			
				|  |  |      /// - Clears the possible for the (x,y).
 | 
	
		
			
				|  |  | -    pub fn set(&mut self, x:u8, y:u8, value:u8) {
 | 
	
		
			
				|  |  | -        self.board.0[pos(x,y)] = value;
 | 
	
		
			
				|  |  | +    pub fn set(&mut self, x: u8, y: u8, value: u8) {
 | 
	
		
			
				|  |  | +        self.board.0[pos(x, y)] = value;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          // update the possible
 | 
	
		
			
				|  |  |          let mut g: &Group = for_row(y);
 | 
	
	
		
			
				|  | @@ -197,16 +483,14 @@ impl <'a>BoardPossible<'a> {
 | 
	
		
			
				|  |  |          for g in g.0 {
 | 
	
		
			
				|  |  |              self.possible[g].set(value, false);
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  | -        g = for_cell(which_cell(x,y));
 | 
	
		
			
				|  |  | +        g = for_cell(which_cell(x, y));
 | 
	
		
			
				|  |  |          for g in g.0 {
 | 
	
		
			
				|  |  |              self.possible[g].set(value, false);
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  | -        self.possible[pos(x,y)].clear();
 | 
	
		
			
				|  |  | +        self.possible[pos(x, y)].clear();
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    pub fn reset_possible(&mut self) {
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | +    pub fn reset_possible(&mut self) {}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      /// Display the possibles.
 | 
	
		
			
				|  |  |      /// This should be in the Possible struct, not here.
 | 
	
	
		
			
				|  | @@ -241,17 +525,16 @@ impl <'a>BoardPossible<'a> {
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |  #[derive(Debug, Clone, Copy)]
 | 
	
		
			
				|  |  |  pub struct Sudoku {
 | 
	
		
			
				|  |  | -    pub board: [u8; MAX_SIZE as usize], // Board
 | 
	
		
			
				|  |  | +    pub board: [u8; MAX_SIZE as usize],      // Board
 | 
	
		
			
				|  |  |      pub possible: [Bits; MAX_SIZE as usize], // BoardPossible
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  /// Translate x,y to position in board.
 | 
	
		
			
				|  |  |  /// 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) 
 | 
	
		
			
				|  |  | +    x as usize + (y as usize * WIDTH as usize)
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  /// Translate x,y (with starting index of 1) to position in board.
 | 
	
	
		
			
				|  | @@ -348,7 +631,7 @@ impl Sudoku {
 | 
	
		
			
				|  |  |              if self.board[pos(x, y) as usize] == 0 {
 | 
	
		
			
				|  |  |                  result.push(blank);
 | 
	
		
			
				|  |  |              } else {
 | 
	
		
			
				|  |  | -                result.push((start_ch as u8 + self.board[pos(x,y) as usize]) as char);
 | 
	
		
			
				|  |  | +                result.push((start_ch as u8 + self.board[pos(x, y) as usize]) as char);
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |              y += 1;
 | 
	
		
			
				|  |  |              if y >= WIDTH {
 | 
	
	
		
			
				|  | @@ -373,8 +656,8 @@ impl Sudoku {
 | 
	
		
			
				|  |  |          result
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    pub fn get(&self, x:u8, y:u8) -> u8 {
 | 
	
		
			
				|  |  | -        self.board[pos(x,y) as usize]
 | 
	
		
			
				|  |  | +    pub fn get(&self, x: u8, y: u8) -> u8 {
 | 
	
		
			
				|  |  | +        self.board[pos(x, y) as usize]
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      /*
 | 
	
	
		
			
				|  | @@ -422,17 +705,17 @@ impl Sudoku {
 | 
	
		
			
				|  |  |                  if item != 0 {
 | 
	
		
			
				|  |  |                      let mut g: &Group = for_row(y);
 | 
	
		
			
				|  |  |                      for g in g.0 {
 | 
	
		
			
				|  |  | -                    self.possible[g as usize].set(item, false);
 | 
	
		
			
				|  |  | +                        self.possible[g as usize].set(item, false);
 | 
	
		
			
				|  |  |                      }
 | 
	
		
			
				|  |  |                      g = for_column(x);
 | 
	
		
			
				|  |  |                      for g in g.0 {
 | 
	
		
			
				|  |  | -                    self.possible[g as usize].set(item, false);
 | 
	
		
			
				|  |  | +                        self.possible[g as usize].set(item, false);
 | 
	
		
			
				|  |  |                      }
 | 
	
		
			
				|  |  | -                    g = for_cell(which_cell(x,y));
 | 
	
		
			
				|  |  | +                    g = for_cell(which_cell(x, y));
 | 
	
		
			
				|  |  |                      for g in g.0 {
 | 
	
		
			
				|  |  | -                    self.possible[g as usize].set(item, false);
 | 
	
		
			
				|  |  | +                        self.possible[g as usize].set(item, false);
 | 
	
		
			
				|  |  |                      }
 | 
	
		
			
				|  |  | -                    self.possible[pos(x,y) as usize].clear();
 | 
	
		
			
				|  |  | +                    self.possible[pos(x, y) as usize].clear();
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |          }
 | 
	
	
		
			
				|  | @@ -513,7 +796,11 @@ impl Sudoku {
 | 
	
		
			
				|  |  |      /// Recursive brute-force solver
 | 
	
		
			
				|  |  |      /// - 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 {
 | 
	
		
			
				|  |  | +    fn calculate_possible(
 | 
	
		
			
				|  |  | +        &mut self,
 | 
	
		
			
				|  |  | +        total_solutions: &mut u16,
 | 
	
		
			
				|  |  | +        solutions: &mut Vec<SudokuBoard>,
 | 
	
		
			
				|  |  | +    ) -> bool {
 | 
	
		
			
				|  |  |          for idx in 0..MAX_SIZE as usize {
 | 
	
		
			
				|  |  |              if self.board[idx as usize] == 0 {
 | 
	
		
			
				|  |  |                  // Ok, there's a blank here
 | 
	
	
		
			
				|  | @@ -611,7 +898,7 @@ impl Sudoku {
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      /// Fill puzzle with random
 | 
	
		
			
				|  |  | -    /// - This is like the brute-force solver, it calls itself recursively 
 | 
	
		
			
				|  |  | +    /// - This is like the brute-force solver, it calls itself recursively
 | 
	
		
			
				|  |  |      ///   and backtraces if a solution can't be found.
 | 
	
		
			
				|  |  |      fn fill_board(&mut self, rng: &mut ChaCha20Rng) -> bool {
 | 
	
		
			
				|  |  |          let backup = Sudoku {
 | 
	
	
		
			
				|  | @@ -676,10 +963,10 @@ impl Sudoku {
 | 
	
		
			
				|  |  |          while value == 0 {
 | 
	
		
			
				|  |  |              x = puzrange.sample(&mut rng);
 | 
	
		
			
				|  |  |              y = puzrange.sample(&mut rng);
 | 
	
		
			
				|  |  | -            value = self.get(x,y);
 | 
	
		
			
				|  |  | +            value = self.get(x, y);
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        self.set(x,y,0);
 | 
	
		
			
				|  |  | +        self.set(x, y, 0);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          // Clone, and solve by logic.
 | 
	
		
			
				|  |  |          let mut puzcopy = self.clone();
 | 
	
	
		
			
				|  | @@ -690,7 +977,7 @@ impl Sudoku {
 | 
	
		
			
				|  |  |          puzcopy.display_possible();
 | 
	
		
			
				|  |  |           */
 | 
	
		
			
				|  |  |          // If solvable, return true.
 | 
	
		
			
				|  |  | -        while puzcopy.solve(false) {};
 | 
	
		
			
				|  |  | +        while puzcopy.solve(false) {}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          /*
 | 
	
		
			
				|  |  |          puzcopy.display();
 | 
	
	
		
			
				|  | @@ -700,9 +987,9 @@ impl Sudoku {
 | 
	
		
			
				|  |  |          if puzcopy.puzzle_complete() {
 | 
	
		
			
				|  |  |              return true;
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  | -        
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |          // If not solvable, restore number, return false.
 | 
	
		
			
				|  |  | -        self.set(x,y,value);
 | 
	
		
			
				|  |  | +        self.set(x, y, value);
 | 
	
		
			
				|  |  |          return false;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 |