|  | @@ -1,7 +1,7 @@
 | 
	
		
			
				|  |  |  // pub mod group;
 | 
	
		
			
				|  |  |  use crate::group::*;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -use std::collections::HashSet;
 | 
	
		
			
				|  |  | +// use std::collections::HashSet;
 | 
	
		
			
				|  |  |  use std::string::String;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  /// Width of the sudoku board.
 | 
	
	
		
			
				|  | @@ -12,11 +12,17 @@ const MAX_SIZE: u8 = 81;
 | 
	
		
			
				|  |  |  // Use bitfields instead of HashSets.
 | 
	
		
			
				|  |  |  use bit_field::BitField;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +extern crate rand_chacha;
 | 
	
		
			
				|  |  | +use rand::prelude::*;
 | 
	
		
			
				|  |  | +use rand_chacha::rand_core::SeedableRng;
 | 
	
		
			
				|  |  | +use rand_chacha::ChaCha20Rng;
 | 
	
		
			
				|  |  | +use rand::seq::SliceRandom;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  #[derive(Debug, Copy, Clone, PartialEq)]
 | 
	
		
			
				|  |  |  pub struct Possible(u16);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  pub const fn set_bits(bits: u8) -> u16 {
 | 
	
		
			
				|  |  | -    (1 << (bits )) - 1
 | 
	
		
			
				|  |  | +    (1 << (bits)) - 1
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  impl Possible {
 | 
	
	
		
			
				|  | @@ -26,12 +32,12 @@ impl Possible {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      pub fn set(&mut self, bit: u8, value: bool) {
 | 
	
		
			
				|  |  |          // print!("{} set {}={}", self.0, bit, value);
 | 
	
		
			
				|  |  | -        self.0.set_bit((bit-1) as usize, value);
 | 
	
		
			
				|  |  | +        self.0.set_bit((bit - 1) as usize, value);
 | 
	
		
			
				|  |  |          // println!("{}", self.0);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      pub fn get(&self, bit: u8) -> bool {
 | 
	
		
			
				|  |  | -        self.0.get_bit((bit-1) as usize)
 | 
	
		
			
				|  |  | +        self.0.get_bit((bit - 1) as usize)
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      pub fn set_bits(&mut self, bits: u8) {
 | 
	
	
		
			
				|  | @@ -162,31 +168,15 @@ impl Sudoku {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          let s = Sudoku {
 | 
	
		
			
				|  |  |              board: [0; MAX_SIZE as usize],
 | 
	
		
			
				|  |  | -            // possible: [(); MAX_SIZE as usize].map(|_| HashSet::from_iter(1..=9)),
 | 
	
		
			
				|  |  |              possible: [initial; MAX_SIZE as usize],
 | 
	
		
			
				|  |  | -            // possible: [HashSet::from_iter(1..=9); MAX_SIZE as usize],
 | 
	
		
			
				|  |  | -            // possible: [[0; SIZE as usize]; MAX_SIZE as usize],
 | 
	
		
			
				|  |  | -            // possible: [(0..MAX_SIZE).map( |_| (1..=9).collect())],
 | 
	
		
			
				|  |  | -            // possible: [(1..=9).map(|_| HashSet::new()).collect(); MAX_SIZE as usize],
 | 
	
		
			
				|  |  |          };
 | 
	
		
			
				|  |  |          s
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      pub fn clear(&mut self) {
 | 
	
		
			
				|  |  |          let initial = Possible(set_bits(9));
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        for x in 0..MAX_SIZE {
 | 
	
		
			
				|  |  | -            self.board[x as usize] = 0;
 | 
	
		
			
				|  |  | -            self.possible[x as usize] = initial;
 | 
	
		
			
				|  |  | -            // self.possible = [(); MAX_SIZE as usize].map(|_| HashSet::from_iter(1..=9));
 | 
	
		
			
				|  |  | -            /*
 | 
	
		
			
				|  |  | -            self.possible[x as usize].clear();
 | 
	
		
			
				|  |  | -            for i in 1..=9 {
 | 
	
		
			
				|  |  | -                self.possible[x as usize].insert(i);
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -            */
 | 
	
		
			
				|  |  | -            // self.possible[x as usize] = [1, 2, 3, 4, 5, 6, 7, 8, 9];
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | +        self.board = [0; MAX_SIZE as usize];
 | 
	
		
			
				|  |  | +        self.possible = [initial; MAX_SIZE as usize];
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      /// Load puzzle from a string.
 | 
	
	
		
			
				|  | @@ -257,6 +247,7 @@ impl Sudoku {
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |          result
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |      pub fn set(&mut self, x: u8, y: u8, value: u8) {
 | 
	
		
			
				|  |  |          self.board[pos(x, y) as usize] = value;
 | 
	
		
			
				|  |  |          // Ok, update the possible
 | 
	
	
		
			
				|  | @@ -284,30 +275,6 @@ impl Sudoku {
 | 
	
		
			
				|  |  |          self.possible[pos(x, y) as usize].clear();
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    pub fn set2(&mut self, x: u8, y: u8, value: u8) {
 | 
	
		
			
				|  |  | -        self.board[pos(x, y) as usize] = value;
 | 
	
		
			
				|  |  | -        // Ok, update the possible
 | 
	
		
			
				|  |  | -        let mut g = Group::new();
 | 
	
		
			
				|  |  | -        g.for_row(x, y);
 | 
	
		
			
				|  |  | -        for g in g.0 {
 | 
	
		
			
				|  |  | -            // remove value from these sets.
 | 
	
		
			
				|  |  | -            self.possible[g as usize].set(value, false);
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        g.for_column(x, y);
 | 
	
		
			
				|  |  | -        for g in g.0 {
 | 
	
		
			
				|  |  | -            // remove value from these sets.
 | 
	
		
			
				|  |  | -            self.possible[g as usize].set(value, false);
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        g.for_block(x, y);
 | 
	
		
			
				|  |  | -        for g in g.0 {
 | 
	
		
			
				|  |  | -            // remove value from these sets.
 | 
	
		
			
				|  |  | -            self.possible[g as usize].set(value, false);
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        self.possible[pos(x, y) as usize].clear();
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |      pub fn display(&self) {
 | 
	
		
			
				|  |  |          println!("╔═══╦═══╦═══╗");
 | 
	
		
			
				|  |  |          for y in 0..WIDTH {
 | 
	
	
		
			
				|  | @@ -364,6 +331,104 @@ impl Sudoku {
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +    pub fn puzzle_complete(&self) -> bool {
 | 
	
		
			
				|  |  | +        for i in 0..MAX_SIZE {
 | 
	
		
			
				|  |  | +            if self.board[i as usize] == 0 {
 | 
	
		
			
				|  |  | +                return false;
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        true
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    pub fn make(&mut self) {
 | 
	
		
			
				|  |  | +        let mut rng = ChaCha20Rng::from_entropy();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        self.fill_board(&mut rng);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    pub fn fill_board(&mut self, rng : &mut ChaCha20Rng ) -> bool {
 | 
	
		
			
				|  |  | +        let backup = Sudoku{ board: self.board,
 | 
	
		
			
				|  |  | +            possible: self.possible 
 | 
	
		
			
				|  |  | +        };
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        for idx in 0..MAX_SIZE {
 | 
	
		
			
				|  |  | +            if self.board[idx as usize] == 0 {
 | 
	
		
			
				|  |  | +                let (x,y) = xy(idx);
 | 
	
		
			
				|  |  | +                let mut available: [u8; WIDTH as usize] = [0; WIDTH as usize];
 | 
	
		
			
				|  |  | +                let mut total_available: u8 = 0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                for t in self.possible[idx as usize].iter() {
 | 
	
		
			
				|  |  | +                    available[total_available as usize] = t;
 | 
	
		
			
				|  |  | +                    total_available += 1;
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                if total_available == 0 {
 | 
	
		
			
				|  |  | +                    // No possible moves remain.
 | 
	
		
			
				|  |  | +                    /*
 | 
	
		
			
				|  |  | +                    self.board = backup.board;
 | 
	
		
			
				|  |  | +                    self.possible = backup.possible;
 | 
	
		
			
				|  |  | +                     */
 | 
	
		
			
				|  |  | +                    return false;
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                // Randomize the possible items.
 | 
	
		
			
				|  |  | +                available[0..total_available as usize].shuffle(rng);
 | 
	
		
			
				|  |  | +                for v_idx in 0..total_available {
 | 
	
		
			
				|  |  | +                    let value = available[v_idx as usize];
 | 
	
		
			
				|  |  | +                    self.set(x,y, value);
 | 
	
		
			
				|  |  | +                    if self.fill_board(rng) {
 | 
	
		
			
				|  |  | +                        return true;
 | 
	
		
			
				|  |  | +                    }
 | 
	
		
			
				|  |  | +                    // failure
 | 
	
		
			
				|  |  | +                    self.board = backup.board;
 | 
	
		
			
				|  |  | +                    self.possible = backup.possible;
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                // We've run out of possible.
 | 
	
		
			
				|  |  | +                return false;
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // We've visited everything, and it isn't 0.
 | 
	
		
			
				|  |  | +        return true;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    pub fn make_(&mut self) {
 | 
	
		
			
				|  |  | +        self.clear();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        let mut rng = ChaCha20Rng::from_entropy();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        let pick_one = |this: &Self, rng: &mut ChaCha20Rng, idx: u8| -> Option<u8> {
 | 
	
		
			
				|  |  | +            let mut available: [u8; WIDTH as usize] = [0; WIDTH as usize];
 | 
	
		
			
				|  |  | +            let mut total_available: u8 = 0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            for t in this.possible[idx as usize].iter() {
 | 
	
		
			
				|  |  | +                available[total_available as usize] = t;
 | 
	
		
			
				|  |  | +                total_available += 1;
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +            if total_available == 1 {
 | 
	
		
			
				|  |  | +                return Some(available[0]);
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +            if total_available == 0 {
 | 
	
		
			
				|  |  | +                return None;
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +            Some(available[rng.gen_range(0..total_available as usize)])
 | 
	
		
			
				|  |  | +        };
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        for i in 0..MAX_SIZE {
 | 
	
		
			
				|  |  | +            let (x, y) = xy(i);
 | 
	
		
			
				|  |  | +            if self.board[i as usize] == 0 {
 | 
	
		
			
				|  |  | +                // Ok, we found a blank space.
 | 
	
		
			
				|  |  | +                let value = pick_one(self, &mut rng, i);
 | 
	
		
			
				|  |  | +                if value.is_some() {
 | 
	
		
			
				|  |  | +                    let value = value.unwrap();
 | 
	
		
			
				|  |  | +                println!("Set({},{})={}", x, y, value);
 | 
	
		
			
				|  |  | +                self.set(x, y, value);
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |      pub fn solve(&mut self) -> bool {
 | 
	
		
			
				|  |  |          // Pass 1: Look for singles in the possible sets.
 | 
	
		
			
				|  |  |          let mut found_something = false;
 |