clippy and fmt
This commit is contained in:
1
rustfmt.toml
Normal file
1
rustfmt.toml
Normal file
@@ -0,0 +1 @@
|
|||||||
|
max_width = 120
|
||||||
165
src/main.rs
165
src/main.rs
@@ -1,10 +1,9 @@
|
|||||||
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 {
|
||||||
@@ -12,18 +11,27 @@ impl PossibleValues {
|
|||||||
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
|
||||||
|
)
|
||||||
|
}
|
||||||
|
val = (x + 1) as u8;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if val == 0 { None } else { Some(val) }
|
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
|
||||||
@@ -46,8 +54,7 @@ impl fmt::Display for PossibleValues {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone, Copy)]
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
pub enum CellValue {
|
pub enum CellValue {
|
||||||
None,
|
None,
|
||||||
Fixed(u8),
|
Fixed(u8),
|
||||||
@@ -75,8 +82,7 @@ impl fmt::Display for CellValue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[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,7 +97,9 @@ 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 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
let curr = self.parent.at(self.row, self.pos);
|
let curr = self.parent.at(self.row, self.pos);
|
||||||
self.pos += 1;
|
self.pos += 1;
|
||||||
Some(*curr)
|
Some(*curr)
|
||||||
@@ -108,7 +116,9 @@ 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 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
let curr = self.parent.at(self.pos, self.col);
|
let curr = self.parent.at(self.pos, self.col);
|
||||||
self.pos += 1;
|
self.pos += 1;
|
||||||
Some(*curr)
|
Some(*curr)
|
||||||
@@ -119,23 +129,33 @@ 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 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
let curr = self.parent.at(self.row + self.pos % 3, self.col + self.pos / 3);
|
let curr = self.parent.at(self.row + self.pos % 3, self.col + self.pos / 3);
|
||||||
self.pos += 1;
|
self.pos += 1;
|
||||||
Some(*curr)
|
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 {
|
||||||
@@ -144,7 +164,7 @@ impl Grid {
|
|||||||
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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -153,24 +173,39 @@ impl Grid {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
*self.at_mut(row, col) = self.compute_possible(row, col);
|
*self.at_mut(row, col) = self.compute_possible(row, col);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -179,8 +214,8 @@ impl Grid {
|
|||||||
// 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) {
|
||||||
@@ -194,7 +229,9 @@ impl Grid {
|
|||||||
}
|
}
|
||||||
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 {
|
||||||
|
panic!();
|
||||||
|
};
|
||||||
Some((row, col, *val))
|
Some((row, col, *val))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
@@ -211,7 +248,7 @@ impl Grid {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn possible(&self) -> bool {
|
pub fn possible(&self) -> bool {
|
||||||
@@ -223,46 +260,42 @@ impl Grid {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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");
|
||||||
}
|
|
||||||
|
|
||||||
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],
|
|
||||||
}
|
}
|
||||||
|
&mut self.data[row * GRID_SIZE + col]
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
||||||
|
return CellValue::Fixed(*x);
|
||||||
|
}
|
||||||
let mut result = PossibleValues([true; 9]);
|
let mut result = PossibleValues([true; 9]);
|
||||||
for other in self.row_iter(row) {
|
for other in self.row_iter(row) {
|
||||||
if let CellValue::Fixed(x) = other { result.0[(x-1) as usize] = false }
|
if let CellValue::Fixed(x) = other {
|
||||||
|
result.0[(x - 1) as usize] = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for other in self.col_iter(col) {
|
for other in self.col_iter(col) {
|
||||||
if let CellValue::Fixed(x) = other { result.0[(x-1) as usize] = false }
|
if let CellValue::Fixed(x) = other {
|
||||||
|
result.0[(x - 1) as usize] = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for other in self.block_iter(row, col) {
|
for other in self.block_iter(row, col) {
|
||||||
if let CellValue::Fixed(x) = other { result.0[(x-1) as usize] = false }
|
if let CellValue::Fixed(x) = other {
|
||||||
|
result.0[(x - 1) as usize] = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
CellValue::from_possible(result)
|
CellValue::from_possible(result)
|
||||||
}
|
}
|
||||||
@@ -273,7 +306,7 @@ impl fmt::Display for Grid {
|
|||||||
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 {
|
||||||
@@ -281,9 +314,9 @@ impl fmt::Display for Grid {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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)?;
|
||||||
}
|
}
|
||||||
@@ -351,7 +384,9 @@ mod tests {
|
|||||||
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() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
let prev = work;
|
let prev = work;
|
||||||
println!("{work}");
|
println!("{work}");
|
||||||
println!();
|
println!();
|
||||||
@@ -359,7 +394,9 @@ fn solve(g: Grid) -> Option<Grid> {
|
|||||||
if work.done() {
|
if work.done() {
|
||||||
return Some(work);
|
return Some(work);
|
||||||
} else if prev == work {
|
} else if prev == work {
|
||||||
let Some((row, col, possibles)) = work.find_shortest_possibles() else { continue; };
|
let Some((row, col, possibles)) = work.find_shortest_possibles() else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
for possible in possibles.get_values() {
|
for possible in possibles.get_values() {
|
||||||
let mut copy = work;
|
let mut copy = work;
|
||||||
*copy.at_mut(row, col) = CellValue::Fixed(possible);
|
*copy.at_mut(row, col) = CellValue::Fixed(possible);
|
||||||
@@ -374,6 +411,7 @@ fn solve(g: Grid) -> Option<Grid> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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())
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user