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())
}
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| {

View File

@ -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<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 {
Square::Value(v) => Some(v),
Square::Value(i, v) => Some((i, v)),
_ => 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(
self,
) -> std::iter::FilterMap<SquareIter, impl FnMut(Square) -> Option<Bitmap<10>>> {
self.filter_map(|sq| match sq {
Square::Marks(m) => Some(m),
Square::Marks(_, m) => Some(m),
_ => None,
})
}

View File

@ -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());

View File

@ -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(),
}
}
}

View File

@ -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
}

View File

@ -6,45 +6,42 @@ pub enum BoardState {
InProgress,
}
fn are_unique<T>(iter: T) -> bool
fn check_unique<T>(iter: T) -> Option<BoardState>
where
T: Iterator<Item = u8>,
T: Iterator<Item = (u8, u8)>,
{
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