clippy and fmt

This commit is contained in:
2024-01-29 15:55:53 +01:00
parent 3b523257f0
commit 6ad197871f
2 changed files with 273 additions and 223 deletions

1
rustfmt.toml Normal file
View File

@@ -0,0 +1 @@
max_width = 120

View File

@@ -1,53 +1,60 @@
use std::fmt;
use arr_macro::arr; use arr_macro::arr;
use std::fmt;
const GRID_SIZE: usize = 9; const GRID_SIZE: usize = 9;
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq, Clone, Copy)]
#[derive(Clone, Copy)]
pub struct PossibleValues([bool; GRID_SIZE]); pub struct PossibleValues([bool; GRID_SIZE]);
impl PossibleValues { impl PossibleValues {
fn get_value(&self) -> Option<u8> { fn get_value(&self) -> Option<u8> {
let mut val = 0u8; let mut val = 0u8;
for x in 0..GRID_SIZE { for x in 0..GRID_SIZE {
if self.0[x] { if self.0[x] {
if val != 0 { panic!("get_value called on PossibleValue with more than one possiblitiy {}", self) } if val != 0 {
val = (x+1) as u8; panic!(
} "get_value called on PossibleValue with more than one possiblitiy {}",
} self
if val == 0 { None } else { Some(val) } )
}
val = (x + 1) as u8;
}
}
if val == 0 {
None
} else {
Some(val)
}
} }
fn get_values(&self) -> Vec<u8> { fn get_values(&self) -> Vec<u8> {
let mut v = Vec::<u8>::new(); let mut v = Vec::<u8>::new();
for x in 0..GRID_SIZE { for x in 0..GRID_SIZE {
if self.0[x] { if self.0[x] {
v.push((x+1) as u8) v.push((x + 1) as u8)
} }
} }
v v
} }
fn get_count(&self) -> u8 { fn get_count(&self) -> u8 {
let mut count = 0u8; let mut count = 0u8;
for x in 0..GRID_SIZE { for x in 0..GRID_SIZE {
if self.0[x] { if self.0[x] {
count += 1; count += 1;
} }
} }
count count
} }
} }
impl fmt::Display for PossibleValues { impl fmt::Display for PossibleValues {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.pad(format!("{:?}", self.get_values()).as_str()) f.pad(format!("{:?}", self.get_values()).as_str())
} }
} }
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq, Clone, Copy)]
#[derive(Clone, Copy)]
pub enum CellValue { pub enum CellValue {
None, None,
Fixed(u8), Fixed(u8),
@@ -56,27 +63,26 @@ pub enum CellValue {
impl CellValue { impl CellValue {
fn from_possible(possible: PossibleValues) -> CellValue { fn from_possible(possible: PossibleValues) -> CellValue {
let cnt = possible.get_count(); let cnt = possible.get_count();
match cnt { match cnt {
0 => CellValue::None, 0 => CellValue::None,
1 => CellValue::Fixed(possible.get_value().unwrap()), 1 => CellValue::Fixed(possible.get_value().unwrap()),
_ => CellValue::Possible(possible), _ => CellValue::Possible(possible),
} }
} }
} }
impl fmt::Display for CellValue { impl fmt::Display for CellValue {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self { match &self {
CellValue::Possible(x) => write!(f, "{:27}", x), CellValue::Possible(x) => write!(f, "{:27}", x),
CellValue::None => write!(f, "{:27}", "X"), CellValue::None => write!(f, "{:27}", "X"),
CellValue::Fixed(x) => write!(f, "{:<27}", x), CellValue::Fixed(x) => write!(f, "{:<27}", x),
} }
} }
} }
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq, Clone, Copy)]
#[derive(Clone, Copy)]
pub struct Grid { pub struct Grid {
data: [CellValue; GRID_SIZE * GRID_SIZE], data: [CellValue; GRID_SIZE * GRID_SIZE],
} }
@@ -91,10 +97,12 @@ impl<'a> Iterator for GridRowIterator<'a> {
type Item = CellValue; type Item = CellValue;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
if self.pos >= GRID_SIZE { return None; } if self.pos >= GRID_SIZE {
let curr = self.parent.at(self.row, self.pos); return None;
self.pos += 1; }
Some(*curr) let curr = self.parent.at(self.row, self.pos);
self.pos += 1;
Some(*curr)
} }
} }
@@ -108,10 +116,12 @@ impl<'a> Iterator for GridColIterator<'a> {
type Item = CellValue; type Item = CellValue;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
if self.pos >= GRID_SIZE { return None; } if self.pos >= GRID_SIZE {
let curr = self.parent.at(self.pos, self.col); return None;
self.pos += 1; }
Some(*curr) let curr = self.parent.at(self.pos, self.col);
self.pos += 1;
Some(*curr)
} }
} }
@@ -119,261 +129,289 @@ pub struct GridBlockIterator<'a> {
parent: &'a Grid, parent: &'a Grid,
pos: usize, pos: usize,
row: usize, row: usize,
col: usize col: usize,
} }
impl<'a> Iterator for GridBlockIterator<'a> { impl<'a> Iterator for GridBlockIterator<'a> {
type Item = CellValue; type Item = CellValue;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
if self.pos >= GRID_SIZE { return None; } if self.pos >= GRID_SIZE {
let curr = self.parent.at(self.row + self.pos % 3, self.col + self.pos / 3); return None;
self.pos += 1; }
Some(*curr) let curr = self.parent.at(self.row + self.pos % 3, self.col + self.pos / 3);
self.pos += 1;
Some(*curr)
}
}
impl Default for Grid {
fn default() -> Self {
Self::new()
} }
} }
impl Grid { impl Grid {
pub fn new() -> Grid { pub fn new() -> Grid {
Grid{data: arr![CellValue::None; 81]} Grid {
data: arr![CellValue::None; 81],
}
} }
pub fn from_array(input: [u8; 81]) -> Grid { pub fn from_array(input: [u8; 81]) -> Grid {
let mut g = Grid::new(); let mut g = Grid::new();
for row in 0..GRID_SIZE { for row in 0..GRID_SIZE {
for col in 0..GRID_SIZE { for col in 0..GRID_SIZE {
match input[row * GRID_SIZE + col] { match input[row * GRID_SIZE + col] {
0 => *g.at_mut(row, col) = CellValue::None, 0 => *g.at_mut(row, col) = CellValue::None,
other => *g.at_mut(row, col) = CellValue::Fixed(other) other => *g.at_mut(row, col) = CellValue::Fixed(other),
} }
} }
} }
g.update(); g.update();
g g
} }
pub fn row_iter(&self, row: usize) -> GridRowIterator { pub fn row_iter(&self, row: usize) -> GridRowIterator {
GridRowIterator{parent: self, pos: 0, row} GridRowIterator {
parent: self,
pos: 0,
row,
}
} }
pub fn col_iter(&self, col: usize) -> GridColIterator { pub fn col_iter(&self, col: usize) -> GridColIterator {
GridColIterator{parent: self, pos: 0, col} GridColIterator {
parent: self,
pos: 0,
col,
}
} }
pub fn block_iter(&self, row: usize, col: usize) -> GridBlockIterator { pub fn block_iter(&self, row: usize, col: usize) -> GridBlockIterator {
let row = (row / 3) * 3; let row = (row / 3) * 3;
let col = (col / 3) * 3; let col = (col / 3) * 3;
GridBlockIterator{parent: self, pos: 0, row, col} GridBlockIterator {
parent: self,
pos: 0,
row,
col,
}
} }
// For all cells that are not fixed, compute possible values // For all cells that are not fixed, compute possible values
pub fn update(&mut self) { pub fn update(&mut self) {
for row in 0..GRID_SIZE { for row in 0..GRID_SIZE {
for col in 0..GRID_SIZE { for col in 0..GRID_SIZE {
if let CellValue::Fixed(_) = &self.at(row, col) { continue; } if let CellValue::Fixed(_) = &self.at(row, col) {
*self.at_mut(row, col) = self.compute_possible(row, col); continue;
} }
} *self.at_mut(row, col) = self.compute_possible(row, col);
}
}
} }
// Find the shortest list of possible values // Find the shortest list of possible values
pub fn find_shortest_possibles(&self) -> Option<(usize, usize, PossibleValues)> { pub fn find_shortest_possibles(&self) -> Option<(usize, usize, PossibleValues)> {
let mut len = 9; let mut len = 9;
let mut shortest_row : Option<usize> = None; let mut shortest_row: Option<usize> = None;
let mut shortest_col : Option<usize> = None; let mut shortest_col: Option<usize> = None;
for row in 0..GRID_SIZE { for row in 0..GRID_SIZE {
for col in 0..GRID_SIZE { for col in 0..GRID_SIZE {
if let CellValue::Possible(x) = &self.at(row, col) { if let CellValue::Possible(x) = &self.at(row, col) {
if x.get_count() <= len { if x.get_count() <= len {
len = x.get_count(); len = x.get_count();
shortest_row = Some(row); shortest_row = Some(row);
shortest_col = Some(col); shortest_col = Some(col);
} }
} }
} }
} }
if let Some(row) = shortest_row { if let Some(row) = shortest_row {
let col = shortest_col.unwrap(); let col = shortest_col.unwrap();
let CellValue::Possible(val) = &self.at(row, col) else { panic!(); }; let CellValue::Possible(val) = &self.at(row, col) else {
Some((row, col, *val)) panic!();
} else { };
None Some((row, col, *val))
} } else {
None
}
} }
pub fn done(&self) -> bool { pub fn done(&self) -> bool {
for row in 0..GRID_SIZE { for row in 0..GRID_SIZE {
for col in 0..GRID_SIZE { for col in 0..GRID_SIZE {
match &self.at(row, col) { match &self.at(row, col) {
CellValue::Possible(_) => return false, CellValue::Possible(_) => return false,
CellValue::None => return false, CellValue::None => return false,
CellValue::Fixed(_) => continue, CellValue::Fixed(_) => continue,
} }
} }
} }
return true; true
} }
pub fn possible(&self) -> bool { pub fn possible(&self) -> bool {
for row in 0..GRID_SIZE { for row in 0..GRID_SIZE {
for col in 0..GRID_SIZE { for col in 0..GRID_SIZE {
match &self.at(row, col) { match &self.at(row, col) {
CellValue::None => return false, CellValue::None => return false,
_ => continue, _ => continue,
} }
} }
} }
return true; true
} }
pub fn at(&self, row: usize, col: usize) -> &CellValue { pub fn at(&self, row: usize, col: usize) -> &CellValue {
if row >= GRID_SIZE || col >= GRID_SIZE { panic!("out of bounds access"); } if row >= GRID_SIZE || col >= GRID_SIZE {
&self.data[row*GRID_SIZE + col] panic!("out of bounds access");
}
&self.data[row * GRID_SIZE + col]
} }
pub fn at_mut(&mut self, row: usize, col: usize) -> &mut CellValue { pub fn at_mut(&mut self, row: usize, col: usize) -> &mut CellValue {
if row >= GRID_SIZE || col >= GRID_SIZE { panic!("out of bounds access"); } if row >= GRID_SIZE || col >= GRID_SIZE {
&mut self.data[row*GRID_SIZE + col] panic!("out of bounds access");
} }
&mut self.data[row * GRID_SIZE + col]
fn get_value(&self, row: usize, col: usize) -> Option<u8> {
match &self.at(row, col) {
CellValue::Possible(x) => x.get_value(),
CellValue::None => None,
CellValue::Fixed(x) => Some(*x)
}
}
fn get_values(&self, row: usize, col: usize) -> Vec<u8> {
match &self.at(row, col) {
CellValue::Possible(x) => x.get_values(),
CellValue::None => Vec::<u8>::new(),
CellValue::Fixed(x) => vec![*x],
}
} }
fn compute_possible(&self, row: usize, col: usize) -> CellValue { fn compute_possible(&self, row: usize, col: usize) -> CellValue {
if let CellValue::Fixed(x) = &self.at(row, col) { return CellValue::Fixed(*x); } if let CellValue::Fixed(x) = &self.at(row, col) {
let mut result = PossibleValues([true; 9]); return CellValue::Fixed(*x);
for other in self.row_iter(row) { }
if let CellValue::Fixed(x) = other { result.0[(x-1) as usize] = false } let mut result = PossibleValues([true; 9]);
} for other in self.row_iter(row) {
for other in self.col_iter(col) { if let CellValue::Fixed(x) = other {
if let CellValue::Fixed(x) = other { result.0[(x-1) as usize] = false } result.0[(x - 1) as usize] = false
} }
for other in self.block_iter(row, col) { }
if let CellValue::Fixed(x) = other { result.0[(x-1) as usize] = false } for other in self.col_iter(col) {
} if let CellValue::Fixed(x) = other {
CellValue::from_possible(result) result.0[(x - 1) as usize] = false
}
}
for other in self.block_iter(row, col) {
if let CellValue::Fixed(x) = other {
result.0[(x - 1) as usize] = false
}
}
CellValue::from_possible(result)
} }
} }
impl fmt::Display for Grid { impl fmt::Display for Grid {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for row in 0..GRID_SIZE { for row in 0..GRID_SIZE {
for col in 0..GRID_SIZE { for col in 0..GRID_SIZE {
write!(f, "{}", &self.at(row, col))?; write!(f, "{}", &self.at(row, col))?;
if col < GRID_SIZE-1 { if col < GRID_SIZE - 1 {
if (col + 1) % 3 == 0 { if (col + 1) % 3 == 0 {
write!(f, " || ")?; write!(f, " || ")?;
} else { } else {
write!(f, " | ")?; write!(f, " | ")?;
} }
} }
} }
if row < GRID_SIZE-1 { if row < GRID_SIZE - 1 {
if (row + 1) % 3 == 0 { if (row + 1) % 3 == 0 {
write!(f, "\n{}", "-".repeat(29*9+2))?; write!(f, "\n{}", "-".repeat(29 * 9 + 2))?;
} }
writeln!(f)?; writeln!(f)?;
} }
} }
Ok(()) Ok(())
} }
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
#[test] #[test]
fn possible_values() { fn possible_values() {
let none = PossibleValues([false; 9]); let none = PossibleValues([false; 9]);
let three = PossibleValues([false, false, true, false, false, false, false, false, false]); let three = PossibleValues([false, false, true, false, false, false, false, false, false]);
let some = PossibleValues([false, true, false, true, false, false, false, false, false]); let some = PossibleValues([false, true, false, true, false, false, false, false, false]);
let all = PossibleValues([true; 9]); let all = PossibleValues([true; 9]);
assert_eq!(None, none.get_value()); assert_eq!(None, none.get_value());
assert_eq!(Some(3), three.get_value()); assert_eq!(Some(3), three.get_value());
assert_eq!(0, none.get_count()); assert_eq!(0, none.get_count());
assert_eq!(1, three.get_count()); assert_eq!(1, three.get_count());
assert_eq!(2, some.get_count()); assert_eq!(2, some.get_count());
assert_eq!(9, all.get_count()); assert_eq!(9, all.get_count());
assert_eq!(Vec::<u8>::new(), none.get_values()); assert_eq!(Vec::<u8>::new(), none.get_values());
assert_eq!(vec![3u8], three.get_values()); assert_eq!(vec![3u8], three.get_values());
assert_eq!(vec![2u8, 4u8], some.get_values()); assert_eq!(vec![2u8, 4u8], some.get_values());
assert_eq!(vec![1u8, 2u8, 3u8, 4u8, 5u8, 6u8, 7u8, 8u8, 9u8], all.get_values()); assert_eq!(vec![1u8, 2u8, 3u8, 4u8, 5u8, 6u8, 7u8, 8u8, 9u8], all.get_values());
} }
#[test] #[test]
#[should_panic] #[should_panic]
fn possible_values_get_value() { fn possible_values_get_value() {
let some = PossibleValues([false, true, false, true, false, false, false, false, false]); let some = PossibleValues([false, true, false, true, false, false, false, false, false]);
some.get_value(); some.get_value();
} }
#[test] #[test]
fn cellvalue_from_possible() { fn cellvalue_from_possible() {
let none = PossibleValues([false; 9]); let none = PossibleValues([false; 9]);
let three = PossibleValues([false, false, true, false, false, false, false, false, false]); let three = PossibleValues([false, false, true, false, false, false, false, false, false]);
let some = PossibleValues([false, true, false, true, false, false, false, false, false]); let some = PossibleValues([false, true, false, true, false, false, false, false, false]);
let all = PossibleValues([true; 9]); let all = PossibleValues([true; 9]);
assert_eq!(CellValue::None, CellValue::from_possible(none)); assert_eq!(CellValue::None, CellValue::from_possible(none));
assert_eq!(CellValue::Fixed(3), CellValue::from_possible(three)); assert_eq!(CellValue::Fixed(3), CellValue::from_possible(three));
assert_eq!(CellValue::Possible(some), CellValue::from_possible(some)); assert_eq!(CellValue::Possible(some), CellValue::from_possible(some));
assert_eq!(CellValue::Possible(all), CellValue::from_possible(all)); assert_eq!(CellValue::Possible(all), CellValue::from_possible(all));
} }
#[test] #[test]
fn new_grid_is_empty() { fn new_grid_is_empty() {
let g = Grid::new(); let g = Grid::new();
for row in 0..9 { for row in 0..9 {
for col in 0..9 { for col in 0..9 {
assert_eq!(None, g.get_value(row, col)); assert_eq!(None, g.get_value(row, col));
} }
} }
} }
} }
fn solve(g: Grid) -> Option<Grid> { fn solve(g: Grid) -> Option<Grid> {
let mut queue = vec![g]; let mut queue = vec![g];
while let Some(mut work) = queue.pop() { while let Some(mut work) = queue.pop() {
if !work.possible() { continue; } if !work.possible() {
let prev = work; continue;
println!("{work}"); }
println!(); let prev = work;
work.update(); println!("{work}");
if work.done() { println!();
return Some(work); work.update();
} else if prev == work { if work.done() {
let Some((row, col, possibles)) = work.find_shortest_possibles() else { continue; }; return Some(work);
for possible in possibles.get_values() { } else if prev == work {
let mut copy = work; let Some((row, col, possibles)) = work.find_shortest_possibles() else {
*copy.at_mut(row, col) = CellValue::Fixed(possible); continue;
copy.update(); };
queue.push(copy); for possible in possibles.get_values() {
} let mut copy = work;
} else { *copy.at_mut(row, col) = CellValue::Fixed(possible);
queue.push(work); copy.update();
} queue.push(copy);
}
} else {
queue.push(work);
}
} }
None None
} }
fn main() { fn main() {
#[rustfmt::skip]
let g = Grid::from_array([5, 3, 0, 0, 7, 0, 0, 0, 0, let g = Grid::from_array([5, 3, 0, 0, 7, 0, 0, 0, 0,
6, 0, 0, 1, 9, 5, 0, 0, 0, 6, 0, 0, 1, 9, 5, 0, 0, 0,
0, 9, 8, 0, 0, 0, 0, 6, 0, 0, 9, 8, 0, 0, 0, 0, 6, 0,
@@ -382,9 +420,14 @@ fn main() {
7, 0, 0, 0, 2, 0, 0, 0, 6, 7, 0, 0, 0, 2, 0, 0, 0, 6,
0, 6, 0, 0, 0, 0, 2, 8, 0, 0, 6, 0, 0, 0, 0, 2, 8, 0,
0, 0, 0, 4, 1, 9, 0, 0, 5, 0, 0, 0, 4, 1, 9, 0, 0, 5,
0, 0, 0, 0, 8, 0, 0, 7, 9]); 0, 0, 0, 0, 8, 0, 0, 7, 9,
println!("{}\n", solve(g).map(|g| format!("{}", g)).unwrap_or("No solution".to_string())); ]);
println!(
"{}\n",
solve(g).map(|g| format!("{}", g)).unwrap_or("No solution".to_string())
);
#[rustfmt::skip]
let evil = Grid::from_array([0, 0, 0, 0, 0, 0, 0, 0, 0, let evil = Grid::from_array([0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 3, 0, 8, 5, 0, 0, 0, 0, 0, 3, 0, 8, 5,
0, 0, 1, 0, 2, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 0,
@@ -393,6 +436,12 @@ fn main() {
0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0,
5, 0, 0, 0, 0, 0, 0, 7, 3, 5, 0, 0, 0, 0, 0, 0, 7, 3,
0, 0, 2, 0, 1, 0, 0, 0, 0, 0, 0, 2, 0, 1, 0, 0, 0, 0,
0, 0, 0, 0, 4, 0, 0, 0, 9]); 0, 0, 0, 0, 4, 0, 0, 0, 9,
println!("{}\n", solve(evil).map(|g| format!("{}", g)).unwrap_or("No solution".to_string())); ]);
println!(
"{}\n",
solve(evil)
.map(|g| format!("{}", g))
.unwrap_or("No solution".to_string())
);
} }