|
@@ -128,8 +128,8 @@ impl AnyBoard {
|
|
let n = board_size as usize;
|
|
let n = board_size as usize;
|
|
let s = AnyBoard {
|
|
let s = AnyBoard {
|
|
size: board_size,
|
|
size: board_size,
|
|
- width: board_size*board_size,
|
|
|
|
- max_index: n*n*n*n,
|
|
|
|
|
|
+ width: board_size * board_size,
|
|
|
|
+ max_index: n * n * n * n,
|
|
board: vec![0; n * n * n * n],
|
|
board: vec![0; n * n * n * n],
|
|
};
|
|
};
|
|
s
|
|
s
|
|
@@ -201,9 +201,7 @@ impl AnyBoard {
|
|
return Err(Box::new(GameLoadError {
|
|
return Err(Box::new(GameLoadError {
|
|
message: format!(
|
|
message: format!(
|
|
"String symbol ({}) represents value {}, expecting 1 to {}.",
|
|
"String symbol ({}) represents value {}, expecting 1 to {}.",
|
|
- ch,
|
|
|
|
- value,
|
|
|
|
- self.width
|
|
|
|
|
|
+ ch, value, self.width
|
|
),
|
|
),
|
|
}));
|
|
}));
|
|
}
|
|
}
|
|
@@ -271,9 +269,7 @@ impl AnyBoard {
|
|
return Err(Box::new(GameLoadError {
|
|
return Err(Box::new(GameLoadError {
|
|
message: format!(
|
|
message: format!(
|
|
"String symbol ({}) represents value {}, expecting 1 to {}.",
|
|
"String symbol ({}) represents value {}, expecting 1 to {}.",
|
|
- ch,
|
|
|
|
- value,
|
|
|
|
- self.width
|
|
|
|
|
|
+ ch, value, self.width
|
|
),
|
|
),
|
|
}));
|
|
}));
|
|
}
|
|
}
|
|
@@ -376,10 +372,8 @@ impl AnyBoard {
|
|
}
|
|
}
|
|
true
|
|
true
|
|
}
|
|
}
|
|
-
|
|
|
|
}
|
|
}
|
|
|
|
|
|
-
|
|
|
|
// Need to use u32, so 5*5=25, 25 bits can be accessed.
|
|
// Need to use u32, so 5*5=25, 25 bits can be accessed.
|
|
// u16 is fine for 3*3=9.
|
|
// u16 is fine for 3*3=9.
|
|
|
|
|
|
@@ -410,26 +404,25 @@ impl AnyPossible {
|
|
// let width = self.size * self.size;
|
|
// let width = self.size * self.size;
|
|
initial.set_bits(0..self.width);
|
|
initial.set_bits(0..self.width);
|
|
|
|
|
|
- self.possible = vec![initial; self.max_index];
|
|
|
|
|
|
+ self.possible = vec![initial; self.max_index];
|
|
// width as usize * width as usize];
|
|
// width as usize * width as usize];
|
|
}
|
|
}
|
|
|
|
|
|
// NOTE: values range from 1..width. Bits range from 0..width-1
|
|
// NOTE: values range from 1..width. Bits range from 0..width-1
|
|
-
|
|
|
|
|
|
+
|
|
#[inline]
|
|
#[inline]
|
|
pub fn set(&mut self, index: usize, value: usize, state: bool) {
|
|
pub fn set(&mut self, index: usize, value: usize, state: bool) {
|
|
- self.possible[index].set(value -1, state);
|
|
|
|
|
|
+ self.possible[index].set(value - 1, state);
|
|
}
|
|
}
|
|
|
|
|
|
#[inline]
|
|
#[inline]
|
|
- pub fn get(&self, index:usize, value:usize) -> bool {
|
|
|
|
- self.possible[index].get(value -1)
|
|
|
|
|
|
+ pub fn get(&self, index: usize, value: usize) -> bool {
|
|
|
|
+ self.possible[index].get(value - 1)
|
|
}
|
|
}
|
|
|
|
|
|
- pub fn pos(&self, x:u8, y:u8) -> usize {
|
|
|
|
|
|
+ pub fn pos(&self, x: u8, y: u8) -> usize {
|
|
x as usize + y as usize * self.width as usize
|
|
x as usize + y as usize * self.width as usize
|
|
}
|
|
}
|
|
-
|
|
|
|
}
|
|
}
|
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
#[derive(Debug, Clone)]
|
|
@@ -473,29 +466,52 @@ impl AnySolver {
|
|
/// Validate the board
|
|
/// Validate the board
|
|
/// Reuse reset_possible code, verify the values are possible.
|
|
/// Reuse reset_possible code, verify the values are possible.
|
|
/// - This does not check if the board is completed.
|
|
/// - This does not check if the board is completed.
|
|
- pub fn validate_board(&mut self) -> bool {
|
|
|
|
|
|
+ pub fn validate_board(&mut self) -> bool {
|
|
|
|
+ let mut has_blanks = false;
|
|
|
|
+
|
|
self.possible.clear();
|
|
self.possible.clear();
|
|
for y in 0..self.board.width {
|
|
for y in 0..self.board.width {
|
|
for x in 0..self.board.width {
|
|
for x in 0..self.board.width {
|
|
let value = self.board.get(x, y);
|
|
let value = self.board.get(x, y);
|
|
|
|
|
|
if value != 0 {
|
|
if value != 0 {
|
|
- if !self.possible.get(self.possible.pos(x,y), value as usize) {
|
|
|
|
|
|
+ if !self.possible.get(self.possible.pos(x, y), value as usize) {
|
|
// I was going to reset_possible, but the board is broken!
|
|
// I was going to reset_possible, but the board is broken!
|
|
// Leave in a broken state.
|
|
// Leave in a broken state.
|
|
- println!("Width: {}, value: {}", self.board.width, value);
|
|
|
|
- println!("FAILED at ({},{})", x, y);
|
|
|
|
|
|
+
|
|
|
|
+ // println!("Width: {}, value: {}", self.board.width, value);
|
|
|
|
+ println!("Invalid at ({},{}) can't place {}.", x + 1, y + 1, value);
|
|
self.board.display();
|
|
self.board.display();
|
|
- println!("{:?}", self);
|
|
|
|
return false;
|
|
return false;
|
|
}
|
|
}
|
|
self.process_move(x, y, value);
|
|
self.process_move(x, y, value);
|
|
|
|
+ } else {
|
|
|
|
+ has_blanks = true;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ // Ok, the pieces given fit correctly with the sudoku constraints.
|
|
|
|
+
|
|
|
|
+ if has_blanks {
|
|
|
|
+ // Verify that the remaining value == 0 positions have possibles.
|
|
|
|
+ // - If they are blank, then it isn't a valid puzzle!
|
|
|
|
+ for y in 0..self.board.width {
|
|
|
|
+ for x in 0..self.board.width {
|
|
|
|
+ let value = self.board.get(x, y);
|
|
|
|
+ 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();
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
true
|
|
true
|
|
- }
|
|
|
|
-
|
|
|
|
|
|
+ }
|
|
|
|
+
|
|
/// Reset the possible
|
|
/// Reset the possible
|
|
/// - For when a new puzzle has been loaded.
|
|
/// - For when a new puzzle has been loaded.
|
|
/// - When something has changed, and the possibles are out of sync.
|
|
/// - When something has changed, and the possibles are out of sync.
|
|
@@ -541,10 +557,80 @@ mod tests {
|
|
assert!(result.is_ok());
|
|
assert!(result.is_ok());
|
|
board.display();
|
|
board.display();
|
|
|
|
|
|
|
|
+ let mut solver = AnySolver::new(&board);
|
|
|
|
+ assert!(solver.validate_board());
|
|
|
|
+
|
|
board = AnyBoard::new(3);
|
|
board = AnyBoard::new(3);
|
|
- let result = board.load_from_tld('b', '_', "__c_____e_h__cb___bd___ei_ch_jb__d___________i_eh__b__dg___ij_f_i__jg_____b_____g");
|
|
|
|
|
|
+ let result = board.load_from_tld(
|
|
|
|
+ 'b',
|
|
|
|
+ '_',
|
|
|
|
+ "__c_____e_h__cb___bd___ei_ch_jb__d___________i_eh__b__dg___ij_f_i__jg_____b_____g",
|
|
|
|
+ );
|
|
assert!(result.is_ok());
|
|
assert!(result.is_ok());
|
|
- board.display();
|
|
|
|
|
|
+ board.display();
|
|
|
|
+ let mut solver = AnySolver::new(&board);
|
|
|
|
+ assert!(solver.validate_board());
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ #[test]
|
|
|
|
+ fn validated_board() {
|
|
|
|
+ // Create an invalid board. Position (5,9) can't possibly hold any value.
|
|
|
|
+
|
|
|
|
+ let mut board = AnyBoard::new(3);
|
|
|
|
+ board.set(4, 0, 1);
|
|
|
|
+ board.set(4, 1, 2);
|
|
|
|
+ board.set(4, 2, 3);
|
|
|
|
+ board.set(4, 3, 4);
|
|
|
|
+ board.set(4, 4, 5);
|
|
|
|
+ board.set(4, 5, 6);
|
|
|
|
+ board.set(0, 8, 7);
|
|
|
|
+ board.set(1, 8, 8);
|
|
|
|
+ board.set(2, 8, 9);
|
|
|
|
+ // board.display();
|
|
|
|
+
|
|
|
|
+ let mut solver = AnySolver::new(&board);
|
|
|
|
+ assert!(!solver.validate_board());
|
|
|
|
+
|
|
|
|
+ // Invalid board: Has two 1's in same column & cell.
|
|
|
|
+ let mut board = AnyBoard::new(3);
|
|
|
|
+ board.set(4, 0, 1);
|
|
|
|
+ board.set(4, 1, 1);
|
|
|
|
+ // board.display();
|
|
|
|
+
|
|
|
|
+ let mut solver = AnySolver::new(&board);
|
|
|
|
+ assert!(!solver.validate_board());
|
|
|
|
+
|
|
|
|
+ // Invalid board: Has two 1's in same row & cell.
|
|
|
|
+ let mut board = AnyBoard::new(3);
|
|
|
|
+ board.set(4, 0, 1);
|
|
|
|
+ board.set(5, 0, 1);
|
|
|
|
+ // board.display();
|
|
|
|
+
|
|
|
|
+ // Invalid board: Has two 1's in same column.
|
|
|
|
+ let mut board = AnyBoard::new(3);
|
|
|
|
+ board.set(4, 0, 1);
|
|
|
|
+ board.set(4, 4, 1);
|
|
|
|
+ // board.display();
|
|
|
|
+
|
|
|
|
+ let mut solver = AnySolver::new(&board);
|
|
|
|
+ assert!(!solver.validate_board());
|
|
|
|
+
|
|
|
|
+ // Invalid board: Has two 1's in same row.
|
|
|
|
+ let mut board = AnyBoard::new(3);
|
|
|
|
+ board.set(4, 0, 1);
|
|
|
|
+ board.set(7, 0, 1);
|
|
|
|
+ // board.display();
|
|
|
|
+ let mut solver = AnySolver::new(&board);
|
|
|
|
+ assert!(!solver.validate_board());
|
|
|
|
+
|
|
|
|
+ // Invalid board: Has two 1's in same cell.
|
|
|
|
+ let mut board = AnyBoard::new(3);
|
|
|
|
+ board.set(4, 0, 1);
|
|
|
|
+ board.set(5, 1, 1);
|
|
|
|
+ // board.display();
|
|
|
|
+
|
|
|
|
+ let mut solver = AnySolver::new(&board);
|
|
|
|
+ assert!(!solver.validate_board());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|