split clean

This commit is contained in:
WanderingPenwing 2024-12-03 22:23:48 +01:00
parent 2678a5d957
commit 3e3245a977
3 changed files with 138 additions and 144 deletions

View file

@ -1,23 +1,7 @@
use std::fmt;
use clap::{Parser}; use clap::{Parser};
mod solver; mod solver;
#[derive(Debug, Clone)]
struct Step {
position: (usize, usize),
state_set: usize,
num_allowed_states: usize,
}
impl fmt::Display for Step {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "({},{}) to {}, out of {}", self.position.0, self.position.1, self.state_set, self.num_allowed_states)
}
}
#[derive(Parser, Debug)] #[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)] #[command(author, version, about, long_about = None)]
struct Args { struct Args {

View file

@ -1,8 +1,7 @@
use std::collections::HashSet; use std::collections::HashSet;
use std::time::Instant;
use std::fmt; use std::fmt;
use crate::Step;
pub mod sudoku; pub mod sudoku;
pub mod ui; pub mod ui;
mod cell; mod cell;
@ -21,6 +20,19 @@ impl fmt::Display for WaveError {
} }
} }
#[derive(Debug, Clone)]
struct Step {
position: (usize, usize),
state_set: usize,
num_allowed_states: usize,
}
impl fmt::Display for Step {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "({},{}) to {}, out of {}", self.position.0, self.position.1, self.state_set, self.num_allowed_states)
}
}
pub struct Solver { pub struct Solver {
grid: Vec<Vec<cell::Cell>>, grid: Vec<Vec<cell::Cell>>,
history: Vec<Step>, history: Vec<Step>,
@ -48,27 +60,109 @@ impl Solver {
collapse_option: cell::CollapseOption::Random, collapse_option: cell::CollapseOption::Random,
} }
} }
fn remove_allowed(&mut self, position: (usize, usize), blocking_cells: &Vec<cell::BlockingCell>) -> Result<(), WaveError> { pub fn random_mode(&mut self, collapse_random: bool) {
match self.grid[position.0][position.1].remove_allowed(blocking_cells) { if collapse_random {
Ok(result) => { self.collapse_option = cell::CollapseOption::Random;
let cell::RemoveResult::Collapsed(state_set) = result else { } else {
return Ok(()) self.collapse_option = cell::CollapseOption::First
};
self.debug(&format!("* collapsed by removal ({},{}) to {}", position.0, position.1, state_set));
self.history.push(Step {
position,
state_set,
num_allowed_states: 1,
});
return Ok(())
}
Err(reason) => {
self.debug(&format!("x failed to update states allowed of ({},{}) : {}", position.0, position.1, reason));
return Err(WaveError::Contradiction)
}
} }
} }
pub fn solve(&mut self, solver_limit: Option<usize>) -> Result<(), WaveError> {
let now = Instant::now();
self.display(ui::DisplayMode::Full);
let mut number_cell_init: usize = 0;
for row in &self.grid {
for cell in row {
if !cell.is_none() {
number_cell_init += 1;
}
}
}
let mut propagation_counter: usize = 0;
let mut collapse_counter: usize = 0;
println!("# started");
self.debug("--------");
self.update_possibilities()?;
while number_cell_init + self.history.len() < self.size * self.size {
self.debug(&format!("\n## while, h={}/{}", self.last_move_index, self.history.len()));
while self.last_move_index < self.history.len() && number_cell_init + self.history.len() < self.size * self.size {
let mut backtrack = 0;
match self.propagate_collapse() {
Ok(_) => {},
Err(reason) => {
if let WaveError::Contradiction = reason {
backtrack = 1;
} else {
return Err(reason)
}
}
};
while backtrack > 0 {
backtrack -=1;
self.backtrack()?;
}
propagation_counter += 1;
}
if self.grid_display {
if !self.debug_display {
self.display(ui::DisplayMode::Erase);
} else {
self.display(ui::DisplayMode::Full);
}
}
self.collapse()?;
collapse_counter += 1;
if !self.debug_display && !self.grid_display {
self.progress_bar(number_cell_init);
}
if let Some(limit) = solver_limit {
if collapse_counter >= limit {
break;
}
}
}
self.debug("--------");
let elapsed = now.elapsed();
println!("\n# finished in {} propagations ({} forced collapse), {:.2?} ({:.2?}/propagation)", propagation_counter, collapse_counter, elapsed, elapsed/(propagation_counter as u32));
if !self.grid_display || self.debug_display {
self.display(ui::DisplayMode::Full);
}
Ok(())
}
fn collapse(&mut self) -> Result<(), WaveError> {
let mut min_allowed_position: (usize, usize) = (0, 0);
let mut min_allowed_number: usize = self.size;
let mut grid_has_empty_cell: bool = false;
for row_index in 0..self.size {
for column_index in 0..self.size {
if !self.grid[row_index][column_index].is_none() {
continue;
}
grid_has_empty_cell = true;
let possibilities_len = self.grid[row_index][column_index].get_num_allowed();
if possibilities_len < min_allowed_number {
min_allowed_position = (row_index, column_index);
min_allowed_number = possibilities_len;
}
}
}
if !grid_has_empty_cell {
self.debug("x no empty cells");
return Ok(())
}
return self.collapse_cell(min_allowed_position)
}
fn collapse_cell(&mut self, position: (usize, usize)) -> Result<(), WaveError> { fn collapse_cell(&mut self, position: (usize, usize)) -> Result<(), WaveError> {
match self.grid[position.0][position.1].collapse(&self.collapse_option) { match self.grid[position.0][position.1].collapse(&self.collapse_option) {
@ -85,14 +179,6 @@ impl Solver {
} }
} }
pub fn random_mode(&mut self, collapse_random: bool) {
if collapse_random {
self.collapse_option = cell::CollapseOption::Random;
} else {
self.collapse_option = cell::CollapseOption::First
}
}
fn backtrack(&mut self) -> Result<(), WaveError> { fn backtrack(&mut self) -> Result<(), WaveError> {
let mut fork: Option<Step> = None; let mut fork: Option<Step> = None;
while let Some(step) = self.history.pop() { while let Some(step) = self.history.pop() {
@ -130,31 +216,24 @@ impl Solver {
Ok(()) Ok(())
} }
fn collapse(&mut self) -> Result<(), WaveError> { fn remove_allowed(&mut self, position: (usize, usize), blocking_cells: &Vec<cell::BlockingCell>) -> Result<(), WaveError> {
let mut min_allowed_position: (usize, usize) = (0, 0); match self.grid[position.0][position.1].remove_allowed(blocking_cells) {
let mut min_allowed_number: usize = self.size; Ok(result) => {
let cell::RemoveResult::Collapsed(state_set) = result else {
let mut grid_has_empty_cell: bool = false; return Ok(())
};
for row_index in 0..self.size { self.debug(&format!("* collapsed by removal ({},{}) to {}", position.0, position.1, state_set));
for column_index in 0..self.size { self.history.push(Step {
if !self.grid[row_index][column_index].is_none() { position,
continue; state_set,
} num_allowed_states: 1,
grid_has_empty_cell = true; });
let possibilities_len = self.grid[row_index][column_index].get_num_allowed(); return Ok(())
if possibilities_len < min_allowed_number { }
min_allowed_position = (row_index, column_index); Err(reason) => {
min_allowed_number = possibilities_len; self.debug(&format!("x failed to update states allowed of ({},{}) : {}", position.0, position.1, reason));
} return Err(WaveError::Contradiction)
} }
} }
}
if !grid_has_empty_cell {
self.debug("x no empty cells");
return Ok(())
}
return self.collapse_cell(min_allowed_position)
}
} }

View file

@ -1,13 +1,11 @@
use std::time::Instant;
use std::collections::HashSet; use std::collections::HashSet;
use super::Solver; use super::Solver;
use super::ui::DisplayMode;
use super::WaveError; use super::WaveError;
use super::cell; use super::cell;
impl Solver { impl Solver {
fn update_possibilities(&mut self) -> Result<(), WaveError> { pub fn update_possibilities(&mut self) -> Result<(), WaveError> {
let mut row_used_states: Vec<Vec<cell::BlockingCell>> = vec![vec![]; self.size]; let mut row_used_states: Vec<Vec<cell::BlockingCell>> = vec![vec![]; self.size];
let mut column_used_states: Vec<Vec<cell::BlockingCell>> = vec![vec![]; self.size]; let mut column_used_states: Vec<Vec<cell::BlockingCell>> = vec![vec![]; self.size];
let mut square_used_states: Vec<Vec<Vec<cell::BlockingCell>>> = vec![vec![vec![]; self.square_size]; self.square_size]; let mut square_used_states: Vec<Vec<Vec<cell::BlockingCell>>> = vec![vec![vec![]; self.square_size]; self.square_size];
@ -40,7 +38,7 @@ impl Solver {
Ok(()) Ok(())
} }
fn propagate_collapse(&mut self) -> Result<(), WaveError> { pub fn propagate_collapse(&mut self) -> Result<(), WaveError> {
if self.last_move_index >= self.history.len() { if self.last_move_index >= self.history.len() {
self.debug(&format!("x nothing to propagate")); self.debug(&format!("x nothing to propagate"));
return Ok(()) return Ok(())
@ -124,71 +122,4 @@ impl Solver {
} }
} }
} }
pub fn solve(&mut self, solver_limit: Option<usize>) -> Result<(), WaveError> {
let now = Instant::now();
self.display(DisplayMode::Full);
let mut number_cell_init: usize = 0;
for row in &self.grid {
for cell in row {
if !cell.is_none() {
number_cell_init += 1;
}
}
}
let mut propagation_counter: usize = 0;
let mut collapse_counter: usize = 0;
println!("# started");
self.debug("--------");
self.update_possibilities()?;
while number_cell_init + self.history.len() < self.size * self.size {
self.debug(&format!("\n## while, h={}/{}", self.last_move_index, self.history.len()));
while self.last_move_index < self.history.len() && number_cell_init + self.history.len() < self.size * self.size {
let mut backtrack = 0;
match self.propagate_collapse() {
Ok(_) => {},
Err(reason) => {
if let WaveError::Contradiction = reason {
backtrack = 1;
} else {
return Err(reason)
}
}
};
while backtrack > 0 {
backtrack -=1;
self.backtrack()?;
}
propagation_counter += 1;
}
if self.grid_display {
if !self.debug_display {
self.display(DisplayMode::Erase);
} else {
self.display(DisplayMode::Full);
}
}
self.collapse()?;
collapse_counter += 1;
if !self.debug_display && !self.grid_display {
self.progress_bar(number_cell_init);
}
if let Some(limit) = solver_limit {
if collapse_counter >= limit {
break;
}
}
}
self.debug("--------");
let elapsed = now.elapsed();
println!("\n# finished in {} propagations ({} forced collapse), {:.2?} ({:.2?}/propagation)", propagation_counter, collapse_counter, elapsed, elapsed/(propagation_counter as u32));
if !self.grid_display || self.debug_display {
self.display(DisplayMode::Full);
}
Ok(())
}
} }