better cells
This commit is contained in:
parent
d5e451e604
commit
847f918ef9
77
src/cell.rs
77
src/cell.rs
|
@ -1,5 +1,6 @@
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
use std::collections::HashMap;
|
||||||
use rand::thread_rng;
|
use rand::thread_rng;
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
|
|
||||||
|
@ -23,6 +24,12 @@ pub enum RemoveResult {
|
||||||
Filled,
|
Filled,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
|
pub struct BlockingCell {
|
||||||
|
pub state: usize,
|
||||||
|
pub position: (usize, usize),
|
||||||
|
}
|
||||||
|
|
||||||
impl fmt::Display for CellError {
|
impl fmt::Display for CellError {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
|
@ -33,32 +40,37 @@ impl fmt::Display for CellError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Cell {
|
pub struct Cell {
|
||||||
state: Option<usize>,
|
state: Option<usize>,
|
||||||
all_states: Vec<usize>,
|
blocking_states: HashMap<usize, Vec<(usize, usize)>>,
|
||||||
allowed_states: Vec<usize>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Cell {
|
impl Cell {
|
||||||
pub fn new(states: Vec<usize>) -> Self {
|
pub fn new(states: Vec<usize>) -> Self {
|
||||||
|
let mut blocking_states = HashMap::new();
|
||||||
|
for state in states {
|
||||||
|
blocking_states.insert(state, vec![]);
|
||||||
|
}
|
||||||
Self {
|
Self {
|
||||||
state: None,
|
state: None,
|
||||||
all_states: states.clone(),
|
blocking_states,
|
||||||
allowed_states: states,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(&self) -> Option<usize> {
|
pub fn get_state(&self) -> Option<usize> {
|
||||||
return self.state
|
self.state
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_allowed(&self) -> Vec<usize> {
|
pub fn get_allowed(&self) -> Vec<usize> {
|
||||||
return self.allowed_states.clone()
|
self.blocking_states
|
||||||
|
.iter()
|
||||||
|
.filter_map(|(state, blocking)| if blocking.is_empty() { Some(*state) } else { None })
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_num_allowed(&self) -> usize {
|
pub fn get_num_allowed(&self) -> usize {
|
||||||
return self.allowed_states.len()
|
return self.get_allowed().len()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_none(&self) -> bool {
|
pub fn is_none(&self) -> bool {
|
||||||
|
@ -69,52 +81,55 @@ impl Cell {
|
||||||
if !self.state.is_none() {
|
if !self.state.is_none() {
|
||||||
return Err(CellError::StateAlreadySet)
|
return Err(CellError::StateAlreadySet)
|
||||||
}
|
}
|
||||||
if self.allowed_states.len() == 0 {
|
|
||||||
|
let allowed_states = self.get_allowed();
|
||||||
|
|
||||||
|
if allowed_states.len() == 0 {
|
||||||
return Err(CellError::NoAllowedState)
|
return Err(CellError::NoAllowedState)
|
||||||
}
|
}
|
||||||
if let CollapseOption::Set(state) = option {
|
if let CollapseOption::Set(state) = option {
|
||||||
if !self.allowed_states.contains(&state) {
|
if !allowed_states.contains(&state) {
|
||||||
return Err(CellError::StateNotAllowed)
|
return Err(CellError::StateNotAllowed)
|
||||||
}
|
}
|
||||||
self.state = Some(*state);
|
self.state = Some(*state);
|
||||||
return Ok(*state)
|
return Ok(*state)
|
||||||
}
|
}
|
||||||
let choice: usize = if let CollapseOption::Random = option {
|
let choice: usize = if let CollapseOption::Random = option {
|
||||||
thread_rng().gen_range(0..self.allowed_states.len())
|
thread_rng().gen_range(0..allowed_states.len())
|
||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
};
|
};
|
||||||
self.state = Some(self.allowed_states[choice]);
|
self.state = Some(allowed_states[choice]);
|
||||||
return Ok(self.allowed_states[choice])
|
return Ok(allowed_states[choice])
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove_allowed(&mut self, states: &HashSet<usize>) -> Result<RemoveResult, CellError> {
|
pub fn remove_allowed(&mut self, blocking_cells: &Vec<BlockingCell>) -> Result<RemoveResult, CellError> {
|
||||||
if !self.state.is_none() {
|
if !self.state.is_none() {
|
||||||
return Ok(RemoveResult::Filled)
|
return Ok(RemoveResult::Filled)
|
||||||
}
|
}
|
||||||
|
|
||||||
self.allowed_states.retain(|&x| !states.contains(&x));
|
for blocking_cell in blocking_cells {
|
||||||
|
if let Some(blocking) = self.blocking_states.get_mut(&blocking_cell.state) {
|
||||||
if self.allowed_states.len() == 0 {
|
blocking.push(blocking_cell.position);
|
||||||
return Err(CellError::NoAllowedState)
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.allowed_states.len() == 1 {
|
let allowed_states = self.get_allowed();
|
||||||
self.state = Some(self.allowed_states[0]);
|
|
||||||
return Ok(RemoveResult::Collapsed(self.allowed_states[0]))
|
match allowed_states.len() {
|
||||||
|
0 => Err(CellError::NoAllowedState),
|
||||||
|
1 => {
|
||||||
|
self.state = Some(allowed_states[0]);
|
||||||
|
Ok(RemoveResult::Collapsed(allowed_states[0]))
|
||||||
|
},
|
||||||
|
_ => Ok(RemoveResult::NumAllowed(allowed_states.len())),
|
||||||
}
|
}
|
||||||
return Ok(RemoveResult::NumAllowed(self.allowed_states.len()))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_allowed(&mut self, state: usize) {
|
pub fn add_allowed(&mut self, removed_cell: &BlockingCell) {
|
||||||
if self.allowed_states.contains(&state) || !self.all_states.contains(&state) {
|
if let Some(blocking) = self.blocking_states.get_mut(&removed_cell.state) {
|
||||||
return
|
blocking.retain(|x| x != &removed_cell.position);
|
||||||
}
|
}
|
||||||
self.allowed_states.push(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn reset_allowed(&mut self) {
|
|
||||||
self.allowed_states = self.all_states.clone();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reset_state(&mut self) {
|
pub fn reset_state(&mut self) {
|
||||||
|
|
149
src/main.rs
149
src/main.rs
|
@ -6,11 +6,7 @@ use std::process;
|
||||||
use clap::{Parser};
|
use clap::{Parser};
|
||||||
|
|
||||||
mod cell;
|
mod cell;
|
||||||
use cell::Cell;
|
|
||||||
use cell::CollapseOption;
|
|
||||||
|
|
||||||
mod ui;
|
mod ui;
|
||||||
use ui::DisplayMode;
|
|
||||||
|
|
||||||
enum WaveError {
|
enum WaveError {
|
||||||
Contradiction,
|
Contradiction,
|
||||||
|
@ -27,27 +23,27 @@ impl fmt::Display for WaveError {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Step {
|
struct Step {
|
||||||
cell_selected: [usize; 2],
|
cell_selected: (usize, usize),
|
||||||
state_selected: usize,
|
state_selected: usize,
|
||||||
num_allowed_states: usize,
|
num_allowed_states: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Sudoku {
|
struct Sudoku {
|
||||||
grid: Vec<Vec<Cell>>,
|
grid: Vec<Vec<cell::Cell>>,
|
||||||
history: Vec<Step>,
|
history: Vec<Step>,
|
||||||
last_history: usize,
|
last_history: usize,
|
||||||
size: usize,
|
size: usize,
|
||||||
square_size: usize,
|
square_size: usize,
|
||||||
debug_display: bool,
|
debug_display: bool,
|
||||||
grid_display: bool,
|
grid_display: bool,
|
||||||
collapse_option: CollapseOption,
|
collapse_option: cell::CollapseOption,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Sudoku {
|
impl Sudoku {
|
||||||
fn new(order: usize) -> Self {
|
fn new(order: usize) -> Self {
|
||||||
let size = order*order;
|
let size = order*order;
|
||||||
let states = (1..=size).collect();
|
let states = (1..=size).collect();
|
||||||
let sudoku_grid: Vec<Vec<Cell>> = vec![vec![Cell::new(states); size]; size];
|
let sudoku_grid: Vec<Vec<cell::Cell>> = vec![vec![cell::Cell::new(states); size]; size];
|
||||||
Self {
|
Self {
|
||||||
grid: sudoku_grid,
|
grid: sudoku_grid,
|
||||||
history: vec![],
|
history: vec![],
|
||||||
|
@ -56,36 +52,38 @@ impl Sudoku {
|
||||||
square_size: order,
|
square_size: order,
|
||||||
debug_display: false,
|
debug_display: false,
|
||||||
grid_display: false,
|
grid_display: false,
|
||||||
collapse_option: CollapseOption::Random,
|
collapse_option: cell::CollapseOption::Random,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_possibilities(&mut self) -> Result<(), WaveError> {
|
fn update_possibilities(&mut self) -> Result<(), WaveError> {
|
||||||
let mut row_used_values: Vec<HashSet<usize>> = vec![HashSet::new(); self.size];
|
let mut row_used_values: Vec<Vec<cell::BlockingCell>> = vec![vec![]; self.size];
|
||||||
let mut column_used_values: Vec<HashSet<usize>> = vec![HashSet::new(); self.size];
|
let mut column_used_values: Vec<Vec<cell::BlockingCell>> = vec![vec![]; self.size];
|
||||||
let mut square_used_values: Vec<Vec<HashSet<usize>>> = vec![vec![HashSet::new(); self.square_size]; self.square_size];
|
let mut square_used_values: Vec<Vec<Vec<cell::BlockingCell>>> = vec![vec![vec![]; self.square_size]; self.square_size];
|
||||||
|
|
||||||
for row_index in 0..self.size {
|
for row_index in 0..self.size {
|
||||||
for column_index in 0..self.size {
|
for column_index in 0..self.size {
|
||||||
let Some(value) = self.grid[row_index][column_index].get() else {
|
let Some(value) = self.grid[row_index][column_index].get_state() else {
|
||||||
continue
|
continue
|
||||||
};
|
};
|
||||||
if row_used_values[row_index].contains(&value) || column_used_values[column_index].contains(&value) || column_used_values[column_index].contains(&value) {
|
let blocking_cell = cell::BlockingCell {
|
||||||
return Err(WaveError::Contradiction)
|
state: value,
|
||||||
}
|
position: (row_index, column_index),
|
||||||
row_used_values[row_index].insert(value);
|
};
|
||||||
column_used_values[column_index].insert(value);
|
row_used_values[row_index].push(blocking_cell.clone());
|
||||||
square_used_values[row_index/self.square_size][column_index/self.square_size].insert(value);
|
column_used_values[column_index].push(blocking_cell.clone());
|
||||||
|
square_used_values[row_index/self.square_size][column_index/self.square_size].push(blocking_cell);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for row_index in 0..self.size {
|
for row_index in 0..self.size {
|
||||||
for column_index in 0..self.size {
|
for column_index in 0..self.size {
|
||||||
let mut used_values = row_used_values[row_index].clone();
|
self.remove_allowed(row_index, column_index, &row_used_values[row_index]
|
||||||
used_values.extend(&column_used_values[column_index]);
|
.iter()
|
||||||
used_values.extend(&square_used_values[row_index/self.square_size][column_index/self.square_size]);
|
.chain(&column_used_values[column_index])
|
||||||
|
.chain(&square_used_values[row_index / self.square_size][column_index / self.square_size])
|
||||||
self.remove_allowed(row_index, column_index, &used_values)?;
|
.cloned()
|
||||||
|
.collect())?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -99,8 +97,8 @@ impl Sudoku {
|
||||||
return Ok(())
|
return Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
let collapsed_row = self.history[self.last_history].cell_selected[0];
|
let collapsed_row = self.history[self.last_history].cell_selected.0;
|
||||||
let collapsed_column = self.history[self.last_history].cell_selected[1];
|
let collapsed_column = self.history[self.last_history].cell_selected.1;
|
||||||
let collapsed_state = self.history[self.last_history].state_selected;
|
let collapsed_state = self.history[self.last_history].state_selected;
|
||||||
self.last_history += 1;
|
self.last_history += 1;
|
||||||
|
|
||||||
|
@ -108,8 +106,10 @@ impl Sudoku {
|
||||||
println!("- propagating {}", collapsed_state);
|
println!("- propagating {}", collapsed_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut collapsed_possibility = HashSet::new();
|
let collapsed_possibility = vec![cell::BlockingCell {
|
||||||
collapsed_possibility.insert(collapsed_state);
|
state: collapsed_state,
|
||||||
|
position: (collapsed_row, collapsed_column),
|
||||||
|
}];
|
||||||
|
|
||||||
for index in 0..self.size {
|
for index in 0..self.size {
|
||||||
if index != collapsed_column {
|
if index != collapsed_column {
|
||||||
|
@ -131,10 +131,9 @@ impl Sudoku {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_impossible(&self, collapsed_row: usize, collapsed_column: usize) -> Result<(),WaveError> {
|
fn check_impossible(&self, collapsed_row: usize, collapsed_column: usize) -> Result<(),WaveError> {
|
||||||
|
|
||||||
let mut missing_states: HashSet<usize> = (1..=self.size).collect();
|
let mut missing_states: HashSet<usize> = (1..=self.size).collect();
|
||||||
for column_index in 0..self.size {
|
for column_index in 0..self.size {
|
||||||
if let Some(state) = self.grid[collapsed_row][column_index].get() {
|
if let Some(state) = self.grid[collapsed_row][column_index].get_state() {
|
||||||
missing_states.remove(&state);
|
missing_states.remove(&state);
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -150,7 +149,7 @@ impl Sudoku {
|
||||||
}
|
}
|
||||||
missing_states = (1..=self.size).collect();
|
missing_states = (1..=self.size).collect();
|
||||||
for row_index in 0..self.size {
|
for row_index in 0..self.size {
|
||||||
if let Some(state) = self.grid[row_index][collapsed_column].get() {
|
if let Some(state) = self.grid[row_index][collapsed_column].get_state() {
|
||||||
missing_states.remove(&state);
|
missing_states.remove(&state);
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -169,7 +168,7 @@ impl Sudoku {
|
||||||
for column_index in 0..self.square_size {
|
for column_index in 0..self.square_size {
|
||||||
let row = (collapsed_row/self.square_size)*self.square_size + row_index;
|
let row = (collapsed_row/self.square_size)*self.square_size + row_index;
|
||||||
let column = (collapsed_column/self.square_size)*self.square_size + column_index;
|
let column = (collapsed_column/self.square_size)*self.square_size + column_index;
|
||||||
if let Some(state) = self.grid[row][column].get() {
|
if let Some(state) = self.grid[row][column].get_state() {
|
||||||
missing_states.remove(&state);
|
missing_states.remove(&state);
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -223,14 +222,19 @@ impl Sudoku {
|
||||||
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() {
|
||||||
self.last_history -= 1;
|
self.last_history -= 1;
|
||||||
self.grid[step.cell_selected[0]][step.cell_selected[1]].reset_state();
|
self.grid[step.cell_selected.0][step.cell_selected.1].reset_state();
|
||||||
self.propagate_backtrack(step.cell_selected, step.state_selected);
|
|
||||||
|
let blocking_cell = cell::BlockingCell {
|
||||||
|
state: step.state_selected,
|
||||||
|
position: step.cell_selected,
|
||||||
|
};
|
||||||
|
self.propagate_backtrack(step.cell_selected, blocking_cell);
|
||||||
if step.num_allowed_states > 1 {
|
if step.num_allowed_states > 1 {
|
||||||
fork = Some(step);
|
fork = Some(step);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if self.debug_display {
|
if self.debug_display {
|
||||||
println!("* backtracking [{}][{}] : {}", step.cell_selected[0], step.cell_selected[1], step.state_selected);
|
println!("* backtracking [{}][{}] : {}", step.cell_selected.0, step.cell_selected.1, step.state_selected);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -241,52 +245,49 @@ impl Sudoku {
|
||||||
return Err(WaveError::NoHistory)
|
return Err(WaveError::NoHistory)
|
||||||
};
|
};
|
||||||
if self.debug_display {
|
if self.debug_display {
|
||||||
println!("* fork [{}][{}] : {}", step.cell_selected[0], step.cell_selected[1], step.state_selected);
|
println!("* fork [{}][{}] : {}", step.cell_selected.0, step.cell_selected.1, step.state_selected);
|
||||||
}
|
}
|
||||||
|
|
||||||
//self.reset_allowed();
|
|
||||||
|
|
||||||
let mut state_selected_set = HashSet::new();
|
let mut state_selected_set = HashSet::new();
|
||||||
state_selected_set.insert(step.state_selected);
|
state_selected_set.insert(step.state_selected);
|
||||||
|
|
||||||
self.remove_allowed(step.cell_selected[0], step.cell_selected[1], &state_selected_set)?;
|
let blocking_cell = cell::BlockingCell {
|
||||||
|
state: step.state_selected,
|
||||||
|
position: step.cell_selected,
|
||||||
|
};
|
||||||
|
|
||||||
|
self.remove_allowed(step.cell_selected.0, step.cell_selected.1, &vec![blocking_cell])?;
|
||||||
if self.debug_display {
|
if self.debug_display {
|
||||||
println!(" - removed : {}, available : {:?}", step.state_selected, self.grid[step.cell_selected[0]][step.cell_selected[1]].get_allowed());
|
println!(" - removed : {}, available : {:?}", step.state_selected, self.grid[step.cell_selected.0][step.cell_selected.1].get_allowed());
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn propagate_backtrack(&mut self, cell_pos: [usize; 2], removed_state: usize) {
|
fn propagate_backtrack(&mut self, cell_pos: (usize, usize), removed_cell: cell::BlockingCell) {
|
||||||
for index in 0..self.size {
|
for index in 0..self.size {
|
||||||
if index != cell_pos[0] {
|
if index != cell_pos.0 {
|
||||||
self.grid[index][cell_pos[1]].add_allowed(removed_state);
|
self.grid[index][cell_pos.1].add_allowed(&removed_cell);
|
||||||
}
|
}
|
||||||
if index != cell_pos[1] {
|
if index != cell_pos.1 {
|
||||||
self.grid[cell_pos[0]][index].add_allowed(removed_state);
|
self.grid[cell_pos.0][index].add_allowed(&removed_cell);
|
||||||
}
|
}
|
||||||
let square_row = (cell_pos[0]/self.square_size)*self.square_size + index/self.square_size;
|
let square_row = (cell_pos.0/self.square_size)*self.square_size + index/self.square_size;
|
||||||
let square_column = (cell_pos[1]/self.square_size)*self.square_size + index%self.square_size;
|
let square_column = (cell_pos.1/self.square_size)*self.square_size + index%self.square_size;
|
||||||
if square_row != cell_pos[0] || square_column != cell_pos[1] {
|
if square_row != cell_pos.0 || square_column != cell_pos.1 {
|
||||||
self.grid[square_row][square_column].add_allowed(removed_state);
|
self.grid[square_row][square_column].add_allowed(&removed_cell);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reset_allowed(&mut self) {
|
fn remove_allowed(&mut self, row_index: usize, column_index: usize, blocking_cells: &Vec<cell::BlockingCell>) -> Result<(), WaveError> {
|
||||||
for row in &mut self.grid {
|
if let Some(state) = self.grid[row_index][column_index].get_state() {
|
||||||
for cell in row {
|
for blocking_cell in blocking_cells {
|
||||||
cell.reset_allowed();
|
if blocking_cell.state == state {
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn remove_allowed(&mut self, row_index: usize, column_index: usize, set_to_remove: &HashSet<usize>) -> Result<(), WaveError> {
|
|
||||||
if let Some(state) = self.grid[row_index][column_index].get() {
|
|
||||||
if set_to_remove.contains(&state) {
|
|
||||||
return Err(WaveError::Contradiction)
|
return Err(WaveError::Contradiction)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
match self.grid[row_index][column_index].remove_allowed(set_to_remove) {
|
}
|
||||||
|
match self.grid[row_index][column_index].remove_allowed(blocking_cells) {
|
||||||
Ok(result) => {
|
Ok(result) => {
|
||||||
let cell::RemoveResult::Collapsed(state) = result else {
|
let cell::RemoveResult::Collapsed(state) = result else {
|
||||||
return Ok(())
|
return Ok(())
|
||||||
|
@ -295,7 +296,7 @@ impl Sudoku {
|
||||||
println!("* collapsed by removal [{}][{}] to {}", row_index, column_index, state)
|
println!("* collapsed by removal [{}][{}] to {}", row_index, column_index, state)
|
||||||
}
|
}
|
||||||
self.history.push(Step {
|
self.history.push(Step {
|
||||||
cell_selected: [row_index, column_index],
|
cell_selected: (row_index, column_index),
|
||||||
state_selected: state,
|
state_selected: state,
|
||||||
num_allowed_states: 1,
|
num_allowed_states: 1,
|
||||||
});
|
});
|
||||||
|
@ -318,7 +319,7 @@ impl Sudoku {
|
||||||
println!("# collapsing [{}][{}] ({}) to {}", row_index, column_index, num_allowed_states, state_selected);
|
println!("# collapsing [{}][{}] ({}) to {}", row_index, column_index, num_allowed_states, state_selected);
|
||||||
}
|
}
|
||||||
self.history.push(Step {
|
self.history.push(Step {
|
||||||
cell_selected: [row_index, column_index],
|
cell_selected: (row_index, column_index),
|
||||||
state_selected,
|
state_selected,
|
||||||
num_allowed_states,
|
num_allowed_states,
|
||||||
});
|
});
|
||||||
|
@ -335,7 +336,7 @@ impl Sudoku {
|
||||||
|
|
||||||
fn solve(&mut self, solver_limit: Option<usize>) -> Result<(), WaveError> {
|
fn solve(&mut self, solver_limit: Option<usize>) -> Result<(), WaveError> {
|
||||||
let now = Instant::now();
|
let now = Instant::now();
|
||||||
self.display(DisplayMode::Full);
|
self.display(ui::DisplayMode::Full);
|
||||||
let mut n_start_cells: usize = 0;
|
let mut n_start_cells: usize = 0;
|
||||||
for row in &self.grid {
|
for row in &self.grid {
|
||||||
for cell in row {
|
for cell in row {
|
||||||
|
@ -372,22 +373,12 @@ impl Sudoku {
|
||||||
while backtrack > 0 {
|
while backtrack > 0 {
|
||||||
backtrack -=1;
|
backtrack -=1;
|
||||||
self.backtrack()?;
|
self.backtrack()?;
|
||||||
// match self.update_possibilities() {
|
|
||||||
// Ok(_) => {},
|
|
||||||
// Err(reason) => {
|
|
||||||
// if let WaveError::Contradiction = reason {
|
|
||||||
// backtrack += 1;
|
|
||||||
// } else {
|
|
||||||
// return Err(reason)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
}
|
}
|
||||||
propagation_counter += 1;
|
propagation_counter += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.grid_display {
|
if self.grid_display {
|
||||||
self.display(DisplayMode::Full);
|
self.display(ui::DisplayMode::Full);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.collapse()?;
|
self.collapse()?;
|
||||||
|
@ -413,15 +404,15 @@ impl Sudoku {
|
||||||
}
|
}
|
||||||
let elapsed = now.elapsed();
|
let elapsed = now.elapsed();
|
||||||
println!("# finished in {} propagations ({} forced collapse), {:.2?} ({:.2?}/propagation)", propagation_counter, collapse_counter, elapsed, elapsed/(propagation_counter as u32));
|
println!("# finished in {} propagations ({} forced collapse), {:.2?} ({:.2?}/propagation)", propagation_counter, collapse_counter, elapsed, elapsed/(propagation_counter as u32));
|
||||||
self.display(DisplayMode::Full);
|
self.display(ui::DisplayMode::Full);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn random_mode(&mut self, collapse_random: bool) {
|
fn random_mode(&mut self, collapse_random: bool) {
|
||||||
if collapse_random {
|
if collapse_random {
|
||||||
self.collapse_option = CollapseOption::Random;
|
self.collapse_option = cell::CollapseOption::Random;
|
||||||
} else {
|
} else {
|
||||||
self.collapse_option = CollapseOption::First
|
self.collapse_option = cell::CollapseOption::First
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -471,6 +462,6 @@ fn main() {
|
||||||
|
|
||||||
if let Err(reason) = sudoku.solve(args.limit) {
|
if let Err(reason) = sudoku.solve(args.limit) {
|
||||||
println!("{}", reason);
|
println!("{}", reason);
|
||||||
sudoku.display(DisplayMode::Full);
|
sudoku.display(ui::DisplayMode::Full);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue