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};
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)]
#[command(author, version, about, long_about = None)]
struct Args {

View file

@ -1,8 +1,7 @@
use std::collections::HashSet;
use std::time::Instant;
use std::fmt;
use crate::Step;
pub mod sudoku;
pub mod ui;
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 {
grid: Vec<Vec<cell::Cell>>,
history: Vec<Step>,
@ -49,25 +61,107 @@ impl Solver {
}
}
fn remove_allowed(&mut self, position: (usize, usize), blocking_cells: &Vec<cell::BlockingCell>) -> Result<(), WaveError> {
match self.grid[position.0][position.1].remove_allowed(blocking_cells) {
Ok(result) => {
let cell::RemoveResult::Collapsed(state_set) = result else {
return Ok(())
};
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(())
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
}
}
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) => {
self.debug(&format!("x failed to update states allowed of ({},{}) : {}", position.0, position.1, reason));
return Err(WaveError::Contradiction)
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> {
@ -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> {
let mut fork: Option<Step> = None;
while let Some(step) = self.history.pop() {
@ -130,31 +216,24 @@ impl Solver {
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");
fn remove_allowed(&mut self, position: (usize, usize), blocking_cells: &Vec<cell::BlockingCell>) -> Result<(), WaveError> {
match self.grid[position.0][position.1].remove_allowed(blocking_cells) {
Ok(result) => {
let cell::RemoveResult::Collapsed(state_set) = result else {
return Ok(())
};
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(())
}
return self.collapse_cell(min_allowed_position)
Err(reason) => {
self.debug(&format!("x failed to update states allowed of ({},{}) : {}", position.0, position.1, reason));
return Err(WaveError::Contradiction)
}
}
}
}

View file

@ -1,13 +1,11 @@
use std::time::Instant;
use std::collections::HashSet;
use super::Solver;
use super::ui::DisplayMode;
use super::WaveError;
use super::cell;
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 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];
@ -40,7 +38,7 @@ impl Solver {
Ok(())
}
fn propagate_collapse(&mut self) -> Result<(), WaveError> {
pub fn propagate_collapse(&mut self) -> Result<(), WaveError> {
if self.last_move_index >= self.history.len() {
self.debug(&format!("x nothing to propagate"));
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(())
}
}