Browse Source

Working make.

The SAVE is not working.  Serde doesn't like XML at all.
Need to rewrite that part, using xml crate. (Event driven parser)
It's primitive, but very small.
Steve Thielemann 6 months ago
parent
commit
ad8b101fb8
3 changed files with 131 additions and 4 deletions
  1. 21 1
      src/main.rs
  2. 27 0
      sudoku/src/ksudoku.rs
  3. 83 3
      sudoku/src/sudoku.rs

+ 21 - 1
src/main.rs

@@ -3,7 +3,7 @@ use std::path::PathBuf;
 
 // https://docs.rs/clap/latest/clap/_tutorial/chapter_0/index.html
 
-use sudoku::ksudoku::load_ksudoku;
+use sudoku::ksudoku::{load_ksudoku, save_ksudoku};
 use sudoku::sudoku::*;
 
 fn main() {
@@ -32,7 +32,27 @@ fn main() {
 
     if args.get_flag("make") {
         s.make();
+        let mut p = s.clone();
+
+        // Ok, get working on the puzzle.
+        for _x in 0..81 {
+            while p.remove() {
+                print!("-");
+            }
+        }
+        println!("");
+
+        p.display();
+        println!("Solution:");
         s.display();
+        if let Some(filename) = args.get_one::<PathBuf>("file") {
+            let puz = p.save_to_tld('b', '_');
+            let sol = s.save_to_tld('b', '_');
+            let r = save_ksudoku(filename.to_path_buf(), &puz, &sol);
+            if r.is_ok() {
+                println!("Saved!");
+            }
+        }
         return;
     }
 

+ 27 - 0
sudoku/src/ksudoku.rs

@@ -2,6 +2,7 @@
 
 use serde_derive::{Deserialize, Serialize};
 use serde_xml_rs::from_reader; // , from_str, to_string};
+use serde_xml_rs::to_writer;
 
 use std::error::Error;
 use std::fs::File;
@@ -40,3 +41,29 @@ pub fn load_ksudoku(filename: std::path::PathBuf) -> Result<String, Box<dyn Erro
     let puzzle: Ksudoku = from_reader(fh)?;
     Ok(puzzle.game.puzzle.values.clone())
 }
+
+pub fn save_ksudoku(filename: std::path::PathBuf, puz: &String, sol: &String) -> Result<(), Box<dyn Error>> {
+    /*
+    let pStr: String = puzzle.save_to_tld(start_ch: 'b', blank: '_');
+    let solStr: solution.save_to_tld(start_ch: 'b', blank: '_');
+    */
+    let ksudoko = Ksudoku {
+        game: Game {
+            help: 0,
+            elapsed: 0,
+            puzzle: Puzzle {
+                graph: Graph {
+                    order: 9,
+                    game_type: String::from("sudoku"),
+                    specific_type: String::from("Plain"),
+                },
+                values: puz.to_string(),
+                solution: sol.to_string(),
+            },
+        },
+    };
+    let fh = File::create(filename)?;
+    let _res = to_writer(fh, &ksudoko)?;
+
+    Ok(())
+}

+ 83 - 3
sudoku/src/sudoku.rs

@@ -13,10 +13,11 @@ const MAX_SIZE: u8 = 81;
 use bit_field::BitField;
 
 extern crate rand_chacha;
-use rand::prelude::*;
+// use rand::prelude::*;
 use rand::seq::SliceRandom;
 use rand_chacha::rand_core::SeedableRng;
 use rand_chacha::ChaCha20Rng;
+use rand::distributions::{Distribution, Uniform};
 
 #[derive(Debug, Copy, Clone, PartialEq)]
 pub struct Possible(u16);
@@ -139,7 +140,7 @@ mod tests {
 pub type SudokuBoard = [u8; MAX_SIZE as usize];
 pub type SudokuPossible = [Possible; MAX_SIZE as usize];
 
-#[derive(Debug)]
+#[derive(Debug, Clone, Copy)]
 pub struct Sudoku {
     pub board: [u8; MAX_SIZE as usize],
     // pub possible: [HashSet<u8>; MAX_SIZE as usize],
@@ -185,6 +186,12 @@ impl Sudoku {
         s
     }
 
+    pub fn clear_possible(&mut self) {
+        let mut initial = Possible(set_bits(10));
+        initial.set(0, false);
+        self.possible = [initial; MAX_SIZE as usize];
+    }
+
     pub fn clear(&mut self) {
         let mut initial = Possible(set_bits(10));
         initial.set(0, false);
@@ -262,6 +269,10 @@ impl Sudoku {
         result
     }
 
+    pub fn get(&self, x:u8, y:u8) -> u8 {
+        self.board[pos(x,y) as usize]
+    }
+
     pub fn set(&mut self, x: u8, y: u8, value: u8) {
         self.board[pos(x, y) as usize] = value;
         // Ok, update the possible
@@ -289,6 +300,31 @@ impl Sudoku {
         self.possible[pos(x, y) as usize].clear();
     }
 
+    pub fn reset_possible(&mut self) {
+        // Reset the possible.
+        self.clear_possible();
+        for y in 0..WIDTH {
+            for x in 0..WIDTH {
+                let item: u8 = self.board[pos(x as u8, y as u8) as usize];
+                if item != 0 {
+                    let mut g: &Group = for_row(y);
+                    for g in g.0 {
+                    self.possible[g as usize].set(item, false);
+                    }
+                    g = for_column(x);
+                    for g in g.0 {
+                    self.possible[g as usize].set(item, false);
+                    }
+                    g = for_cell(which_cell(x,y));
+                    for g in g.0 {
+                    self.possible[g as usize].set(item, false);
+                    }
+                    self.possible[pos(x,y) as usize].clear();
+                }
+            }
+        }
+    }
+
     pub fn display(&self) {
         println!("╔═══╦═══╦═══╗");
         for y in 0..WIDTH {
@@ -443,6 +479,7 @@ impl Sudoku {
         let mut rng = ChaCha20Rng::from_entropy();
 
         self.fill_board(&mut rng);
+        // Ok, this gives us a random (but fully solved) puzzle.
     }
 
     fn fill_board(&mut self, rng: &mut ChaCha20Rng) -> bool {
@@ -493,7 +530,49 @@ impl Sudoku {
         return true;
     }
 
-    pub fn make_(&mut self) {
+    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;
+    }
+
+    /*
+    fn make_(&mut self) {
         self.clear();
 
         let mut rng = ChaCha20Rng::from_entropy();
@@ -530,6 +609,7 @@ impl Sudoku {
             }
         }
     }
+    */
 
     pub fn solve(&mut self, debug: bool) -> bool {
         // Pass 1: Look for singles in the possible sets.