|  | @@ -113,7 +113,7 @@ impl error::Error for GameLoadError {}
 | 
	
		
			
				|  |  |  // const DEBUG_OUTPUT: bool = false;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  // Vec doesn't implement Copy ...
 | 
	
		
			
				|  |  | -#[derive(Debug, Clone)]
 | 
	
		
			
				|  |  | +#[derive(Debug, Clone, Eq, PartialEq)]
 | 
	
		
			
				|  |  |  pub struct AnyBoard {
 | 
	
		
			
				|  |  |      pub size: u8,
 | 
	
		
			
				|  |  |      pub width: u8,
 | 
	
	
		
			
				|  | @@ -400,6 +400,30 @@ impl AnyBoard {
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +    pub fn to_strings(&self) -> Vec<String> {
 | 
	
		
			
				|  |  | +        let mut result = Vec::<String>::new();
 | 
	
		
			
				|  |  | +        let alpha_display = self.width >= 10;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        for y in 0..self.width {
 | 
	
		
			
				|  |  | +            let mut line = String::new();
 | 
	
		
			
				|  |  | +            line.reserve(self.width as usize);
 | 
	
		
			
				|  |  | +            for x in 0..self.width {
 | 
	
		
			
				|  |  | +                let value = self.get(x, y);
 | 
	
		
			
				|  |  | +                if value == 0 {
 | 
	
		
			
				|  |  | +                    line.push(' ');
 | 
	
		
			
				|  |  | +                } else {
 | 
	
		
			
				|  |  | +                    if alpha_display {
 | 
	
		
			
				|  |  | +                        line.push((value - 1 + 'A' as u8) as char);
 | 
	
		
			
				|  |  | +                    } else {
 | 
	
		
			
				|  |  | +                        line.push((value + '0' as u8) as char);
 | 
	
		
			
				|  |  | +                    }
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +            result.push(line);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        result
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |      /// Is the puzzle completed?
 | 
	
		
			
				|  |  |      /// Have all of the locations been filled with a value?
 | 
	
		
			
				|  |  |      /// - This does not validate that it is a correct puzzle.
 | 
	
	
		
			
				|  | @@ -413,12 +437,12 @@ impl AnyBoard {
 | 
	
		
			
				|  |  |          true
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    pub fn brute_force_solver(&self) -> u16 {
 | 
	
		
			
				|  |  | +    pub fn brute_force_solver(&self, max: u16) -> (u16, Vec<AnyBoard>) {
 | 
	
		
			
				|  |  |          let mut workset = self.clone();
 | 
	
		
			
				|  |  |          let mut total_solutions: u16 = 0;
 | 
	
		
			
				|  |  |          let mut solutions: Vec<AnyBoard> = Vec::new();
 | 
	
		
			
				|  |  |          let groups = AnyGroup::new(workset.size);
 | 
	
		
			
				|  |  | -        solutions.reserve(1);
 | 
	
		
			
				|  |  | +        solutions.reserve(max as usize);
 | 
	
		
			
				|  |  |          workset.brute_force(&mut total_solutions, &mut solutions, &groups);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          if solutions.len() > 0 {
 | 
	
	
		
			
				|  | @@ -426,7 +450,7 @@ impl AnyBoard {
 | 
	
		
			
				|  |  |              solutions[0].display();
 | 
	
		
			
				|  |  |              println!("***");
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  | -        total_solutions
 | 
	
		
			
				|  |  | +        (total_solutions, solutions)
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      fn brute_force(
 | 
	
	
		
			
				|  | @@ -543,7 +567,7 @@ impl AnyPossible {
 | 
	
		
			
				|  |  |              index < self.max_index,
 | 
	
		
			
				|  |  |              "Index {} >= {}",
 | 
	
		
			
				|  |  |              index,
 | 
	
		
			
				|  |  | -            self.max_index 
 | 
	
		
			
				|  |  | +            self.max_index
 | 
	
		
			
				|  |  |          );
 | 
	
		
			
				|  |  |          self.possible[index].set(value - 1, state);
 | 
	
		
			
				|  |  |      }
 | 
	
	
		
			
				|  | @@ -554,7 +578,7 @@ impl AnyPossible {
 | 
	
		
			
				|  |  |              index < self.max_index,
 | 
	
		
			
				|  |  |              "Index {} >= {}",
 | 
	
		
			
				|  |  |              index,
 | 
	
		
			
				|  |  | -            self.max_index 
 | 
	
		
			
				|  |  | +            self.max_index
 | 
	
		
			
				|  |  |          );
 | 
	
		
			
				|  |  |          self.possible[index].get(value - 1)
 | 
	
		
			
				|  |  |      }
 | 
	
	
		
			
				|  | @@ -589,7 +613,7 @@ impl AnyPossible {
 | 
	
		
			
				|  |  |                  // let stuff: String = values.into_iter().map(|i| i.to_string().push_str(",")).collect::<String>();
 | 
	
		
			
				|  |  |                  let stuff: String = values
 | 
	
		
			
				|  |  |                      .into_iter()
 | 
	
		
			
				|  |  | -                    .map(|i| (i+1).to_string())
 | 
	
		
			
				|  |  | +                    .map(|i| (i + 1).to_string())
 | 
	
		
			
				|  |  |                      .collect::<String>();
 | 
	
		
			
				|  |  |                  /*
 | 
	
		
			
				|  |  |                  if stuff.len() > 1 {
 | 
	
	
		
			
				|  | @@ -643,7 +667,7 @@ impl AnySolver {
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      pub fn clear(&mut self) {
 | 
	
		
			
				|  |  | -        let board_size:u8 = self.board.size;
 | 
	
		
			
				|  |  | +        let board_size: u8 = self.board.size;
 | 
	
		
			
				|  |  |          self.board = AnyBoard::new(board_size);
 | 
	
		
			
				|  |  |          self.possible = AnyPossible::new(board_size);
 | 
	
		
			
				|  |  |          self.reset_possible();
 | 
	
	
		
			
				|  | @@ -680,7 +704,7 @@ impl AnySolver {
 | 
	
		
			
				|  |  |          for g in g {
 | 
	
		
			
				|  |  |              self.possible.set(*g, value, false);
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  | -        let idx = self.possible.pos(x,y);
 | 
	
		
			
				|  |  | +        let idx = self.possible.pos(x, y);
 | 
	
		
			
				|  |  |          self.possible.possible[idx] = GenBits::<u32>(0); // .clear();
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -775,7 +799,7 @@ impl AnySolver {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      pub fn make(&mut self) {
 | 
	
		
			
				|  |  |          let mut rng = ChaCha20Rng::from_entropy();
 | 
	
		
			
				|  |  | -        self.reset_possible(); 
 | 
	
		
			
				|  |  | +        self.reset_possible();
 | 
	
		
			
				|  |  |          self.fill_board(&mut rng);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -786,12 +810,12 @@ impl AnySolver {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          for idx in 0..max_index {
 | 
	
		
			
				|  |  |              if self.board.board[idx] == 0 {
 | 
	
		
			
				|  |  | -                let (x,y) = self.board.xy(idx);
 | 
	
		
			
				|  |  | -                let mut available :Vec<u8> = Vec::new();
 | 
	
		
			
				|  |  | -                available.reserve(width as usize); 
 | 
	
		
			
				|  |  | +                let (x, y) = self.board.xy(idx);
 | 
	
		
			
				|  |  | +                let mut available: Vec<u8> = Vec::new();
 | 
	
		
			
				|  |  | +                available.reserve(width as usize);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |                  for t in self.possible.possible[idx].iter() {
 | 
	
		
			
				|  |  | -                    available.push(t+1);
 | 
	
		
			
				|  |  | +                    available.push(t + 1);
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  |                  if available.len() == 0 {
 | 
	
		
			
				|  |  |                      return false;
 | 
	
	
		
			
				|  | @@ -801,12 +825,12 @@ impl AnySolver {
 | 
	
		
			
				|  |  |                  // Randomize the possible items.
 | 
	
		
			
				|  |  |                  available.shuffle(rng);
 | 
	
		
			
				|  |  |                  // available.as_mut_slice().shuffle(rng);
 | 
	
		
			
				|  |  | -                
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |                  // print!("{:?}", available);
 | 
	
		
			
				|  |  |                  for value in available.into_iter() {
 | 
	
		
			
				|  |  |                      assert!(value != 0);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -                    self.set(x,y, value);
 | 
	
		
			
				|  |  | +                    self.set(x, y, value);
 | 
	
		
			
				|  |  |                      // self.board.display();
 | 
	
		
			
				|  |  |                      // self.possible.display();
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -832,7 +856,7 @@ impl AnySolver {
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |          // We've visited everything, and it isn't 0.
 | 
	
		
			
				|  |  |          true
 | 
	
		
			
				|  |  | -    }    
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      // This seems .. broken.  Not sure.  4x4 kicked me.
 | 
	
		
			
				|  |  |      pub fn brute_force_solver(&mut self) -> u16 {
 | 
	
	
		
			
				|  | @@ -850,6 +874,7 @@ impl AnySolver {
 | 
	
		
			
				|  |  |              solutions[0].display();
 | 
	
		
			
				|  |  |              println!("***");
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |          total_solutions
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -925,14 +950,52 @@ mod tests {
 | 
	
		
			
				|  |  |              "__c_____e_h__cb___bd___ei_ch_jb__d___________i_eh__b__dg___ij_f_i__jg_____b_____g",
 | 
	
		
			
				|  |  |          );
 | 
	
		
			
				|  |  |          assert!(result.is_ok());
 | 
	
		
			
				|  |  | -        board.display();
 | 
	
		
			
				|  |  | +        let strings = 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"
 | 
	
		
			
				|  |  | +            ]
 | 
	
		
			
				|  |  | +        );
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // board.display();
 | 
	
		
			
				|  |  |          let mut solver = AnySolver::new_from(&board);
 | 
	
		
			
				|  |  |          assert!(solver.validate_board());
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          board = AnyBoard::new(4);
 | 
	
		
			
				|  |  |          let result = 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_");
 | 
	
		
			
				|  |  |          assert!(result.is_ok());
 | 
	
		
			
				|  |  | -        board.display();
 | 
	
		
			
				|  |  | +        let strings = board.to_strings();
 | 
	
		
			
				|  |  | +        assert_eq!(
 | 
	
		
			
				|  |  | +            strings,
 | 
	
		
			
				|  |  | +            vec![
 | 
	
		
			
				|  |  | +                " D    O    C  IN",
 | 
	
		
			
				|  |  | +                "A  ENC   IL     ",
 | 
	
		
			
				|  |  | +                "NG  AP   J MHC  ",
 | 
	
		
			
				|  |  | +                "  P H   D A  FOL",
 | 
	
		
			
				|  |  | +                "IOHKFB  A   L  P",
 | 
	
		
			
				|  |  | +                " BN  M E L ID   ",
 | 
	
		
			
				|  |  | +                "LE  O AN K BC   ",
 | 
	
		
			
				|  |  | +                " C    H    JO EF",
 | 
	
		
			
				|  |  | +                "EN GP    A    F ",
 | 
	
		
			
				|  |  | +                "   OG J IM L  NC",
 | 
	
		
			
				|  |  | +                "   MK B C N  PG ",
 | 
	
		
			
				|  |  | +                "C  L   F  PEMIKO",
 | 
	
		
			
				|  |  | +                "OPC  N H   F J  ",
 | 
	
		
			
				|  |  | +                "  EHJ I   MA  CK",
 | 
	
		
			
				|  |  | +                "     FM   IPA  D",
 | 
	
		
			
				|  |  | +                "FM  L    H    P "                
 | 
	
		
			
				|  |  | +            ]
 | 
	
		
			
				|  |  | +        );
 | 
	
		
			
				|  |  | +        // board.display();
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          let mut solver = AnySolver::new_from(&board);
 | 
	
		
			
				|  |  |          assert!(solver.validate_board());
 | 
	
	
		
			
				|  | @@ -955,11 +1018,15 @@ mod tests {
 | 
	
		
			
				|  |  |              "__c_____e_h__cb___bd___ei_ch_jb__d___________i_eh__b__dg___ij_f_i__jg_____b_____g",
 | 
	
		
			
				|  |  |          );
 | 
	
		
			
				|  |  |          assert!(result.is_ok());
 | 
	
		
			
				|  |  | +        assert_eq!(3, board.size);
 | 
	
		
			
				|  |  | +        assert_eq!(9, board.width);
 | 
	
		
			
				|  |  | +        assert_eq!(81, board.max_index);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |          board.display();
 | 
	
		
			
				|  |  |          let mut solver = AnySolver::new_from(&board);
 | 
	
		
			
				|  |  |          assert!(solver.validate_board());
 | 
	
		
			
				|  |  | -        let solutions = solver.board.brute_force_solver();
 | 
	
		
			
				|  |  | -        assert!(solutions == 1, "Expected 1 solution, got {}", solutions);
 | 
	
		
			
				|  |  | +        let solutions = solver.board.brute_force_solver(2);
 | 
	
		
			
				|  |  | +        assert!(solutions.0 == 1, "Expected 1 solution, got {}", solutions.0);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          // 4x4 board takes 40 minutes
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -971,8 +1038,8 @@ mod tests {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |              let mut solver = AnySolver::new_from(&board);
 | 
	
		
			
				|  |  |              assert!(solver.validate_board());
 | 
	
		
			
				|  |  | -            let solutions = solver.board.brute_force_solver();
 | 
	
		
			
				|  |  | -            assert!(solutions == 1);
 | 
	
		
			
				|  |  | +            let solutions = solver.board.brute_force_solver(2);
 | 
	
		
			
				|  |  | +            assert!(solutions.0 == 1);
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          /*
 | 
	
	
		
			
				|  | @@ -989,7 +1056,10 @@ mod tests {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      #[test]
 | 
	
		
			
				|  |  |      fn make_board() {
 | 
	
		
			
				|  |  | -        let mut solver = AnySolver::new(4);
 | 
	
		
			
				|  |  | +        // Making a 4x4 board varies (0.3-60 seconds).
 | 
	
		
			
				|  |  | +        // Maybe we don't want to do this in a test, because of the randomness involved.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        let mut solver = AnySolver::new(3);
 | 
	
		
			
				|  |  |          solver.make();
 | 
	
		
			
				|  |  |          solver.board.display();
 | 
	
		
			
				|  |  |      }
 |