|  | @@ -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();
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | +    */
 | 
	
		
			
				|  |  |  }
 |