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())
|
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| {
|
||||||
|
|
|
@ -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,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue