|  | @@ -445,11 +445,13 @@ impl AnyBoard {
 | 
	
		
			
				|  |  |          solutions.reserve(max as usize);
 | 
	
		
			
				|  |  |          workset.brute_force(&mut total_solutions, &mut solutions, &groups);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +        /* 
 | 
	
		
			
				|  |  |          if solutions.len() > 0 {
 | 
	
		
			
				|  |  |              println!("*** A Solution:");
 | 
	
		
			
				|  |  |              solutions[0].display();
 | 
	
		
			
				|  |  |              println!("***");
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  | +        */
 | 
	
		
			
				|  |  |          (total_solutions, solutions)
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -711,6 +713,7 @@ impl AnySolver {
 | 
	
		
			
				|  |  |      /// Validate the board
 | 
	
		
			
				|  |  |      /// Reuse reset_possible code, verify the values are possible.
 | 
	
		
			
				|  |  |      /// - This does not check if the board is completed.
 | 
	
		
			
				|  |  | +    /// - It does check that blanks have possible values.
 | 
	
		
			
				|  |  |      pub fn validate_board(&mut self) -> bool {
 | 
	
		
			
				|  |  |          let mut has_blanks = false;
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -724,9 +727,9 @@ impl AnySolver {
 | 
	
		
			
				|  |  |                          // I was going to reset_possible, but the board is broken!
 | 
	
		
			
				|  |  |                          // Leave in a broken state.
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -                        // println!("Width: {}, value: {}", self.board.width, value);
 | 
	
		
			
				|  |  | -                        println!("Invalid at ({},{}) can't place {}.", x + 1, y + 1, value);
 | 
	
		
			
				|  |  | -                        self.board.display();
 | 
	
		
			
				|  |  | +                        // log (maybe)
 | 
	
		
			
				|  |  | +                        // println!("Invalid at ({},{}) can't place {}.", x + 1, y + 1, value);
 | 
	
		
			
				|  |  | +                        // self.board.display();
 | 
	
		
			
				|  |  |                          return false;
 | 
	
		
			
				|  |  |                      }
 | 
	
		
			
				|  |  |                      self.process_move(x, y, value);
 | 
	
	
		
			
				|  | @@ -746,8 +749,9 @@ impl AnySolver {
 | 
	
		
			
				|  |  |                      if value == 0 {
 | 
	
		
			
				|  |  |                          let count = self.possible.possible[self.possible.pos(x, y)].count_set();
 | 
	
		
			
				|  |  |                          if count == 0 {
 | 
	
		
			
				|  |  | -                            println!("Invalid ({},{}) = no values possible.", x + 1, y + 1);
 | 
	
		
			
				|  |  | -                            self.board.display();
 | 
	
		
			
				|  |  | +                            // log (maybe)
 | 
	
		
			
				|  |  | +                            // println!("Invalid ({},{}) = no values possible.", x + 1, y + 1);
 | 
	
		
			
				|  |  | +                            // self.board.display();
 | 
	
		
			
				|  |  |                              return false;
 | 
	
		
			
				|  |  |                          }
 | 
	
		
			
				|  |  |                      }
 | 
	
	
		
			
				|  | @@ -858,81 +862,92 @@ impl AnySolver {
 | 
	
		
			
				|  |  |          true
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    // This seems .. broken.  Not sure.  4x4 kicked me.
 | 
	
		
			
				|  |  | -    pub fn brute_force_solver(&mut self) -> u16 {
 | 
	
		
			
				|  |  | -        let mut workset = self.clone();
 | 
	
		
			
				|  |  | -        workset.reset_possible();
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        let mut total_solutions: u16 = 0;
 | 
	
		
			
				|  |  | -        let mut solutions: Vec<AnyBoard> = Vec::new();
 | 
	
		
			
				|  |  | -        solutions.reserve(1);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        workset.brute_force(&mut total_solutions, &mut solutions);
 | 
	
		
			
				|  |  | +    /// Solve by logic alone.
 | 
	
		
			
				|  |  | +    /// - Returns true when something was added to board.
 | 
	
		
			
				|  |  | +    /// - Call solve until it returns false.
 | 
	
		
			
				|  |  | +    /// - It might not be solved (if guessing is required).
 | 
	
		
			
				|  |  | +    pub fn solve_logic(&mut self) -> bool {
 | 
	
		
			
				|  |  | +        // Pass 1: Look for singles in the possible sets.
 | 
	
		
			
				|  |  | +        let mut found_something = false;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        if solutions.len() > 0 {
 | 
	
		
			
				|  |  | -            println!("*** A solution:");
 | 
	
		
			
				|  |  | -            solutions[0].display();
 | 
	
		
			
				|  |  | -            println!("***");
 | 
	
		
			
				|  |  | +        for i in 0 .. self.possible.max_index {
 | 
	
		
			
				|  |  | +            if self.board.board[i] != 0 {
 | 
	
		
			
				|  |  | +                // Skip, if position already filled.
 | 
	
		
			
				|  |  | +                continue;
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +            if self.possible.possible[i].count_set() == 1 {
 | 
	
		
			
				|  |  | +                // Get value
 | 
	
		
			
				|  |  | +                let value = self.possible.possible[i].iter().next().unwrap();
 | 
	
		
			
				|  |  | +                let pos = self.board.xy(i);
 | 
	
		
			
				|  |  | +                self.set(pos.0, pos.1, value);
 | 
	
		
			
				|  |  | +                found_something = true;
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        total_solutions
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    fn brute_force(&mut self, total_solutions: &mut u16, solutions: &mut Vec<AnyBoard>) -> bool {
 | 
	
		
			
				|  |  | -        // Verify that possible is setup correctly.
 | 
	
		
			
				|  |  | -        // self.validate_board(); // The better choice here.
 | 
	
		
			
				|  |  | -        // self.reset_possible();
 | 
	
		
			
				|  |  | +        let width = self.group.width;
 | 
	
		
			
				|  |  | +        let grp = self.group.clone();
 | 
	
		
			
				|  |  | +        let mut values = Bits(0); // HashSet<u8> = HashSet::new();
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        for idx in 0..self.board.max_index {
 | 
	
		
			
				|  |  | -            if self.board.board[idx] == 0 {
 | 
	
		
			
				|  |  | -                // Blank found
 | 
	
		
			
				|  |  | -                let (x, y) = self.board.xy(idx);
 | 
	
		
			
				|  |  | -                if DEBUG_OUTPUT {
 | 
	
		
			
				|  |  | -                    println!("idx={} ({},{})", idx, x + 1, y + 1);
 | 
	
		
			
				|  |  | -                    self.board.display();
 | 
	
		
			
				|  |  | -                    self.possible.display();
 | 
	
		
			
				|  |  | +        let mut group_process = |this: &mut Self, grp: &[usize]| {
 | 
	
		
			
				|  |  | +            // Collect all the possible values within the group.
 | 
	
		
			
				|  |  | +            values.clear();
 | 
	
		
			
				|  |  | +            for gidx in 0..width {
 | 
	
		
			
				|  |  | +                // println!("possible: {:?}", this.possible[grp.items[gidx as usize] as usize]);
 | 
	
		
			
				|  |  | +                for v in this.possible.possible[grp[gidx as usize]].iter() {
 | 
	
		
			
				|  |  | +                    values.set(v, true);
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  | +                // values.extend(this.possible[grp.0[gidx as usize] as usize]);
 | 
	
		
			
				|  |  | +                // println!("now     : {:?}", this.possible[grp.items[gidx as usize] as usize]);
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -                // save possible
 | 
	
		
			
				|  |  | -                let old_possible = self.possible.clone();
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                for value in 1..=self.board.width {
 | 
	
		
			
				|  |  | -                    if self.possible.get(idx, value as usize) {
 | 
	
		
			
				|  |  | -                        // Ok, it could go here.
 | 
	
		
			
				|  |  | -                        if DEBUG_OUTPUT {
 | 
	
		
			
				|  |  | -                            println!("({},{})={}", x + 1, y + 1, value);
 | 
	
		
			
				|  |  | -                        }
 | 
	
		
			
				|  |  | -                        self.set(x, y, value);
 | 
	
		
			
				|  |  | -                        self.board.display();
 | 
	
		
			
				|  |  | +            // println!("values {:?}", values);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -                        if self.board.complete() {
 | 
	
		
			
				|  |  | -                            if *total_solutions < solutions.capacity() as u16 {
 | 
	
		
			
				|  |  | -                                solutions.push(self.board.clone());
 | 
	
		
			
				|  |  | -                            }
 | 
	
		
			
				|  |  | -                            *total_solutions += 1;
 | 
	
		
			
				|  |  | +            // Now, check for singles.
 | 
	
		
			
				|  |  | +            for v in values.iter() {
 | 
	
		
			
				|  |  | +                let mut count = 0;
 | 
	
		
			
				|  |  | +                let mut pos = 0;
 | 
	
		
			
				|  |  | +                for gidx in 0..width{
 | 
	
		
			
				|  |  | +                    if this.possible.possible[grp[gidx as usize] ].get(v as usize) {
 | 
	
		
			
				|  |  | +                        // if this.possible[grp.0[gidx as usize] as usize].contains(&v) {
 | 
	
		
			
				|  |  | +                        count += 1;
 | 
	
		
			
				|  |  | +                        pos = grp[gidx as usize];
 | 
	
		
			
				|  |  | +                        if count > 1 {
 | 
	
		
			
				|  |  |                              break;
 | 
	
		
			
				|  |  | -                        } else {
 | 
	
		
			
				|  |  | -                            if self.brute_force(total_solutions, solutions) {
 | 
	
		
			
				|  |  | -                                return true;
 | 
	
		
			
				|  |  | -                            }
 | 
	
		
			
				|  |  |                          }
 | 
	
		
			
				|  |  | -                        // Restore
 | 
	
		
			
				|  |  | -                        self.possible.copy(&old_possible);
 | 
	
		
			
				|  |  |                      }
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  | -                if DEBUG_OUTPUT {
 | 
	
		
			
				|  |  | -                    println!("Rewind!");
 | 
	
		
			
				|  |  | -                }
 | 
	
		
			
				|  |  | -                self.set(x, y, 0);
 | 
	
		
			
				|  |  | -                // self.possible.copy(&old_possible);
 | 
	
		
			
				|  |  | -                if DEBUG_OUTPUT {
 | 
	
		
			
				|  |  | -                    self.board.display();
 | 
	
		
			
				|  |  | -                    self.possible.display();
 | 
	
		
			
				|  |  | +                if count == 1 {
 | 
	
		
			
				|  |  | +                    // don't need this, it was v!
 | 
	
		
			
				|  |  | +                    // let value = this.possible[pos as usize].iter().next().cloned().unwrap();
 | 
	
		
			
				|  |  | +                    /*
 | 
	
		
			
				|  |  | +                    if debug {
 | 
	
		
			
				|  |  | +                        println!("Set2 {:?} to {}", xy(pos), v);
 | 
	
		
			
				|  |  | +                    }
 | 
	
		
			
				|  |  | +                    */
 | 
	
		
			
				|  |  | +                    let xy = this.board.xy(pos);
 | 
	
		
			
				|  |  | +                    this.set(xy.0, xy.1, v);
 | 
	
		
			
				|  |  | +                    found_something = true;
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  | -                return false;
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  | +        };
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // Change to 0..WIDTH ...  Keep it simple.
 | 
	
		
			
				|  |  | +        for i in 0..width {
 | 
	
		
			
				|  |  | +            let mut g = grp.column(i);
 | 
	
		
			
				|  |  | +            group_process(self, g);
 | 
	
		
			
				|  |  | +            g = grp.row(i);
 | 
	
		
			
				|  |  | +            group_process(self, g);
 | 
	
		
			
				|  |  | +            g = grp.cell(i);
 | 
	
		
			
				|  |  | +            group_process(self, g);
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  | -        false
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        if found_something {
 | 
	
		
			
				|  |  | +            return found_something;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // Pair processing.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        found_something
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -992,7 +1007,7 @@ mod tests {
 | 
	
		
			
				|  |  |                  "OPC  N H   F J  ",
 | 
	
		
			
				|  |  |                  "  EHJ I   MA  CK",
 | 
	
		
			
				|  |  |                  "     FM   IPA  D",
 | 
	
		
			
				|  |  | -                "FM  L    H    P "                
 | 
	
		
			
				|  |  | +                "FM  L    H    P "
 | 
	
		
			
				|  |  |              ]
 | 
	
		
			
				|  |  |          );
 | 
	
		
			
				|  |  |          // board.display();
 | 
	
	
		
			
				|  | @@ -1006,7 +1021,7 @@ mod tests {
 | 
	
		
			
				|  |  |          // board.display();
 | 
	
		
			
				|  |  |          let strings: Vec<String> = board.to_strings();
 | 
	
		
			
				|  |  |          assert_eq!(
 | 
	
		
			
				|  |  | -            strings, 
 | 
	
		
			
				|  |  | +            strings,
 | 
	
		
			
				|  |  |              vec![
 | 
	
		
			
				|  |  |                  " T DPF    Y H R    WSX L ",
 | 
	
		
			
				|  |  |                  "L QF     J X C G     UB D",
 | 
	
	
		
			
				|  | @@ -1033,7 +1048,6 @@ mod tests {
 | 
	
		
			
				|  |  |                  " FR H DQOC  K  INBW T UY ",
 | 
	
		
			
				|  |  |                  "T JL     G I P F     OC W",
 | 
	
		
			
				|  |  |                  " B KMV    Q J H    GRI E "
 | 
	
		
			
				|  |  | -        
 | 
	
		
			
				|  |  |              ]
 | 
	
		
			
				|  |  |          );
 | 
	
		
			
				|  |  |          let mut solver = AnySolver::new_from(&board);
 | 
	
	
		
			
				|  | @@ -1053,11 +1067,42 @@ mod tests {
 | 
	
		
			
				|  |  |          assert_eq!(9, board.width);
 | 
	
		
			
				|  |  |          assert_eq!(81, board.max_index);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        board.display();
 | 
	
		
			
				|  |  | +        // board.display();
 | 
	
		
			
				|  |  | +        let strings: Vec<String> = board.to_strings();
 | 
	
		
			
				|  |  | +        assert_eq!(
 | 
	
		
			
				|  |  | +            strings,
 | 
	
		
			
				|  |  | +            vec![
 | 
	
		
			
				|  |  | +                "  17 83  ",
 | 
	
		
			
				|  |  | +                " 73   68 ",
 | 
	
		
			
				|  |  | +                "2  9 4  1",
 | 
	
		
			
				|  |  | +                "   1 7   ",
 | 
	
		
			
				|  |  | +                " 2     9 ",
 | 
	
		
			
				|  |  | +                " 14   86 ",
 | 
	
		
			
				|  |  | +                "  83 19  ",
 | 
	
		
			
				|  |  | +                "         ",
 | 
	
		
			
				|  |  | +                "4 2   5 6"
 | 
	
		
			
				|  |  | +            ]
 | 
	
		
			
				|  |  | +        );
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |          let mut solver = AnySolver::new_from(&board);
 | 
	
		
			
				|  |  |          assert!(solver.validate_board());
 | 
	
		
			
				|  |  |          let solutions = solver.board.brute_force_solver(2);
 | 
	
		
			
				|  |  |          assert!(solutions.0 == 1, "Expected 1 solution, got {}", solutions.0);
 | 
	
		
			
				|  |  | +        let strings: Vec<String> = solutions.1[0].to_strings();
 | 
	
		
			
				|  |  | +        assert_eq!(
 | 
	
		
			
				|  |  | +            strings,
 | 
	
		
			
				|  |  | +            vec![
 | 
	
		
			
				|  |  | +                "541768329",
 | 
	
		
			
				|  |  | +                "973512684",
 | 
	
		
			
				|  |  | +                "286934751",
 | 
	
		
			
				|  |  | +                "869157243",
 | 
	
		
			
				|  |  | +                "325486197",
 | 
	
		
			
				|  |  | +                "714293865",
 | 
	
		
			
				|  |  | +                "658341972",
 | 
	
		
			
				|  |  | +                "197625438",
 | 
	
		
			
				|  |  | +                "432879516",
 | 
	
		
			
				|  |  | +            ]
 | 
	
		
			
				|  |  | +        );
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          // 4x4 board takes 40 minutes
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -1093,6 +1138,7 @@ mod tests {
 | 
	
		
			
				|  |  |          let mut solver = AnySolver::new(3);
 | 
	
		
			
				|  |  |          solver.make();
 | 
	
		
			
				|  |  |          solver.board.display();
 | 
	
		
			
				|  |  | +        assert!(solver.validate_board());
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      #[test]
 | 
	
	
		
			
				|  | @@ -1281,6 +1327,15 @@ impl<'a> BoardPossible<'a> {
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  */
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +/*
 | 
	
		
			
				|  |  | +  ___  _     _    ____          _      
 | 
	
		
			
				|  |  | + / _ \| | __| |  / ___|___   __| | ___ 
 | 
	
		
			
				|  |  | +| | | | |/ _` | | |   / _ \ / _` |/ _ \
 | 
	
		
			
				|  |  | +| |_| | | (_| | | |__| (_) | (_| |  __/
 | 
	
		
			
				|  |  | + \___/|_|\__,_|  \____\___/ \__,_|\___|
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  #[derive(Debug, Clone, Copy)]
 | 
	
		
			
				|  |  |  pub struct Sudoku {
 | 
	
		
			
				|  |  |      pub board: [u8; MAX_SIZE as usize],      // Board
 |