1
0
Fork 0
sudoku_constraint_solver/src/board.rs

113 lines
2.9 KiB
Rust

use std::collections::HashMap;
/**
Contains the values on a given board as well as a bit of metadata.
The actual tiles are stored in a `HashMap` to allow disparate data.
*/
#[derive(Clone, Debug)]
pub struct Board {
width: usize,
height: usize,
num_options: usize,
tiles: HashMap<(usize, usize), usize>,
}
impl Board {
/**
Creates a new board.
Panics if width or height are zero, or there are less than two options.
*/
pub fn new(width: usize, height: usize, num_options: usize) -> Self {
assert!(width != 0);
assert!(height != 0);
assert!(num_options >= 2);
Self {
width,
height,
num_options,
tiles: HashMap::new(),
}
}
pub fn get_width(&self) -> usize {
self.width
}
pub fn get_height(&self) -> usize {
self.height
}
pub fn get_num_options(&self) -> usize {
self.num_options
}
/**
Set the value of a tile, or removes it if `None` is given.
Returns the previous value or `None`.
Panics if `x` or `y` are beyond the boards dimensions or `value` is greater or equal to `num_options`.
*/
pub fn set_tile(&mut self, x: usize, y: usize, value: Option<usize>) -> Option<usize> {
assert!(x < self.width);
assert!(y < self.height);
if let Some(value) = value {
assert!(value < self.num_options);
self.tiles.insert((x, y), value)
} else {
self.tiles.remove(&(x, y))
}
}
/**
Get the value of a tile, or `None` if no value is known.
Panics if `x` or `y` are beyond the boards dimensions.
*/
pub fn get_tile(&self, x: usize, y: usize) -> Option<usize> {
assert!(x < self.width);
assert!(y < self.height);
self.tiles.get(&(x, y)).copied()
}
/**
Get all the values of a column, in ascending y order.
If a value in one row is not present, `None` is given instead.
*/
pub fn get_column(&self, x: usize) -> Vec<Option<usize>> {
(0..self.height)
.map(|y| self.tiles.get(&(x, y)).copied())
.collect()
}
/**
Get all the values of a row, in ascending x order.
If a value in one column is not present, `None` is given instead.
*/
pub fn get_row(&self, y: usize) -> Vec<Option<usize>> {
(0..self.width)
.map(|x| self.tiles.get(&(x, y)).copied())
.collect()
}
}
impl std::fmt::Display for Board {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
for x in 0..self.width {
for y in 0..self.height {
if let Some(value) = self.tiles.get(&(x, y)) {
write!(f, "{value}\t")?;
} else {
write!(f, "?\t")?;
}
}
writeln!(f)?;
}
Ok(())
}
}