Jelajahi Sumber

Making and saving working again.

Steve Thielemann 4 bulan lalu
induk
melakukan
549f406da4
2 mengubah file dengan 78 tambahan dan 97 penghapusan
  1. 12 20
      src/main.rs
  2. 66 77
      sudoku/src/sudoku.rs

+ 12 - 20
src/main.rs

@@ -38,36 +38,28 @@ fn main() {
 
     if args.get_flag("make") {
         let size: u8 = *args.get_one::<u8>("size").unwrap();
-        let mut s = AnySolver::new(size);
-
-        s.make();
-        s.board.display();
-        /*
-        s.make();
-        let mut p = s.clone();
-
-        // Ok, get working on the puzzle.
-        for _x in 0..81 {
-            while p.remove() {
-                print!("-");
-            }
+        let mut solution = AnySolver::new(size);
+
+        solution.make();
+        let mut puzzle = solution.clone();
+        for _ in 0..81 {
+            puzzle.make_puzzle();
         }
-        println!("");
 
-        p.display();
-        println!("Solution:");
-        s.display();
         if let Some(filename) = args.get_one::<PathBuf>("file") {
             let mut ksudo = Ksudoku::default();
-            ksudo.puzzle = p.save_to_tld('b', '_');
-            ksudo.solution = s.save_to_tld('b', '_');
+            ksudo.puzzle = puzzle.board.save_ksudoku();
+            ksudo.solution = solution.board.save_ksudoku();
             ksudo.order = 9; // Defaults currently 3x3
             let r = save_ksudoku(filename.to_path_buf(), &ksudo);
             if r.is_ok() {
                 println!("Saved!");
             }
+        } else {
+            puzzle.board.display();
+            println!("Solution:");
+            solution.board.display();    
         }
-        */
         return;
     }
 

+ 66 - 77
sudoku/src/sudoku.rs

@@ -2,10 +2,12 @@
 use crate::bits::*;
 use crate::group::*;
 
-use strum::IntoEnumIterator;
 use std::string::String;
+use strum::IntoEnumIterator;
 extern crate rand_chacha;
+use rand::distributions::{Distribution, Uniform};
 use rand::seq::SliceRandom;
+
 use rand_chacha::rand_core::SeedableRng;
 use rand_chacha::ChaCha20Rng;
 
@@ -128,16 +130,17 @@ impl AnyBoard {
         self.board[index]
     }
 
-    /// Load from ksudoku file
-    /// - uses load_from_tld
+    /// Load from ksudoku format
+    /// - uses load_from_tld with specifics
     pub fn load_ksudoku(&mut self, s: &str) -> Result<(), Box<dyn error::Error>> {
         self.load_from_tld('b', '_', s)
     }
 
+    /// Save to ksudoku format
     pub fn save_ksudoku(&self) -> String {
         self.save_to_tld('b', '_')
     }
-    
+
     /// Load puzzle from string (top,left) going down.
     pub fn load_from_tld(
         &mut self,
@@ -746,6 +749,17 @@ impl AnySolver {
         }
     }
 
+    pub fn get(&self, x: u8, y: u8) -> u8 {
+        debug_assert!(
+            x < self.board.width && y < self.board.width,
+            "Expected ({}, {}) < {}",
+            x,
+            y,
+            self.board.width
+        );
+        self.board.get(x, y)
+    }
+
     /// Make completed board.
     /// - uses fill_board (recursive)
     pub fn make(&mut self) {
@@ -787,14 +801,6 @@ impl AnySolver {
                     // self.board.display();
                     // self.possible.display();
 
-                    // I can't validate board, it might be invalid!
-                    // Really!
-                    /*
-                    if ! self.validate_board() {
-                        panic!("Whaaaat?!");
-                    }
-                    */
-
                     if self.fill_board(rng) {
                         return true;
                     }
@@ -811,6 +817,50 @@ impl AnySolver {
         true
     }
 
+    /// Make a puzzle by removing items
+    /// - Verify it still has a single solution.
+    pub fn make_puzzle(&mut self) {
+        let mut rng = ChaCha20Rng::from_entropy();
+
+        if !self.board.complete() {
+            self.fill_board(&mut rng);
+        }
+        self.reset_possible();
+        while self.remove(&mut rng) {}
+    }
+
+    /// Remove an item
+    /// - Remove a number, test if still solvable.
+    /// - Returns true when removal was successful, and still solvable.
+    /// - Return false when it can't.
+    fn remove(&mut self, rng: &mut ChaCha20Rng) -> bool {
+        let puzrange = Uniform::new(0, self.board.width);
+        let mut x = 0;
+        let mut y = 0;
+        let mut value: u8 = 0;
+
+        while value == 0 {
+            x = puzrange.sample(rng);
+            y = puzrange.sample(rng);
+            value = self.get(x, y);
+        }
+
+        self.set(x, y, 0);
+
+        // clone, and solve by logic.
+        let mut puzcopy = self.clone();
+        puzcopy.reset_possible();
+        puzcopy.solve_logic();
+
+        if puzcopy.board.complete() {
+            return true;
+        }
+
+        // Not solvable, restore and return false.
+        self.set(x, y, value);
+        return false;
+    }
+
     fn logic_pass1(&mut self) -> bool {
         // Pass 1: Look for singles in the possible sets.
         let mut pass1 = false;
@@ -914,24 +964,10 @@ impl AnySolver {
 
             for gr in Groups::iter() {
                 for i in 0..width {
-                let g = grp.group(gr, i);
+                    let g = grp.group(gr, i);
                     group_process(self, g);
                 }
             }
-            /*
-            // Change to 0..WIDTH ...  Keep it simple.
-            for i in 0..width {
-                // println!("Column {i}:");
-                let mut g = grp.column(i);
-                group_process(self, g);
-                // println!("Row {i}:");
-                g = grp.row(i);
-                group_process(self, g);
-                // println!("Cell {i}:");
-                g = grp.cell(i);
-                group_process(self, g);
-            }
-            */
 
             if found_something == true {
                 // Ok, pass 2 found something.
@@ -962,16 +998,18 @@ impl AnySolver {
             // Pass 1: Look for singles in the possible sets.
             while result1 {
                 result1 = self.logic_pass1();
+                /*
                 if result1 {
                     println!("Pass1");
                 };
+                */
             }
 
             let mut result2 = true;
             while result2 {
                 result2 = self.logic_pass2();
                 if result2 {
-                    println!("Pass2");
+                    // println!("Pass2");
                     found_more = true;
                 };
             }
@@ -1305,7 +1343,6 @@ impl AnySolver {
             */
         }
         self.board.complete()
-
     }
 }
 
@@ -1567,51 +1604,3 @@ mod tests {
         assert!(!solver.validate_board());
     }
 }
-
-/* 
-    /// Puzzle generation
-    /// - Removes a number, tests to see if the puzzle can still be solved by logic.
-    /// - Returns true when still a valid, solvable puzzle.
-    /// - Otherwise, restores number and returns false.
-    pub fn remove(&mut self) -> bool {
-        // Find a number, remove it. Save position.
-        let mut rng = ChaCha20Rng::from_entropy();
-        let puzrange = Uniform::new(0, WIDTH);
-        let mut x = 0;
-        let mut y = 0;
-        let mut value: u8 = 0;
-
-        while value == 0 {
-            x = puzrange.sample(&mut rng);
-            y = puzrange.sample(&mut rng);
-            value = self.get(x, y);
-        }
-
-        self.set(x, y, 0);
-
-        // Clone, and solve by logic.
-        let mut puzcopy = self.clone();
-
-        puzcopy.reset_possible();
-        /*
-        puzcopy.display();
-        puzcopy.display_possible();
-         */
-        // If solvable, return true.
-        while puzcopy.solve(false) {}
-
-        /*
-        puzcopy.display();
-        puzcopy.display_possible();
-        */
-
-        if puzcopy.puzzle_complete() {
-            return true;
-        }
-
-        // If not solvable, restore number, return false.
-        self.set(x, y, value);
-        return false;
-    }
-*/
-