Basic knowledge of self and regions

This commit is contained in:
Greg Hellings
2024-10-15 22:45:44 -05:00
parent c31d638dc0
commit 6ec40c15f4
6 changed files with 268 additions and 62 deletions
+132
View File
@@ -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);
}
}
+97
View File
@@ -0,0 +1,97 @@
use std::collections::HashSet;
#[derive(Clone, Debug, Copy, Hash, Eq, PartialEq)]
pub enum CellValue {
One,
Two,
Three,
Four,
Five,
Six,
Seven,
Eight,
Nine,
}
pub struct Cell {
value: Option<CellValue>,
candidates: HashSet<CellValue>,
}
impl Cell {
pub fn value(&self) -> Option<CellValue> {
self.value
}
pub fn set_value(&mut self, value: CellValue) {
self.value = Some(value);
}
pub fn candidates(&self) -> HashSet<CellValue> {
self.candidates.clone()
}
pub fn remove_candidate(&mut self, value: CellValue) {
self.candidates.remove(&value);
}
}
impl Default for Cell {
fn default() -> Cell {
let mut candidates = HashSet::new();
candidates.insert(CellValue::One);
candidates.insert(CellValue::Two);
candidates.insert(CellValue::Three);
candidates.insert(CellValue::Four);
candidates.insert(CellValue::Five);
candidates.insert(CellValue::Six);
candidates.insert(CellValue::Seven);
candidates.insert(CellValue::Eight);
candidates.insert(CellValue::Nine);
Cell {
value: None,
candidates,
}
}
}
#[cfg(test)]
mod test {
use super::*;
use assertables::{assert_contains, assert_not_contains};
#[test]
fn inits_empty() {
let cell = Cell::default();
assert!(cell.value().is_none());
}
#[test]
fn has_all_candidates() {
let cell = Cell::default();
assert_contains!(cell.candidates(), &CellValue::One);
assert_contains!(cell.candidates(), &CellValue::Two);
assert_contains!(cell.candidates(), &CellValue::Three);
assert_contains!(cell.candidates(), &CellValue::Four);
assert_contains!(cell.candidates(), &CellValue::Five);
assert_contains!(cell.candidates(), &CellValue::Six);
assert_contains!(cell.candidates(), &CellValue::Seven);
assert_contains!(cell.candidates(), &CellValue::Eight);
assert_contains!(cell.candidates(), &CellValue::Nine);
}
#[test]
fn removed_candidate_is_gone() {
let mut cell = Cell::default();
cell.remove_candidate(CellValue::One);
assert_not_contains!(cell.candidates(), &CellValue::One);
assert_contains!(cell.candidates(), &CellValue::Two);
assert_contains!(cell.candidates(), &CellValue::Three);
assert_contains!(cell.candidates(), &CellValue::Four);
assert_contains!(cell.candidates(), &CellValue::Five);
assert_contains!(cell.candidates(), &CellValue::Six);
assert_contains!(cell.candidates(), &CellValue::Seven);
assert_contains!(cell.candidates(), &CellValue::Eight);
assert_contains!(cell.candidates(), &CellValue::Nine);
}
}
+2 -62
View File
@@ -1,62 +1,2 @@
#[derive(Clone, Debug, Copy)]
pub enum CellValue {
One,
Two,
Three,
Four,
Five,
Six,
Seven,
Eight,
Nine,
}
pub struct Cell {
value: Option<CellValue>,
candidates: Vec<CellValue>,
}
impl Default for Cell {
fn default() -> Cell {
Cell {
value: None,
candidates: vec![
CellValue::One,
CellValue::Two,
CellValue::Three,
CellValue::Four,
CellValue::Five,
CellValue::Six,
CellValue::Seven,
CellValue::Eight,
CellValue::Nine,
],
}
}
}
#[derive(Default)]
pub struct Board {
cells: [[Cell; 9]; 9],
}
impl Board {
fn value(self, x: usize, y: usize) -> Option<CellValue> {
self.cells[x][y].value
}
}
pub fn add(left: u64, right: u64) -> u64 {
left + right
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() {
let result = add(2, 2);
assert_eq!(result, 4);
}
}
pub mod cell;
pub mod board;