浏览代码

Update tests validated_board

We check for invalid boards (numbers on same row/column/cell),
as well as impossible situations (no values possible).
Steve Thielemann 4 月之前
父节点
当前提交
2d61296dd5
共有 1 个文件被更改,包括 112 次插入26 次删除
  1. 112 26
      sudoku/src/sudoku.rs

+ 112 - 26
sudoku/src/sudoku.rs

@@ -128,8 +128,8 @@ impl AnyBoard {
         let n = board_size as usize;
         let s = AnyBoard {
             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],
         };
         s
@@ -201,9 +201,7 @@ impl AnyBoard {
                     return Err(Box::new(GameLoadError {
                         message: format!(
                             "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 {
                         message: format!(
                             "String symbol ({}) represents value {}, expecting 1 to {}.",
-                            ch,
-                            value,
-                            self.width
+                            ch, value, self.width
                         ),
                     }));
                 }
@@ -376,10 +372,8 @@ impl AnyBoard {
         }
         true
     }
-
 }
 
-
 // Need to use u32, so 5*5=25, 25 bits can be accessed.
 // u16 is fine for 3*3=9.
 
@@ -410,26 +404,25 @@ impl AnyPossible {
         // let width = self.size * self.size;
         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];
     }
 
     // NOTE: values range from 1..width. Bits range from 0..width-1
-    
+
     #[inline]
     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]
-    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
     }
-
 }
 
 #[derive(Debug, Clone)]
@@ -473,29 +466,52 @@ impl AnySolver {
     /// Validate the board
     /// Reuse reset_possible code, verify the values are possible.
     /// - 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();
         for y in 0..self.board.width {
             for x in 0..self.board.width {
                 let value = self.board.get(x, y);
 
                 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!
                         // 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();
-                        println!("{:?}", self);
                         return false;
                     }
                     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
-    } 
-    
+    }
+
     /// Reset the possible
     /// - For when a new puzzle has been loaded.
     /// - When something has changed, and the possibles are out of sync.
@@ -541,10 +557,80 @@ mod tests {
         assert!(result.is_ok());
         board.display();
 
+        let mut solver = AnySolver::new(&board);
+        assert!(solver.validate_board());
+
         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());
-        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());
     }
 }