diff --git a/src/board.rs b/src/board.rs index 4a2396c..41d926d 100644 --- a/src/board.rs +++ b/src/board.rs @@ -14,8 +14,8 @@ impl Board { panic!("Input string not length 81: got {}", str.len()) } let mut squares = Vec::new(); - for c in str.chars() { - squares.push(Square::from_char(c)); + for (i, c) in str.chars().enumerate() { + squares.push(Square::from_char(i as u8, c)); } let mut board = Board { squares: squares.try_into().unwrap(), @@ -26,44 +26,44 @@ impl Board { pub fn restrict_marks(&mut self) { let self_copy = self.clone(); - for (index, ref mut square) in self.squares.iter_mut().enumerate() { - if let Square::Marks(ref mut marks) = square { - self_copy.row_from_index(index).values().for_each(|value| { + for ref mut square in self.squares.iter_mut() { + if let Square::Marks(index, ref mut marks) = square { + self_copy.row_from_index(*index).values().for_each(|value| { marks.set(value as usize, false); }); - self_copy.col_from_index(index).values().for_each(|value| { + self_copy.col_from_index(*index).values().for_each(|value| { marks.set(value as usize, false); }); - self_copy.box_from_index(index).values().for_each(|value| { + self_copy.box_from_index(*index).values().for_each(|value| { marks.set(value as usize, false); }); } } } - pub fn row_from_index(&self, index: usize) -> SquareIter { + pub fn row_from_index(&self, index: u8) -> SquareIter { SquareIter::from_row(&self.squares, index / 9) } - pub fn row(&self, row: usize) -> SquareIter { + pub fn row(&self, row: u8) -> SquareIter { SquareIter::from_row(&self.squares, row) } - pub fn col_from_index(&self, index: usize) -> SquareIter { + pub fn col_from_index(&self, index: u8) -> SquareIter { SquareIter::from_col(&self.squares, index % 9) } - pub fn col(&self, col: usize) -> SquareIter { + pub fn col(&self, col: u8) -> SquareIter { SquareIter::from_col(&self.squares, col) } - pub fn box_from_index(&self, index: usize) -> SquareIter { + pub fn box_from_index(&self, index: u8) -> SquareIter { let row = index / 27; let col = (index % 9) / 3; SquareIter::from_box(&self.squares, (row * 3) + col) } - pub fn boxn(&self, boxn: usize) -> SquareIter { + pub fn boxn(&self, boxn: u8) -> SquareIter { SquareIter::from_box(&self.squares, boxn) } @@ -71,7 +71,7 @@ impl Board { self.squares .iter() .map(|sq| match sq { - Square::Value(x) => x.to_string(), + Square::Value(_, x) => x.to_string(), _ => ".".to_string(), }) .fold(String::new(), |a, b| a + &b) @@ -81,15 +81,10 @@ impl Board { self.squares .iter() .map(|sq| match sq { - Square::Marks(marks) => { - marks - .into_iter() - .map(|a| a + 1) - .fold(String::new(), |mut a, b| { - a.push_str(&b.to_string()); - a - }) - } + Square::Marks(_, marks) => marks.into_iter().fold(String::new(), |mut a, b| { + a.push_str(&b.to_string()); + a + }), _ => String::new(), }) .fold(String::new(), |mut a, b| { diff --git a/src/iterators.rs b/src/iterators.rs index 1bed6f1..f16a2d6 100644 --- a/src/iterators.rs +++ b/src/iterators.rs @@ -53,39 +53,50 @@ pub struct SquareIter { } impl SquareIter { - pub fn from_row(squares: &[Square; 81], row: usize) -> SquareIter { + pub fn from_row(squares: &[Square; 81], row: u8) -> SquareIter { SquareIter { - squares: to_row(squares, row), + squares: to_row(squares, row as usize), curr: 0, } } - pub fn from_col(squares: &[Square; 81], col: usize) -> SquareIter { + pub fn from_col(squares: &[Square; 81], col: u8) -> SquareIter { SquareIter { - squares: to_col(squares, col), + squares: to_col(squares, col as usize), curr: 0, } } - pub fn from_box(squares: &[Square; 81], boxn: usize) -> SquareIter { + pub fn from_box(squares: &[Square; 81], boxn: u8) -> SquareIter { SquareIter { - squares: to_box(squares, boxn), + squares: to_box(squares, boxn as usize), curr: 0, } } - pub fn values(self) -> std::iter::FilterMap Option> { + pub fn values_enumerate( + self, + ) -> std::iter::FilterMap Option<(u8, u8)>> { self.filter_map(|sq| match sq { - Square::Value(v) => Some(v), + Square::Value(i, v) => Some((i, v)), _ => None, }) } + pub fn values( + self, + ) -> std::iter::Map< + std::iter::FilterMap Option<(u8, u8)>>, + impl FnMut((u8, u8)) -> u8, + > { + self.values_enumerate().map(|(i, v)| v) + } + pub fn marks( self, ) -> std::iter::FilterMap Option>> { self.filter_map(|sq| match sq { - Square::Marks(m) => Some(m), + Square::Marks(_, m) => Some(m), _ => None, }) } diff --git a/src/main.rs b/src/main.rs index d8a3adb..e1af7a0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,7 +7,6 @@ mod validator; use strategy::Strategy; fn main() { - /* let nyt_hard = "3...184.9\ 8.47.....\ .....61..\ @@ -17,7 +16,7 @@ fn main() { ...6.1...\ 17.2.....\ 5........"; - */ + /* let nyt_easy = "154..627.\ ..817..45\ ..649..1.\ @@ -27,7 +26,8 @@ fn main() { 5..9....3\ .97...1.2\ 8...54..."; - let mut sudoku_board = board::Board::from_string(nyt_easy); + */ + let mut sudoku_board = board::Board::from_string(nyt_hard); if let validator::BoardState::Broken(ind) = validator::validate_board(&sudoku_board) { println!("{}", sudoku_board.to_url()); diff --git a/src/square.rs b/src/square.rs index 675ccd7..9200cac 100644 --- a/src/square.rs +++ b/src/square.rs @@ -2,26 +2,26 @@ use bitmaps::Bitmap; #[derive(Clone, Debug)] pub enum Square { - Value(u8), - Marks(Bitmap<10>), + Value(u8, u8), + Marks(u8, Bitmap<10>), } impl Square { - pub fn from_char(c: char) -> Square { + pub fn from_char(index: u8, c: char) -> Square { match c { - '1' => Square::Value(1), - '2' => Square::Value(2), - '3' => Square::Value(3), - '4' => Square::Value(4), - '5' => Square::Value(5), - '6' => Square::Value(6), - '7' => Square::Value(7), - '8' => Square::Value(8), - '9' => Square::Value(9), + '1' => Square::Value(index, 1), + '2' => Square::Value(index, 2), + '3' => Square::Value(index, 3), + '4' => Square::Value(index, 4), + '5' => Square::Value(index, 5), + '6' => Square::Value(index, 6), + '7' => Square::Value(index, 7), + '8' => Square::Value(index, 8), + '9' => Square::Value(index, 9), '.' => { let mut bm = Bitmap::mask(10); bm.set(0, false); - Square::Marks(bm) + Square::Marks(index, bm) } _ => panic!("Unexpected character in input: {}", c), } @@ -29,8 +29,8 @@ impl Square { pub fn to_str(&self) -> String { match self { - Square::Marks(_) => " ".to_string(), - Square::Value(v) => v.to_string(), + Square::Marks(_, _) => " ".to_string(), + Square::Value(_, v) => v.to_string(), } } } diff --git a/src/strategy/naked_single.rs b/src/strategy/naked_single.rs index 46d6ba7..c4730fb 100644 --- a/src/strategy/naked_single.rs +++ b/src/strategy/naked_single.rs @@ -1,7 +1,7 @@ use crate::{board::Board, square::Square, strategy::Strategy}; pub struct NakedSingle { - index: usize, + index: u8, value: u8, } @@ -13,20 +13,19 @@ impl Strategy for NakedSingle { board .squares .iter() - .enumerate() - .filter_map(|(index, square)| match square { - Square::Marks(marks) => Some((index, marks)), + .filter_map(|square| match square { + Square::Marks(index, marks) => Some((index, marks)), _ => None, }) .find(|(_index, marks)| marks.len() == 1) .map(|(index, marks)| NakedSingle { - index, + index: *index, value: marks.first_index().unwrap() as u8, }) } fn apply(&self, mut board: Board) -> Board { - board.squares[self.index] = Square::Value(self.value); + board.squares[self.index as usize] = Square::Value(self.index, self.value); board.restrict_marks(); board } diff --git a/src/validator.rs b/src/validator.rs index 71f8941..6fc95e7 100644 --- a/src/validator.rs +++ b/src/validator.rs @@ -6,45 +6,42 @@ pub enum BoardState { InProgress, } -fn are_unique(iter: T) -> bool +fn check_unique(iter: T) -> Option where - T: Iterator, + T: Iterator, { let mut bitmap: bitmaps::Bitmap<10> = bitmaps::Bitmap::new(); - for item in iter { + for (ind, item) in iter { if bitmap.get(item as usize) { - return false; + return Some(BoardState::Broken(ind)); } bitmap.set(item as usize, true); } - true + None } pub fn validate_board(board: &Board) -> BoardState { for r in 0..9 { - if !are_unique(board.row(r).values()) { - // TODO: Add the index. - return BoardState::Broken(0); + if let Some(s) = check_unique(board.row(r).values_enumerate()) { + return s; } } for c in 0..9 { - if !are_unique(board.col(c).values()) { - // TODO: Add the index. - return BoardState::Broken(0); + if let Some(s) = check_unique(board.col(c).values_enumerate()) { + return s; } } for b in 0..9 { - if !are_unique(board.boxn(b).values()) { - // TODO: Add the index. - return BoardState::Broken(0); + if let Some(s) = check_unique(board.boxn(b).values_enumerate()) { + return s; } } if board.squares.iter().any(|sq| match sq { - Square::Marks(_) => true, + Square::Marks(..) => true, _ => false, }) { BoardState::InProgress