diff --git a/src/main.rs b/src/main.rs index 6f2076b..f0b1e2b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -32,6 +32,10 @@ struct Args { /// Display grid when solving #[arg(long)] grid: bool, + + /// Create puzzle + #[arg(long)] + puzzle: bool, } @@ -53,10 +57,17 @@ fn main() { solver.benchmark(number); return } - if let Err(reason) = solver.solve(args.limit) { + + let result = if args.puzzle { + solver.make_puzzle().map(|_| ()) + } else { + solver.solve(args.limit).map(|_| ()) + }; + + if let Err(reason) = result { println!("{}", reason); if args.debug { - solver.display(solver::ui::DisplayMode::Full); + solver.display(solver::ui::DisplayMode::Full); } } } diff --git a/src/solver/cell.rs b/src/solver/cell.rs index df3c9d0..27ca3e6 100644 --- a/src/solver/cell.rs +++ b/src/solver/cell.rs @@ -64,6 +64,10 @@ impl Cell { .collect() } + pub fn get_state(&self) -> Option { + self.state + } + pub fn get_existing(&self) -> Vec { if let Some(state) = self.state { vec![state] diff --git a/src/solver/mod.rs b/src/solver/mod.rs index e819a22..80cef80 100644 --- a/src/solver/mod.rs +++ b/src/solver/mod.rs @@ -3,6 +3,7 @@ use std::time::Instant; use std::time::Duration; use std::ops::MulAssign; use std::fmt; +use rand::Rng; pub mod sudoku; pub mod ui; @@ -115,6 +116,7 @@ pub struct Solver { debug_display: bool, grid_display: bool, solve_display: bool, + solve_progress_display: bool, collapse_option: cell::CollapseOption, } @@ -132,10 +134,42 @@ impl Solver { debug_display: false, grid_display: false, solve_display: true, + solve_progress_display: true, collapse_option: cell::CollapseOption::Random, } } + pub fn make_puzzle(&mut self) -> Result<(), WaveError> { + self.solve_display = false; + println!("# generating full..."); + let _ = self.solve(None)?; + + println!("\n\n# erasing cells..."); + let mut rng = rand::thread_rng(); + + let erase_cell = loop { + let pos = (rng.gen_range(1..=self.size), rng.gen_range(1..=self.size)); + if let Some(state) = self.grid[pos.0][pos.1].get_state() { + self.grid[pos.0][pos.1].reset_state(); + break (pos, state); + } + }; + + let blocking_cell = cell::BlockingCell { + state: erase_cell.1, + position: erase_cell.0, + }; + + self.propagate_backtrack(erase_cell.0, blocking_cell); // get min allowed state number + // while min state number < 2 => loop + + + println!(); + self.display(ui::DisplayMode::Full); + self.solve_display = true; + Ok(()) + } + fn reset_grid(&mut self) { let states = (1..=self.size).collect(); let empty_grid = vec![vec![cell::Cell::new(states); self.size]; self.size]; @@ -154,6 +188,7 @@ impl Solver { pub fn benchmark(&mut self, solve_number: usize) { self.solve_display = false; + self.solve_progress_display = false; println!(); if self.grid_display { self.display(ui::DisplayMode::Full); @@ -179,7 +214,6 @@ impl Solver { if !self.debug_display && !self.grid_display { let progress = (index + 1) as f32 / solve_number as f32; self.progress_bar(progress); - //print!("\r- {} ({}/{})", progress, index + 1, solve_number); } if self.grid_display { if !self.debug_display { @@ -198,6 +232,7 @@ impl Solver { println!("\nbenchmark {} (n = {})\n{}\n({} errors)", self.square_size, solve_number, results_sum, error_number); self.solve_display = true; + self.solve_progress_display = true; } pub fn solve(&mut self, solver_limit: Option) -> Result { @@ -251,7 +286,7 @@ impl Solver { collapse_counter.0 += 1; collapse_counter.1 += collapse_start.elapsed(); - if !self.debug_display && !self.grid_display && self.solve_display { + if !self.debug_display && !self.grid_display && self.solve_progress_display { self.progress_bar(self.history.len() as f32/((self.size*self.size) as f32)); } if let Some(limit) = solver_limit { @@ -322,7 +357,7 @@ impl Solver { } } - fn backtrack(&mut self) -> Result<(), WaveError> { + fn get_last_fork(&mut self) -> Result { let mut fork: Option = None; while let Some(step) = self.history.pop() { if self.last_move_index == 0 { @@ -343,12 +378,20 @@ impl Solver { } self.debug(&format!("* backtracking [{}][{}] : {}", step.position.0, step.position.1, step.state_set)); } + match fork { + Some(step) => { + self.debug(&format!("* fork [{}][{}] : {}", step.position.0, step.position.1, step.state_set)); + Ok(step) + }, + None => { + self.debug("x backtracked to start"); + Err(WaveError::NoHistory) + } + } + } - let Some(step) = fork else { - self.debug("x backtracked to start"); - return Err(WaveError::NoHistory) - }; - self.debug(&format!("* fork [{}][{}] : {}", step.position.0, step.position.1, step.state_set)); + fn backtrack(&mut self) -> Result<(), WaveError> { + let step = self.get_last_fork()?; let mut state_selected_set = HashSet::new(); state_selected_set.insert(step.state_set);