Преглед на файлове

Fixed find_value_pos (use max_index)

Implemented Debug trait for GenBits for better/cleaner output.
Steve Thielemann преди 1 месец
родител
ревизия
39f00dc04c
променени са 3 файла, в които са добавени 143 реда и са изтрити 66 реда
  1. 30 16
      sudoku/src/bits.rs
  2. 3 15
      sudoku/src/group.rs
  3. 110 35
      sudoku/src/sudoku.rs

+ 30 - 16
sudoku/src/bits.rs

@@ -45,9 +45,10 @@ And we could handle any crazy size as well... :O
  */
 
 use std::ops::RangeBounds;
+use std::fmt;
 // use std::iter::{Map, Filter, Enumerate};
 
-#[derive(Clone, Debug)]
+#[derive(Clone)]
 pub struct GenBits(pub Vec<bool>);
 
 impl GenBits {
@@ -60,6 +61,13 @@ impl GenBits {
             self.0[i] = false;
         }
     }
+
+    pub fn fill(&mut self, value: bool) {
+        for i in 0..self.0.len() {
+            self.0[i] = value;
+        }
+    }
+
     pub fn set(&mut self, bit: usize, state: bool) {
         self.0[bit] = state;
     }
@@ -80,7 +88,7 @@ impl GenBits {
 
     // https://depth-first.com/articles/2020/06/22/returning-rust-iterators/
 
-    #[deprecated="Use iter() instead."]
+    #[deprecated = "Use iter() instead."]
     /// Returns the indexes of items that are true
     pub fn indexes(&self) -> impl Iterator<Item = usize> + '_ {
         self.0.iter().enumerate().filter(|x| *x.1).map(|x| x.0)
@@ -91,7 +99,7 @@ impl GenBits {
         self.0.iter().enumerate().filter(|x| *x.1).map(|x| x.0)
     }
 
-    /* 
+    /*
     pub fn iter(&self) -> std::slice::Iter<'_, bool> {
         self.0.iter()
     }
@@ -100,15 +108,22 @@ impl GenBits {
     /// Display bits that are set.
     /// +1 is added to the display, so it matches the cell values (1..N)
     pub fn display(&self) -> String {
-        self.0.iter()
+        self.0
+            .iter()
             .enumerate()
             .filter(|x| *x.1)
             .map(|x| x.0)
-            .map(|i| (i+1).to_string())
+            .map(|i| (i + 1).to_string())
             // .map(|i| i.to_string())
-            .collect::<Vec<_>>().join(",")
+            .collect::<Vec<_>>()
+            .join(",")
     }
+}
 
+impl fmt::Debug for GenBits {
+        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+            write!(f, "({})", self.0.iter().enumerate().filter(|x| *x.1).map(|x| x.0.to_string()).collect::<Vec<_>>().join(","))
+        }
 }
 
 impl PartialEq for GenBits {
@@ -132,8 +147,8 @@ mod tests {
 
     #[test]
     fn check_u16() {
-        const size:usize = 9;
-        let mut p = GenBits::new(size);
+        const SIZE: usize = 9;
+        let mut p = GenBits::new(SIZE);
 
         p.clear();
 
@@ -145,7 +160,7 @@ mod tests {
             assert_eq!(result, true);
         }
 
-        p = GenBits::new(size);
+        p = GenBits::new(SIZE);
         p.set(3, true);
         p.set(5, true);
         p.set(6, true);
@@ -156,7 +171,7 @@ mod tests {
         p.set(0, true);
         assert_eq!(4, p.count_set());
 
-        p = GenBits::new(size);
+        p = GenBits::new(SIZE);
         p.set_bits(0..6);
 
         for i in 0..6 {
@@ -168,8 +183,8 @@ mod tests {
 
     #[test]
     fn check_u32() {
-        const size:usize = 29;
-        let mut p = GenBits::new(size);
+        const SIZE: usize = 29;
+        let mut p = GenBits::new(SIZE);
 
         p.clear();
 
@@ -181,7 +196,7 @@ mod tests {
             assert_eq!(result, true);
         }
 
-        p = GenBits::new(size);
+        p = GenBits::new(SIZE);
         p.set(13, true);
         p.set(15, true);
         p.set(26, true);
@@ -192,7 +207,7 @@ mod tests {
         p.set(0, true);
         assert_eq!(4, p.count_set());
 
-        p = GenBits::new(size);
+        p = GenBits::new(SIZE);
         p.set_bits(10..26);
 
         for i in 10..26 {
@@ -204,7 +219,6 @@ mod tests {
     }
 }
 
-
 /*
     // -> Map<Filter<Enumerate<std::slice::Iter<'_, bool>>>>
     pub fn indexes(&self) -> std::slice::Iter<usize>  {
@@ -387,4 +401,4 @@ mod tests {
     }
 }
 
-*/
+*/

+ 3 - 15
sudoku/src/group.rs

@@ -42,16 +42,13 @@ impl AnyGroup {
             groups: [vec![0; size], vec![0; size], vec![0; size]],
             row_cell: vec![0; size],
             col_cell: vec![0; size],
-            /*
-            row: vec![0; b_width * b_width],
-            column: vec![0; size],
-            cell: vec![0; size],
-            */
         };
         g.calculate();
         g
     }
 
+    /// Calculate the values for the various groups.
+    /// Called only by new().
     fn calculate(&mut self) {
         let size = self.size;
         for y in 0..self.width {
@@ -134,16 +131,7 @@ impl AnyGroup {
     pub fn which_cell(&self, x: u8, y: u8) -> u8 {
         (x / self.size) + (y / self.size) * self.size
     }
-
-    /*
-    #[deprecated="Use xy() instead"]
-    #[must_use]
-    /// Convert index to x,y offsets.
-    pub fn cell_offset(&self, idx:u8) -> (u8,u8) {
-        (idx % self.size, idx / self.size)
-    }
-    */
-    
+  
     #[must_use]
     /// Which index for given cell and (x,y)?
     pub fn which_cell_index(&self, cell_index:u8, x:u8, y:u8) -> usize {

+ 110 - 35
sudoku/src/sudoku.rs

@@ -575,12 +575,17 @@ impl AnyPossible {
     }
 
     #[must_use]
+    /// find pairs (same possible number in different cell locations)
+    /// This finds them all, and is not limited to finding 2.
+    /// Returns
+    ///  - Vector of (Vec(positions), Vec(values))
+    ///  - If possible was modified, return true
     pub fn find_pairs(&mut self, cellgroup: &[usize]) -> (Vec<(Vec<usize>, Vec<u8>)>, bool) {
         // result[value] = indexes where it is located?
         // Step 1: find values, and their position(s).
 
         let initial = GenBits::new(self.width as usize);
-        let mut result: Vec<GenBits> = vec![initial; self.width as usize];
+        let mut value_positions: Vec<GenBits> = vec![initial; self.width as usize];
 
         // let cellgroup = self.group.group(Groups::Cell, cell_index);
 
@@ -588,44 +593,39 @@ impl AnyPossible {
             for pos in 0..self.width {
                 let cellindex = cellgroup[pos as usize];
 
-                if self.get(cellindex, value as usize + 1)
-                // .get(self.possible.pos(x, y), value as usize + 1)
-                {
+                if self.get(cellindex, value as usize + 1) {
                     // println!("Found {} ({},{}) = {}", cell_index, x, y, value);
-                    result[value as usize].set(pos as usize, true);
+                    value_positions[value as usize].set(pos as usize, true);
                 }
             }
         }
 
         // Step 2: pair them up, and if complete, fixup possible (if needed).
 
-        let zero_bits = GenBits::new(self.width as usize);
         let width = self.width;
         let mut possibles_updated: bool = false;
         let mut pairs: Vec<(Vec<usize>, Vec<u8>)> = vec![];
 
         'outer: for idx in 0..width - 1 {
             // pos_found contains the positions.
-            let pos_found = &result[idx as usize];
+            let pos_found = &value_positions[idx as usize];
             if pos_found.count_set() == 0 {
                 continue;
             }
             if idx > 0 {
                 // Check previous for matches - already checked...
                 for check in 0..idx {
-                    if *pos_found == result[check as usize] {
+                    if *pos_found == value_positions[check as usize] {
                         continue 'outer;
                     }
                 }
             }
 
             let count = pos_found.count_set();
-            /*
             if count == 1 {
                 // Single possible item here ... skip this for now.
                 continue;
             }
-            */
 
             let mut matches = 1;
             // Pos contains the numbers in the cell.
@@ -634,7 +634,7 @@ impl AnyPossible {
 
             if count != 1 {
                 for look in idx + 1..width {
-                    if result[look as usize] == *pos_found {
+                    if value_positions[look as usize] == *pos_found {
                         matches += 1;
                         pos.push(look);
                     }
@@ -644,13 +644,13 @@ impl AnyPossible {
             if matches == count {
                 // Ok! We found a pair (or triple, or quad, or ...)
                 // Build new possible
-                let mut new_possible = zero_bits.clone();
+                let mut new_possible = GenBits::new(width as usize);
                 for p in &pos {
                     new_possible.set(*p as usize, true);
                 }
                 let mut index_pos = Vec::<usize>::new();
 
-                for p in pos_found.indexes() {
+                for p in pos_found.iter() {
                     index_pos.push(p);
                     if self.possible[cellgroup[p as usize]] != new_possible {
                         // println!("Update pos {} with {:?}", p, new_possible);
@@ -675,30 +675,21 @@ impl AnyPossible {
 
     #[must_use]
     /// Find positions where each value is possible.
-    /// - Vec index is value
-    /// - GenBits are the positions it is found.
+    /// - Vec index is the value - 1  !
+    /// - GenBits are the positions found.
     pub fn find_value_pos(&self) -> Vec<GenBits> {
-        let zero = GenBits::new(self.width as usize);
-        let mut result = vec![zero.clone(); self.width as usize];
+        let zero = GenBits::new(self.max_index as usize);
+        let mut result = vec![zero; self.width as usize];
 
-        for index in 0..self.width {
-            if self.possible[index as usize] == zero {
+        for index in 0..self.max_index {
+            if self.possible[index as usize].count_set() == 0 {
                 continue;
             }
 
             // Ok, there's some value there.
-            // Would it be better to use the iterator here? Yes, I think so.
-            for v in self.possible[index as usize].indexes() {
+            for v in self.possible[index as usize].iter() {
                 result[v as usize].set(index as usize, true);
             }
-
-            /*
-            for v in 0..self.width {
-                if self.possible[index as usize].get(v as usize +1) {
-                    result[v as usize].set(index as usize, true);
-                }
-            }
-            */
         }
         result
     }
@@ -903,12 +894,14 @@ impl AnySolver {
         // let mut update: bool = false;
 
         // use width, not size. ;)
-        let mut cell_has_value = vec![false; width as usize];
+        let mut cell_has_value = GenBits::new(self.board.max_index); 
+        // vec![false; self.board.max_index];
 
         let mut cell_update = vec![false; width as usize];
         cell_update[cell_index as usize] = true;
 
         let values = self.possible.find_value_pos();
+        println!("Values: {:?}", values);
 
         for (value, positions) in values.iter().enumerate() {
             if positions.count_set() == 0 {
@@ -920,7 +913,7 @@ impl AnySolver {
             cell_has_value.fill(false);
 
             for p in positions.iter() {
-                cell_has_value[p as usize] = true;
+                cell_has_value.set(p, true); // [p as usize] = true;
             }
 
             println!("Value {} : Pos {:?}", value, cell_has_value);
@@ -1969,6 +1962,9 @@ mod tests {
         solver.possible.display();
     }
 
+    // Running just this test:
+    // cargo test -p sudoku logic_test_pairs -- --ignored --show-output
+
     #[ignore]
     #[test]
     fn logic_test_pairs() {
@@ -1980,7 +1976,6 @@ mod tests {
         board.set(0, 4, 4);
         board.set(1, 7, 5);
         board.display();
-        let mut solver = AnySolver::new_from(&board);
         /*
            ╔═══╦═══╦═══╗
            ║ 2 ║   ║   ║
@@ -1996,7 +1991,11 @@ mod tests {
            ║   ║   ║   ║
            ╚═══╩═══╩═══╝
            P = Possible pair (3,5)
+         */
+        let mut solver = AnySolver::new_from(&board);
 
+        solver.possible.display();
+        /*
         (1,1):1,6,7,8,9         (2,1):                  (3,1):1,4,6,7,8,9       (4,1):1,3,4,5,6,7,8,9   (5,1):1,3,4,5,6,7,8,9   (6,1):1,3,4,5,6,7,8,9   (7,1):1,3,4,5,6,7,8,9   (8,1):1,3,4,5,6,7,8,9   (9,1):1,3,4,5,6,7,8,9
         (1,2):1,6,7,8,9         (2,2):1,4,6,7,8,9       (3,2):                  (4,2):1,2,4,5,6,7,8,9   (5,2):1,2,4,5,6,7,8,9   (6,2):1,2,4,5,6,7,8,9   (7,2):1,2,4,5,6,7,8,9   (8,2):1,2,4,5,6,7,8,9   (9,2):1,2,4,5,6,7,8,9
         (1,3):1,6,7,8,9         (2,3):1,4,6,7,8,9       (3,3):                  (4,3):1,2,3,4,6,7,8,9   (5,3):1,2,3,4,6,7,8,9   (6,3):1,2,3,4,6,7,8,9   (7,3):1,2,3,4,6,7,8,9   (8,3):1,2,3,4,6,7,8,9   (9,3):1,2,3,4,6,7,8,9
@@ -2013,9 +2012,31 @@ mod tests {
 
         println!("RIGHT HERE:");
         let g = solver.group.group(Groups::Cell, 3);
-        println!("Pairs [cell index 3]: {:?}", solver.possible.find_pairs(g));
-        solver.finalize_cell(3);
+        let pairs = solver.possible.find_pairs(g);
+        println!("Pairs [cell index 3]: {:?}", pairs);
+        // Pairs [cell index 3]: ([([0, 6], [2, 4])], true)
+
+        let expected: Vec<(Vec<usize>, Vec<u8>)> = vec![(vec![0, 6], vec![2, 4])];
+        assert_eq!(pairs, (expected, true));
+
+        // solver.finalize_cell(3);
         solver.possible.display();
+        /*
+        (1,1):1,6,7,8,9         (2,1):                  (3,1):1,4,6,7,8,9       (4,1):1,3,4,5,6,7,8,9   (5,1):1,3,4,5,6,7,8,9   (6,1):1,3,4,5,6,7,8,9   (7,1):1,3,4,5,6,7,8,9   (8,1):1,3,4,5,6,7,8,9   (9,1):1,3,4,5,6,7,8,9   
+        (1,2):1,6,7,8,9         (2,2):1,4,6,7,8,9       (3,2):                  (4,2):1,2,4,5,6,7,8,9   (5,2):1,2,4,5,6,7,8,9   (6,2):1,2,4,5,6,7,8,9   (7,2):1,2,4,5,6,7,8,9   (8,2):1,2,4,5,6,7,8,9   (9,2):1,2,4,5,6,7,8,9   
+        (1,3):1,6,7,8,9         (2,3):1,4,6,7,8,9       (3,3):                  (4,3):1,2,3,4,6,7,8,9   (5,3):1,2,3,4,6,7,8,9   (6,3):1,2,3,4,6,7,8,9   (7,3):1,2,3,4,6,7,8,9   (8,3):1,2,3,4,6,7,8,9   (9,3):1,2,3,4,6,7,8,9   
+        (1,4):3,5               (2,4):1,6,7,8,9         (3,4):1,2,6,7,8,9       (4,4):1,2,3,4,5,6,7,8,9 (5,4):1,2,3,4,5,6,7,8,9 (6,4):1,2,3,4,5,6,7,8,9 (7,4):1,2,3,4,5,6,7,8,9 (8,4):1,2,3,4,5,6,7,8,9 (9,4):1,2,3,4,5,6,7,8,9 
+        (1,5):                  (2,5):1,6,7,8,9         (3,5):1,2,6,7,8,9       (4,5):1,2,3,5,6,7,8,9   (5,5):1,2,3,5,6,7,8,9   (6,5):1,2,3,5,6,7,8,9   (7,5):1,2,3,5,6,7,8,9   (8,5):1,2,3,5,6,7,8,9   (9,5):1,2,3,5,6,7,8,9   
+        (1,6):3,5               (2,6):1,6,7,8,9         (3,6):1,2,6,7,8,9       (4,6):1,2,3,4,5,6,7,8,9 (5,6):1,2,3,4,5,6,7,8,9 (6,6):1,2,3,4,5,6,7,8,9 (7,6):1,2,3,4,5,6,7,8,9 (8,6):1,2,3,4,5,6,7,8,9 (9,6):1,2,3,4,5,6,7,8,9 
+        (1,7):1,2,6,7,8,9       (2,7):                  (3,7):1,2,4,6,7,8,9     (4,7):1,2,4,5,6,7,8,9   (5,7):1,2,4,5,6,7,8,9   (6,7):1,2,4,5,6,7,8,9   (7,7):1,2,4,5,6,7,8,9   (8,7):1,2,4,5,6,7,8,9   (9,7):1,2,4,5,6,7,8,9   
+        (1,8):1,2,6,7,8,9       (2,8):                  (3,8):1,2,4,6,7,8,9     (4,8):1,2,3,4,6,7,8,9   (5,8):1,2,3,4,6,7,8,9   (6,8):1,2,3,4,6,7,8,9   (7,8):1,2,3,4,6,7,8,9   (8,8):1,2,3,4,6,7,8,9   (9,8):1,2,3,4,6,7,8,9   
+        (1,9):1,2,6,7,8,9       (2,9):1,4,6,7,8,9       (3,9):1,2,4,6,7,8,9     (4,9):1,2,3,4,5,6,7,8,9 (5,9):1,2,3,4,5,6,7,8,9 (6,9):1,2,3,4,5,6,7,8,9 (7,9):1,2,3,4,5,6,7,8,9 (8,9):1,2,3,4,5,6,7,8,9 (9,9):1,2,3,4,5,6,7,8,9 
+
+        ^ This shows that find_pairs is working!
+        finalize - should see that 2 is only possible in (1,7), (1,8), and (1,9) 
+        // OK!  find_pairs does work (making the changes) - so I do need to call it, sometime.
+        and not in (3,7), (3,8) and (3,9).
+         */
 
         /*
         Pairs: [{1, 4, 8, 6, 7, 0, 5, 2}, {6, 0, 8, 5, 2}, {0, 6}, {}, {0, 6}, {1, 4, 8, 6, 7, 0, 5, 2}, {1, 4, 8, 6, 7, 0, 5, 2}, {1, 4, 8, 6, 7, 0, 5, 2}, {1, 4, 8, 6, 7, 0, 5, 2}]
@@ -2024,7 +2045,61 @@ mod tests {
         // Is validate_board destroying our work?!?
         // YES IT IS!
         // assert!(solver.validate_board());
-        solver.possible.display();
+        // solver.possible.display();
+    }
+
+    #[ignore]
+    #[test]
+    fn logic_test_triple() {
+        let mut board = AnyBoard::new(3);
+        board.set(2, 0, 3);
+        board.set(2, 1, 4);
+        board.set(2, 2, 5);
+        board.set(1, 6, 3);
+        board.set(1, 7, 4);
+        board.set(1, 8, 5);
+        // board.display();
+        /*
+        ╔═══╦═══╦═══╗
+        ║  3║   ║   ║
+        ║  4║   ║   ║
+        ║  5║   ║   ║
+        ╠═══╬═══╬═══╣
+        ║   ║   ║   ║
+        ║   ║   ║   ║
+        ║   ║   ║   ║
+        ╠═══╬═══╬═══╣
+        ║ 3 ║   ║   ║
+        ║ 4 ║   ║   ║
+        ║ 5 ║   ║   ║
+        ╚═══╩═══╩═══╝
+         */
+
+        let mut solver = AnySolver::new_from(&board);
+        // solver.possible.display();
+        /*
+        (1,1):1,2,6,7,8,9       (2,1):1,2,6,7,8,9       (3,1):                  (4,1):1,2,4,5,6,7,8,9   (5,1):1,2,4,5,6,7,8,9   (6,1):1,2,4,5,6,7,8,9   (7,1):1,2,4,5,6,7,8,9   (8,1):1,2,4,5,6,7,8,9   (9,1):1,2,4,5,6,7,8,9
+        (1,2):1,2,6,7,8,9       (2,2):1,2,6,7,8,9       (3,2):                  (4,2):1,2,3,5,6,7,8,9   (5,2):1,2,3,5,6,7,8,9   (6,2):1,2,3,5,6,7,8,9   (7,2):1,2,3,5,6,7,8,9   (8,2):1,2,3,5,6,7,8,9   (9,2):1,2,3,5,6,7,8,9
+        (1,3):1,2,6,7,8,9       (2,3):1,2,6,7,8,9       (3,3):                  (4,3):1,2,3,4,6,7,8,9   (5,3):1,2,3,4,6,7,8,9   (6,3):1,2,3,4,6,7,8,9   (7,3):1,2,3,4,6,7,8,9   (8,3):1,2,3,4,6,7,8,9   (9,3):1,2,3,4,6,7,8,9
+        (1,4):1,2,3,4,5,6,7,8,9 (2,4):1,2,6,7,8,9       (3,4):1,2,6,7,8,9       (4,4):1,2,3,4,5,6,7,8,9 (5,4):1,2,3,4,5,6,7,8,9 (6,4):1,2,3,4,5,6,7,8,9 (7,4):1,2,3,4,5,6,7,8,9 (8,4):1,2,3,4,5,6,7,8,9 (9,4):1,2,3,4,5,6,7,8,9
+        (1,5):1,2,3,4,5,6,7,8,9 (2,5):1,2,6,7,8,9       (3,5):1,2,6,7,8,9       (4,5):1,2,3,4,5,6,7,8,9 (5,5):1,2,3,4,5,6,7,8,9 (6,5):1,2,3,4,5,6,7,8,9 (7,5):1,2,3,4,5,6,7,8,9 (8,5):1,2,3,4,5,6,7,8,9 (9,5):1,2,3,4,5,6,7,8,9
+        (1,6):1,2,3,4,5,6,7,8,9 (2,6):1,2,6,7,8,9       (3,6):1,2,6,7,8,9       (4,6):1,2,3,4,5,6,7,8,9 (5,6):1,2,3,4,5,6,7,8,9 (6,6):1,2,3,4,5,6,7,8,9 (7,6):1,2,3,4,5,6,7,8,9 (8,6):1,2,3,4,5,6,7,8,9 (9,6):1,2,3,4,5,6,7,8,9
+        (1,7):1,2,6,7,8,9       (2,7):                  (3,7):1,2,6,7,8,9       (4,7):1,2,4,5,6,7,8,9   (5,7):1,2,4,5,6,7,8,9   (6,7):1,2,4,5,6,7,8,9   (7,7):1,2,4,5,6,7,8,9   (8,7):1,2,4,5,6,7,8,9   (9,7):1,2,4,5,6,7,8,9
+        (1,8):1,2,6,7,8,9       (2,8):                  (3,8):1,2,6,7,8,9       (4,8):1,2,3,5,6,7,8,9   (5,8):1,2,3,5,6,7,8,9   (6,8):1,2,3,5,6,7,8,9   (7,8):1,2,3,5,6,7,8,9   (8,8):1,2,3,5,6,7,8,9   (9,8):1,2,3,5,6,7,8,9
+        (1,9):1,2,6,7,8,9       (2,9):                  (3,9):1,2,6,7,8,9       (4,9):1,2,3,4,6,7,8,9   (5,9):1,2,3,4,6,7,8,9   (6,9):1,2,3,4,6,7,8,9   (7,9):1,2,3,4,6,7,8,9   (8,9):1,2,3,4,6,7,8,9   (9,9):1,2,3,4,6,7,8,9
+         */
+
+        println!("RIGHT HERE:");
+        let g = solver.group.group(Groups::Cell, 3);
+        let pairs = solver.possible.find_pairs(g);
+        println!("Pairs [cell index 3]: {:?}", pairs);
+        // Pairs [cell index 3]: ([([0, 3, 6], [2, 3, 4])], true)
+
+        let expected: Vec<(Vec<usize>, Vec<u8>)> = vec![(vec![0, 3, 6], vec![2, 3, 4])];
+        assert_eq!(pairs, (expected, true));
+
+        // solver.finalize_cell(3);
+        // solver.possible.display();
     }
 
     #[test]