|
@@ -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();
|
|
|
}
|