Przeglądaj źródła

Added initial solver routine.

Steve Thielemann 10 miesięcy temu
rodzic
commit
b27d436b4b
1 zmienionych plików z 93 dodań i 12 usunięć
  1. 93 12
      src/main.rs

+ 93 - 12
src/main.rs

@@ -4,6 +4,8 @@ use serde_xml_rs::{from_reader, from_str, to_string};
 use std::fmt;
 use std::fs::File;
 
+use std::collections::HashSet;
+
 #[derive(Debug, Serialize, Deserialize, PartialEq)]
 struct Graph {
     order: i32,
@@ -39,7 +41,7 @@ const MAX_SIZE: u8 = 81;
 #[derive(Debug)]
 struct Sudoku {
     board: [u8; MAX_SIZE as usize],
-    possible: [[u8; SIZE as usize]; MAX_SIZE as usize],
+    possible: [HashSet<u8>; MAX_SIZE as usize],
 }
 
 // Translate x,y to position in board.
@@ -52,12 +54,26 @@ const fn xy(pos: u8) -> (u8, u8) {
     ((pos % SIZE), (pos / SIZE))
 }
 
+/*
+(0 .. 10)
+                        .map(|_| HashSet::<usize>::new())
+                        .collect();
+
+let arr: [Vec<u32>; 10] = [(); 10].map(|_| Vec::with_capacity(100));
+
+*/
+
 impl Sudoku {
     fn new() -> Self {
+        // let b : HashSet<u8> = HashSet::from_iter(1..=9);
+
         let s = Sudoku {
             board: [0; MAX_SIZE as usize],
+            possible: [(); MAX_SIZE as usize].map(|_| HashSet::from_iter(1..=9)),
+            // possible: [HashSet::from_iter(1..=9); MAX_SIZE as usize],
             // possible: [[0; SIZE as usize]; MAX_SIZE as usize],
-            possible: [[1, 2, 3, 4, 5, 6, 7, 8, 9]; MAX_SIZE as usize],
+            // possible: [(0..MAX_SIZE).map( |_| (1..=9).collect())],
+            // possible: [(1..=9).map(|_| HashSet::new()).collect(); MAX_SIZE as usize],
         };
         s
     }
@@ -65,7 +81,14 @@ impl Sudoku {
     fn clear(&mut self) {
         for x in 0..MAX_SIZE {
             self.board[x as usize] = 0;
-            self.possible[x as usize] = [1, 2, 3, 4, 5, 6, 7, 8, 9];
+            self.possible = [(); MAX_SIZE as usize].map(|_| HashSet::from_iter(1..=9));
+            /*
+            self.possible[x as usize].clear();
+            for i in 1..=9 {
+                self.possible[x as usize].insert(i);
+            }
+            */
+            // self.possible[x as usize] = [1, 2, 3, 4, 5, 6, 7, 8, 9];
         }
     }
 
@@ -75,7 +98,8 @@ impl Sudoku {
         let mut y: u8 = 0;
         for ch in s.chars() {
             if ch >= 'b' {
-                self.board[pos(x, y) as usize] = ch as u8 - 'a' as u8;
+                self.set(x, y, ch as u8 - 'a' as u8);
+                // self.board[pos(x, y) as usize] = ch as u8 - 'a' as u8;
             };
             y += 1;
             if y >= SIZE {
@@ -85,6 +109,28 @@ impl Sudoku {
         }
     }
 
+    fn set(&mut self, x: u8, y: u8, value: u8) {
+        self.board[pos(x, y) as usize] = value;
+        // Ok, update the possible
+        let mut g = Group::new();
+        g.for_row(x, y);
+        for g in g.items {
+            // remove value from these sets.
+            self.possible[g as usize].take(&value);
+        }
+        g.for_column(x, y);
+        for g in g.items {
+            // remove value from these sets.
+            self.possible[g as usize].take(&value);
+        }
+        g.for_block(x, y);
+        for g in g.items {
+            // remove value from these sets.
+            self.possible[g as usize].take(&value);
+        }
+        self.possible[pos(x, y) as usize].clear();
+    }
+
     fn display(&self) {
         println!("╔═══╦═══╦═══╗");
         for y in 0..SIZE {
@@ -114,20 +160,47 @@ impl Sudoku {
     fn display_possible(&self) {
         for y in 0..SIZE {
             for x in 0..SIZE {
+                let mut possible = String::new();
+
+                for p in self.possible[pos(x, y) as usize].iter() {
+                    possible += format!("{}", p).as_str();
+                }
+
+                // for i in 0..SIZE {
+                // let &pos = self.possible[pos(x, y) as usize];
                 print!("({},{}):", x, y);
-                for i in 0..SIZE {
-                    let pos = self.possible[pos(x, y) as usize][i as usize];
-                    if pos == 0 {
-                        print!(" ");
-                    } else {
-                        print!("{}", pos);
-                    }
+                // print!("{:20}", format!("{:?}", self.possible[pos(x, y) as usize]));
+                print!("{:9}", possible);
+                /*
+                if pos == 0 {
+                    print!(" ");
+                } else {
+                    print!("{}", pos);
                 }
-                print!(" ");
+                */
+                // }
+                // print!(" ");
             }
             println!("");
         }
     }
+
+    fn solve(&mut self) -> bool {
+        // Pass 1: Look for singles in the possible sets.
+        let mut found_something = false;
+
+        for i in 0..MAX_SIZE {
+            if self.possible[i as usize].len() == 1 {
+                // Get the value
+                let value = self.possible[i as usize].iter().next().cloned().unwrap();
+                // Found one!
+                println!("Set {:?} to {}", xy(i), value);
+                self.set(xy(i).0, xy(i).1, value);
+                found_something = true;
+            }
+        }
+        found_something
+    }
 }
 
 // #[derive(Debug)]
@@ -204,6 +277,13 @@ fn main() {
     s.display();
     s.display_possible();
 
+    while s.solve() {
+        println!("Try it again...");
+    }
+    s.display();
+    s.display_possible();
+
+    /*
     let mut g = Group::new();
     g.for_row(1, 1);
     print!("Row: ");
@@ -221,4 +301,5 @@ fn main() {
         println!("({},{} {:#?})", i, i, g);
         // g.display();
     }
+    */
 }