Add index information to Square enum.
This commit is contained in:
parent
a86542d297
commit
b51f47594d
41
src/board.rs
41
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| {
|
||||
|
|
|
@ -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,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue