Add index information to Square enum.

This commit is contained in:
Drew Galbraith 2024-06-20 23:16:54 -07:00
parent a86542d297
commit b51f47594d
6 changed files with 73 additions and 71 deletions

View File

@ -14,8 +14,8 @@ impl Board {
panic!("Input string not length 81: got {}", str.len()) panic!("Input string not length 81: got {}", str.len())
} }
let mut squares = Vec::new(); let mut squares = Vec::new();
for c in str.chars() { for (i, c) in str.chars().enumerate() {
squares.push(Square::from_char(c)); squares.push(Square::from_char(i as u8, c));
} }
let mut board = Board { let mut board = Board {
squares: squares.try_into().unwrap(), squares: squares.try_into().unwrap(),
@ -26,44 +26,44 @@ impl Board {
pub fn restrict_marks(&mut self) { pub fn restrict_marks(&mut self) {
let self_copy = self.clone(); let self_copy = self.clone();
for (index, ref mut square) in self.squares.iter_mut().enumerate() { for ref mut square in self.squares.iter_mut() {
if let Square::Marks(ref mut marks) = square { if let Square::Marks(index, ref mut marks) = square {
self_copy.row_from_index(index).values().for_each(|value| { self_copy.row_from_index(*index).values().for_each(|value| {
marks.set(value as usize, false); 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); 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); 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) 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) 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) 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) 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 row = index / 27;
let col = (index % 9) / 3; let col = (index % 9) / 3;
SquareIter::from_box(&self.squares, (row * 3) + col) 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) SquareIter::from_box(&self.squares, boxn)
} }
@ -71,7 +71,7 @@ impl Board {
self.squares self.squares
.iter() .iter()
.map(|sq| match sq { .map(|sq| match sq {
Square::Value(x) => x.to_string(), Square::Value(_, x) => x.to_string(),
_ => ".".to_string(), _ => ".".to_string(),
}) })
.fold(String::new(), |a, b| a + &b) .fold(String::new(), |a, b| a + &b)
@ -81,15 +81,10 @@ impl Board {
self.squares self.squares
.iter() .iter()
.map(|sq| match sq { .map(|sq| match sq {
Square::Marks(marks) => { Square::Marks(_, marks) => marks.into_iter().fold(String::new(), |mut a, b| {
marks a.push_str(&b.to_string());
.into_iter() a
.map(|a| a + 1) }),
.fold(String::new(), |mut a, b| {
a.push_str(&b.to_string());
a
})
}
_ => String::new(), _ => String::new(),
}) })
.fold(String::new(), |mut a, b| { .fold(String::new(), |mut a, b| {

View File

@ -53,39 +53,50 @@ pub struct SquareIter {
} }
impl SquareIter { impl SquareIter {
pub fn from_row(squares: &[Square; 81], row: usize) -> SquareIter { pub fn from_row(squares: &[Square; 81], row: u8) -> SquareIter {
SquareIter { SquareIter {
squares: to_row(squares, row), squares: to_row(squares, row as usize),
curr: 0, curr: 0,
} }
} }
pub fn from_col(squares: &[Square; 81], col: usize) -> SquareIter { pub fn from_col(squares: &[Square; 81], col: u8) -> SquareIter {
SquareIter { SquareIter {
squares: to_col(squares, col), squares: to_col(squares, col as usize),
curr: 0, curr: 0,
} }
} }
pub fn from_box(squares: &[Square; 81], boxn: usize) -> SquareIter { pub fn from_box(squares: &[Square; 81], boxn: u8) -> SquareIter {
SquareIter { SquareIter {
squares: to_box(squares, boxn), squares: to_box(squares, boxn as usize),
curr: 0, curr: 0,
} }
} }
pub fn values(self) -> std::iter::FilterMap<SquareIter, impl FnMut(Square) -> Option<u8>> { pub fn values_enumerate(
self,
) -> std::iter::FilterMap<SquareIter, impl FnMut(Square) -> Option<(u8, u8)>> {
self.filter_map(|sq| match sq { self.filter_map(|sq| match sq {
Square::Value(v) => Some(v), Square::Value(i, v) => Some((i, v)),
_ => None, _ => None,
}) })
} }
pub fn values(
self,
) -> std::iter::Map<
std::iter::FilterMap<SquareIter, impl FnMut(Square) -> Option<(u8, u8)>>,
impl FnMut((u8, u8)) -> u8,
> {
self.values_enumerate().map(|(i, v)| v)
}
pub fn marks( pub fn marks(
self, self,
) -> std::iter::FilterMap<SquareIter, impl FnMut(Square) -> Option<Bitmap<10>>> { ) -> std::iter::FilterMap<SquareIter, impl FnMut(Square) -> Option<Bitmap<10>>> {
self.filter_map(|sq| match sq { self.filter_map(|sq| match sq {
Square::Marks(m) => Some(m), Square::Marks(_, m) => Some(m),
_ => None, _ => None,
}) })
} }

View File

@ -7,7 +7,6 @@ mod validator;
use strategy::Strategy; use strategy::Strategy;
fn main() { fn main() {
/*
let nyt_hard = "3...184.9\ let nyt_hard = "3...184.9\
8.47.....\ 8.47.....\
.....61..\ .....61..\
@ -17,7 +16,7 @@ fn main() {
...6.1...\ ...6.1...\
17.2.....\ 17.2.....\
5........"; 5........";
*/ /*
let nyt_easy = "154..627.\ let nyt_easy = "154..627.\
..817..45\ ..817..45\
..649..1.\ ..649..1.\
@ -27,7 +26,8 @@ fn main() {
5..9....3\ 5..9....3\
.97...1.2\ .97...1.2\
8...54..."; 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) { if let validator::BoardState::Broken(ind) = validator::validate_board(&sudoku_board) {
println!("{}", sudoku_board.to_url()); println!("{}", sudoku_board.to_url());

View File

@ -2,26 +2,26 @@ use bitmaps::Bitmap;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum Square { pub enum Square {
Value(u8), Value(u8, u8),
Marks(Bitmap<10>), Marks(u8, Bitmap<10>),
} }
impl Square { impl Square {
pub fn from_char(c: char) -> Square { pub fn from_char(index: u8, c: char) -> Square {
match c { match c {
'1' => Square::Value(1), '1' => Square::Value(index, 1),
'2' => Square::Value(2), '2' => Square::Value(index, 2),
'3' => Square::Value(3), '3' => Square::Value(index, 3),
'4' => Square::Value(4), '4' => Square::Value(index, 4),
'5' => Square::Value(5), '5' => Square::Value(index, 5),
'6' => Square::Value(6), '6' => Square::Value(index, 6),
'7' => Square::Value(7), '7' => Square::Value(index, 7),
'8' => Square::Value(8), '8' => Square::Value(index, 8),
'9' => Square::Value(9), '9' => Square::Value(index, 9),
'.' => { '.' => {
let mut bm = Bitmap::mask(10); let mut bm = Bitmap::mask(10);
bm.set(0, false); bm.set(0, false);
Square::Marks(bm) Square::Marks(index, bm)
} }
_ => panic!("Unexpected character in input: {}", c), _ => panic!("Unexpected character in input: {}", c),
} }
@ -29,8 +29,8 @@ impl Square {
pub fn to_str(&self) -> String { pub fn to_str(&self) -> String {
match self { match self {
Square::Marks(_) => " ".to_string(), Square::Marks(_, _) => " ".to_string(),
Square::Value(v) => v.to_string(), Square::Value(_, v) => v.to_string(),
} }
} }
} }

View File

@ -1,7 +1,7 @@
use crate::{board::Board, square::Square, strategy::Strategy}; use crate::{board::Board, square::Square, strategy::Strategy};
pub struct NakedSingle { pub struct NakedSingle {
index: usize, index: u8,
value: u8, value: u8,
} }
@ -13,20 +13,19 @@ impl Strategy for NakedSingle {
board board
.squares .squares
.iter() .iter()
.enumerate() .filter_map(|square| match square {
.filter_map(|(index, square)| match square { Square::Marks(index, marks) => Some((index, marks)),
Square::Marks(marks) => Some((index, marks)),
_ => None, _ => None,
}) })
.find(|(_index, marks)| marks.len() == 1) .find(|(_index, marks)| marks.len() == 1)
.map(|(index, marks)| NakedSingle { .map(|(index, marks)| NakedSingle {
index, index: *index,
value: marks.first_index().unwrap() as u8, value: marks.first_index().unwrap() as u8,
}) })
} }
fn apply(&self, mut board: Board) -> Board { 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.restrict_marks();
board board
} }

View File

@ -6,45 +6,42 @@ pub enum BoardState {
InProgress, InProgress,
} }
fn are_unique<T>(iter: T) -> bool fn check_unique<T>(iter: T) -> Option<BoardState>
where where
T: Iterator<Item = u8>, T: Iterator<Item = (u8, u8)>,
{ {
let mut bitmap: bitmaps::Bitmap<10> = bitmaps::Bitmap::new(); let mut bitmap: bitmaps::Bitmap<10> = bitmaps::Bitmap::new();
for item in iter { for (ind, item) in iter {
if bitmap.get(item as usize) { if bitmap.get(item as usize) {
return false; return Some(BoardState::Broken(ind));
} }
bitmap.set(item as usize, true); bitmap.set(item as usize, true);
} }
true None
} }
pub fn validate_board(board: &Board) -> BoardState { pub fn validate_board(board: &Board) -> BoardState {
for r in 0..9 { for r in 0..9 {
if !are_unique(board.row(r).values()) { if let Some(s) = check_unique(board.row(r).values_enumerate()) {
// TODO: Add the index. return s;
return BoardState::Broken(0);
} }
} }
for c in 0..9 { for c in 0..9 {
if !are_unique(board.col(c).values()) { if let Some(s) = check_unique(board.col(c).values_enumerate()) {
// TODO: Add the index. return s;
return BoardState::Broken(0);
} }
} }
for b in 0..9 { for b in 0..9 {
if !are_unique(board.boxn(b).values()) { if let Some(s) = check_unique(board.boxn(b).values_enumerate()) {
// TODO: Add the index. return s;
return BoardState::Broken(0);
} }
} }
if board.squares.iter().any(|sq| match sq { if board.squares.iter().any(|sq| match sq {
Square::Marks(_) => true, Square::Marks(..) => true,
_ => false, _ => false,
}) { }) {
BoardState::InProgress BoardState::InProgress