use serde_derive::{Deserialize, Serialize}; use serde_xml_rs::{from_reader, from_str, to_string}; use std::fmt; use std::fs::File; #[derive(Debug, Serialize, Deserialize, PartialEq)] struct Graph { order: i32, #[serde(rename = "type")] game_type: String, #[serde(rename = "specific-type")] specific_type: String, } #[derive(Debug, Serialize, Deserialize, PartialEq)] struct Puzzle { graph: Graph, values: String, solution: String, } #[derive(Debug, Serialize, Deserialize, PartialEq)] struct Game { #[serde(rename = "had-help")] help: i16, #[serde(rename = "msecs-elapsed")] elapsed: u32, puzzle: Puzzle, } #[derive(Debug, Serialize, Deserialize, PartialEq)] struct Ksudoku { game: Game, } const SIZE: u8 = 9; const MAX_SIZE: u8 = 81; #[derive(Debug)] struct Sudoku { board: [u8; MAX_SIZE as usize], possible: [[u8; SIZE as usize]; MAX_SIZE as usize], } // Translate x,y to position in board. const fn pos(x: u8, y: u8) -> u8 { x + (y * SIZE as u8) } // Translate post to x,y in board. const fn xy(pos: u8) -> (u8, u8) { ((pos % SIZE), (pos / SIZE)) } impl Sudoku { fn new() -> Self { let s = Sudoku { board: [0; 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], }; s } 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]; } } fn load_xsudoku(&mut self, s: &str) { self.clear(); let mut x: u8 = 0; 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; }; y += 1; if y >= SIZE { y = 0; x += 1; } } } fn display(&self) { println!("╔═══╦═══╦═══╗"); for y in 0..SIZE { print!("║"); for x in 0..SIZE { let item = self.board[pos(x as u8, y as u8) as usize]; if item == 0 { print!(" "); } else if (item >= 1) && (item <= 9) { print!("{}", item); } if x % 3 == 2 { print!("║"); } } println!(""); if y % 3 == 2 { if y + 1 == SIZE { println!("╚═══╩═══╩═══╝"); } else { println!("╠═══╬═══╬═══╣"); } } } } fn display_possible(&self) { for y in 0..SIZE { for x in 0..SIZE { 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!(" "); } println!(""); } } } // #[derive(Debug)] struct Group { items: [u8; SIZE as usize], } impl fmt::Debug for Group { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { if f.alternate() { write!(f, "Group {{ {}[{},{}], {}[{},{}], {}[{},{}], {}[{},{}], {}[{},{}], {}[{},{}], {}[{},{}], {}[{},{}], {}[{},{}] }}", self.items[0], xy(self.items[0]).0, xy(self.items[0]).1, self.items[1], xy(self.items[1]).0, xy(self.items[1]).1, self.items[2], xy(self.items[2]).0, xy(self.items[2]).1, self.items[3], xy(self.items[3]).0, xy(self.items[3]).1, self.items[4], xy(self.items[4]).0, xy(self.items[4]).1, self.items[5], xy(self.items[5]).0, xy(self.items[5]).1, self.items[6], xy(self.items[6]).0, xy(self.items[6]).1, self.items[7], xy(self.items[7]).0, xy(self.items[7]).1, self.items[8], xy(self.items[8]).0, xy(self.items[8]).1, ) } else { f.debug_struct("Group").field("items", &self.items).finish() } } } impl Group { fn new() -> Self { Group { items: [0; SIZE as usize], } } fn for_column(&mut self, x: u8, _y: u8) { for y in 0..SIZE { self.items[y as usize] = pos(x, y); } } fn for_row(&mut self, _x: u8, y: u8) { for x in 0..SIZE { self.items[x as usize] = pos(x, y); } } fn for_block(&mut self, x: u8, y: u8) { // Find starting block positions let sb_x = x - (x % 3); let sb_y = y - (y % 3); for i in 0..SIZE { let ix = i % 3; let iy = i / 3; // println!("i = {}, sb.x = {} sb.y = {}, ix = {} iy = {}", i, sb_x, sb_y, ix, iy); self.items[i as usize] = pos(sb_x + ix, sb_y + iy); } } fn display(&self) { for i in 0..SIZE { let v = self.items[i as usize]; print!("{} [{},{}] ", v, xy(v).0, xy(v).1); } println!(""); } } fn main() { let filename = "../puzzle1"; let fh = File::open(filename).unwrap(); let puzzle: Ksudoku = from_reader(fh).unwrap(); println!("Puzzle: {:?}", puzzle); let mut s = Sudoku::new(); s.load_xsudoku(&puzzle.game.puzzle.values); s.display(); s.display_possible(); let mut g = Group::new(); g.for_row(1, 1); print!("Row: "); println!("{:?}", g); println!("{:#?}", g); // g.display(); print!("Col: "); g.for_column(1, 1); println!("{:?}", g); // g.display(); println!("Blk testing output: "); for i in 0..SIZE { g.for_block(i, i); println!("({},{} {:#?})", i, i, g); // g.display(); } }