Basic knowledge of self and regions
This commit is contained in:
+132
@@ -0,0 +1,132 @@
|
||||
use crate::cell::{Cell, CellValue};
|
||||
use std::collections::HashSet;
|
||||
|
||||
pub struct Board {
|
||||
cells: Vec<Vec<Cell>>,
|
||||
regions: Vec<Region>,
|
||||
}
|
||||
|
||||
impl Board {
|
||||
pub fn new() -> Board {
|
||||
let mut rows = Vec::with_capacity(9);
|
||||
for _ in 0..9 {
|
||||
let mut col = Vec::with_capacity(9);
|
||||
for _ in 0..9 {
|
||||
col.push(Cell::default());
|
||||
}
|
||||
rows.push(col);
|
||||
}
|
||||
let mut regions = Vec::with_capacity(9);
|
||||
for x in 0..3 {
|
||||
for y in 0..3 {
|
||||
regions.push(Region::new(&Point(x, y)));
|
||||
}
|
||||
}
|
||||
let board = Board {
|
||||
cells: rows,
|
||||
regions
|
||||
};
|
||||
board
|
||||
}
|
||||
|
||||
pub fn value(&self, point: &Point) -> Option<CellValue> {
|
||||
self.cells[point.0][point.1].value()
|
||||
}
|
||||
|
||||
pub fn set_value(&mut self, point: &Point, value: CellValue) {
|
||||
self.cells[point.0][point.1].set_value(value);
|
||||
self.update_row(point.0, value);
|
||||
self.update_column(point.1, value);
|
||||
self.update_region(point, value);
|
||||
}
|
||||
|
||||
pub fn update_row(&mut self, x: usize, value: CellValue) {
|
||||
for i in self.cells[x].iter_mut() {
|
||||
i.remove_candidate(value);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_column(&mut self, y: usize, value: CellValue) {
|
||||
for i in self.cells.iter_mut() {
|
||||
(*i)[y].remove_candidate(value);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_region(&mut self, point: &Point, value: CellValue) {
|
||||
for i in self.regions.iter_mut() {
|
||||
if i.includes(point) {
|
||||
for pt in i.iter_mut() {
|
||||
self.cells[pt.0][pt.1].remove_candidate(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn candidates(&self, point: &Point) -> HashSet<CellValue> {
|
||||
self.cells[point.0][point.1].candidates()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
pub struct Point(usize, usize);
|
||||
|
||||
pub struct Region {
|
||||
points: Vec<Point>,
|
||||
}
|
||||
|
||||
impl Region {
|
||||
pub fn new(start: &Point)-> Region {
|
||||
let mut points = Vec::with_capacity(9);
|
||||
for x in start.0..(start.0 + 3) {
|
||||
for y in start.1..(start.1 + 3) {
|
||||
points.push(Point(x, y));
|
||||
}
|
||||
}
|
||||
Region {
|
||||
points,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> std::slice::Iter<Point> {
|
||||
self.points.iter()
|
||||
}
|
||||
|
||||
pub fn includes(&self, point: &Point) -> bool {
|
||||
self.points.contains(point)
|
||||
}
|
||||
|
||||
pub fn iter_mut(&mut self) -> std::slice::IterMut<Point> {
|
||||
self.points.iter_mut()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use assertables::{assert_contains, assert_not_contains};
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn has_none_values() {
|
||||
let board = Board::new();
|
||||
assert!(board.value(&Point(0, 0)).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_value_updates_cell() {
|
||||
let mut board = Board::new();
|
||||
board.set_value(&Point(0, 0), CellValue::One);
|
||||
let val = board.value(&Point(0, 0)).unwrap();
|
||||
assert_eq!(val, CellValue::One);
|
||||
|
||||
// Same column
|
||||
assert_not_contains!(board.candidates(&Point(0, 1)), &CellValue::One);
|
||||
// Same row
|
||||
assert_not_contains!(board.candidates(&Point(1, 0)), &CellValue::One);
|
||||
// Same sub-structure
|
||||
assert_not_contains!(board.candidates(&Point(1, 1)), &CellValue::One);
|
||||
|
||||
// Different row
|
||||
assert_contains!(board.candidates(&Point(8, 8)), &CellValue::One);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user