|  | @@ -13,10 +13,11 @@ const MAX_SIZE: u8 = 81;
 | 
	
		
			
				|  |  |  use bit_field::BitField;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  extern crate rand_chacha;
 | 
	
		
			
				|  |  | -use rand::prelude::*;
 | 
	
		
			
				|  |  | +// use rand::prelude::*;
 | 
	
		
			
				|  |  |  use rand::seq::SliceRandom;
 | 
	
		
			
				|  |  |  use rand_chacha::rand_core::SeedableRng;
 | 
	
		
			
				|  |  |  use rand_chacha::ChaCha20Rng;
 | 
	
		
			
				|  |  | +use rand::distributions::{Distribution, Uniform};
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  #[derive(Debug, Copy, Clone, PartialEq)]
 | 
	
		
			
				|  |  |  pub struct Possible(u16);
 | 
	
	
		
			
				|  | @@ -139,7 +140,7 @@ mod tests {
 | 
	
		
			
				|  |  |  pub type SudokuBoard = [u8; MAX_SIZE as usize];
 | 
	
		
			
				|  |  |  pub type SudokuPossible = [Possible; MAX_SIZE as usize];
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -#[derive(Debug)]
 | 
	
		
			
				|  |  | +#[derive(Debug, Clone, Copy)]
 | 
	
		
			
				|  |  |  pub struct Sudoku {
 | 
	
		
			
				|  |  |      pub board: [u8; MAX_SIZE as usize],
 | 
	
		
			
				|  |  |      // pub possible: [HashSet<u8>; MAX_SIZE as usize],
 | 
	
	
		
			
				|  | @@ -185,6 +186,12 @@ impl Sudoku {
 | 
	
		
			
				|  |  |          s
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +    pub fn clear_possible(&mut self) {
 | 
	
		
			
				|  |  | +        let mut initial = Possible(set_bits(10));
 | 
	
		
			
				|  |  | +        initial.set(0, false);
 | 
	
		
			
				|  |  | +        self.possible = [initial; MAX_SIZE as usize];
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |      pub fn clear(&mut self) {
 | 
	
		
			
				|  |  |          let mut initial = Possible(set_bits(10));
 | 
	
		
			
				|  |  |          initial.set(0, false);
 | 
	
	
		
			
				|  | @@ -262,6 +269,10 @@ impl Sudoku {
 | 
	
		
			
				|  |  |          result
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +    pub fn get(&self, x:u8, y:u8) -> u8 {
 | 
	
		
			
				|  |  | +        self.board[pos(x,y) as usize]
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |      pub fn set(&mut self, x: u8, y: u8, value: u8) {
 | 
	
		
			
				|  |  |          self.board[pos(x, y) as usize] = value;
 | 
	
		
			
				|  |  |          // Ok, update the possible
 | 
	
	
		
			
				|  | @@ -289,6 +300,31 @@ impl Sudoku {
 | 
	
		
			
				|  |  |          self.possible[pos(x, y) as usize].clear();
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +    pub fn reset_possible(&mut self) {
 | 
	
		
			
				|  |  | +        // Reset the possible.
 | 
	
		
			
				|  |  | +        self.clear_possible();
 | 
	
		
			
				|  |  | +        for y in 0..WIDTH {
 | 
	
		
			
				|  |  | +            for x in 0..WIDTH {
 | 
	
		
			
				|  |  | +                let item: u8 = self.board[pos(x as u8, y as u8) as usize];
 | 
	
		
			
				|  |  | +                if item != 0 {
 | 
	
		
			
				|  |  | +                    let mut g: &Group = for_row(y);
 | 
	
		
			
				|  |  | +                    for g in g.0 {
 | 
	
		
			
				|  |  | +                    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);
 | 
	
		
			
				|  |  | +                    }
 | 
	
		
			
				|  |  | +                    g = for_cell(which_cell(x,y));
 | 
	
		
			
				|  |  | +                    for g in g.0 {
 | 
	
		
			
				|  |  | +                    self.possible[g as usize].set(item, false);
 | 
	
		
			
				|  |  | +                    }
 | 
	
		
			
				|  |  | +                    self.possible[pos(x,y) as usize].clear();
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |      pub fn display(&self) {
 | 
	
		
			
				|  |  |          println!("╔═══╦═══╦═══╗");
 | 
	
		
			
				|  |  |          for y in 0..WIDTH {
 | 
	
	
		
			
				|  | @@ -443,6 +479,7 @@ impl Sudoku {
 | 
	
		
			
				|  |  |          let mut rng = ChaCha20Rng::from_entropy();
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          self.fill_board(&mut rng);
 | 
	
		
			
				|  |  | +        // Ok, this gives us a random (but fully solved) puzzle.
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      fn fill_board(&mut self, rng: &mut ChaCha20Rng) -> bool {
 | 
	
	
		
			
				|  | @@ -493,7 +530,49 @@ impl Sudoku {
 | 
	
		
			
				|  |  |          return true;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    pub fn make_(&mut self) {
 | 
	
		
			
				|  |  | +    pub fn remove(&mut self) -> bool {
 | 
	
		
			
				|  |  | +        // Find a number, remove it. Save position.
 | 
	
		
			
				|  |  | +        let mut rng = ChaCha20Rng::from_entropy();
 | 
	
		
			
				|  |  | +        let puzrange = Uniform::new(0, WIDTH);
 | 
	
		
			
				|  |  | +        let mut x = 0;
 | 
	
		
			
				|  |  | +        let mut y = 0;
 | 
	
		
			
				|  |  | +        let mut value: u8 = 0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        while value == 0 {
 | 
	
		
			
				|  |  | +            x = puzrange.sample(&mut rng);
 | 
	
		
			
				|  |  | +            y = puzrange.sample(&mut rng);
 | 
	
		
			
				|  |  | +            value = self.get(x,y);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        self.set(x,y,0);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // Clone, and solve by logic.
 | 
	
		
			
				|  |  | +        let mut puzcopy = self.clone();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        puzcopy.reset_possible();
 | 
	
		
			
				|  |  | +        /*
 | 
	
		
			
				|  |  | +        puzcopy.display();
 | 
	
		
			
				|  |  | +        puzcopy.display_possible();
 | 
	
		
			
				|  |  | +         */
 | 
	
		
			
				|  |  | +        // If solvable, return true.
 | 
	
		
			
				|  |  | +        while puzcopy.solve(false) {};
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        /*
 | 
	
		
			
				|  |  | +        puzcopy.display();
 | 
	
		
			
				|  |  | +        puzcopy.display_possible();
 | 
	
		
			
				|  |  | +        */
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        if puzcopy.puzzle_complete() {
 | 
	
		
			
				|  |  | +            return true;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        
 | 
	
		
			
				|  |  | +        // If not solvable, restore number, return false.
 | 
	
		
			
				|  |  | +        self.set(x,y,value);
 | 
	
		
			
				|  |  | +        return false;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    /*
 | 
	
		
			
				|  |  | +    fn make_(&mut self) {
 | 
	
		
			
				|  |  |          self.clear();
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          let mut rng = ChaCha20Rng::from_entropy();
 | 
	
	
		
			
				|  | @@ -530,6 +609,7 @@ impl Sudoku {
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | +    */
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      pub fn solve(&mut self, debug: bool) -> bool {
 | 
	
		
			
				|  |  |          // Pass 1: Look for singles in the possible sets.
 |