diff --git a/src/bin/generator.rs b/src/bin/generator.rs index 83d748f..38d1a86 100644 --- a/src/bin/generator.rs +++ b/src/bin/generator.rs @@ -98,6 +98,7 @@ fn main() { let mut difficulty = Difficulty::Hard; let mut threads = 1; let mut print_possibilities = false; + let mut alternative_generation = false; { // this block limits scope of borrows by ap.refer() method @@ -141,14 +142,25 @@ fn main() { ); ap.refer(&mut print_possibilities).add_option( - &["-p", "--possibilities"], + &["-p", "--pencils"], argparse::StoreTrue, - "Include each cell's possibilities in the output; applies only to PDF output", + "Include each cell's pencil marks in the output; applies only to PDF output", + ); + + ap.refer(&mut alternative_generation).add_option( + &["--alt"], + argparse::StoreTrue, + "Generate using an alternative style of generation", ); ap.parse_args_or_exit(); } + print_possibilities = print_possibilities | alternative_generation; + if alternative_generation { + max_hints = 81*9; + } + let max_attempts = max_attempts.unwrap_or(100 * number_puzzles); let solve_controller = difficulty.map_to_solve_controller(); @@ -168,6 +180,7 @@ fn main() { &AtomicI64::new(number_puzzles as i64), &AtomicI64::new(max_attempts as i64), debug, + alternative_generation, ) } @@ -179,6 +192,7 @@ fn main() { debug, solve_controller, difficulty, + alternative_generation, ), }; @@ -230,6 +244,7 @@ fn run_multi_threaded( debug: bool, solve_controller: SolveController, difficulty: Difficulty, + alternative_generation: bool, ) -> Vec { let mut thread_rng = thread_rng(); let (transmitter, receiver) = mpsc::channel(); @@ -259,6 +274,7 @@ fn run_multi_threaded( &*puzzles_left, &*attempts_left, debug, + alternative_generation, ); let num_puzzles_found = found_puzzles.len(); @@ -300,13 +316,16 @@ fn get_puzzle_matching_conditions( puzzles_left: &AtomicI64, attempts_left: &AtomicI64, debug: bool, + alternative_generation: bool, ) -> Vec { let mut generated_grids: Vec = Vec::new(); while attempts_left.fetch_sub(1, Ordering::SeqCst) > 0 && puzzles_left.load(Ordering::SeqCst) > 0 { - let (grid, num_hints, statistics) = - sudoku_solver::generator::generate_grid(rng, &solve_controller); + let (grid, num_hints, statistics) = match alternative_generation { + true => {sudoku_solver::generator::generate_alternate_grid(rng, &solve_controller)} + false => {sudoku_solver::generator::generate_grid(rng, &solve_controller)} + }; if debug { println!("Found puzzle with {:#?}", statistics); diff --git a/src/generator.rs b/src/generator.rs index 2d6c18f..eec1a27 100644 --- a/src/generator.rs +++ b/src/generator.rs @@ -178,6 +178,92 @@ pub fn generate_grid( (grid, num_hints, statistics_option.unwrap()) } +pub fn generate_alternate_grid( + rng: &mut R, + solve_controller: &SolveController, +) -> (Grid, u64, SolveStatistics) { + let mut grid = generate_completed_grid(rng); + + + let mut cell_order_vec = Vec::new(); + // go through and replace every number with a pencil marking + for x in 0..9 { + for y in 0..9 { + let mut cell = grid.get(x, y).unwrap(); + cell_order_vec.push(Rc::clone(&cell)); + + if let CellValue::Fixed(digit) = cell.get_value_copy() { + cell.set_value_exact(CellValue::Unknown(vec![digit])); + } else { + panic!("Unexpectedly found an incomplete cell in a completed puzzle"); + } + + } + } + + // Need to randomly reorder non_empty_cells + cell_order_vec.shuffle(rng); + + fn invert_digits(digits: &[u8]) -> Vec{ + let mut inverted = Vec::with_capacity(9); + + for i in 1..=9 { + if !digits.contains(&i) { + inverted.push(i); + } + } + + inverted + } + + let mut num_pencils = 81; + for cell in cell_order_vec { + let mut current_digits = match cell.get_value_copy() { + CellValue::Fixed(digit) => {vec![digit]} + CellValue::Unknown(digits) => {digits} + }; + + let to_try_add = invert_digits(¤t_digits); + for digit in to_try_add { + current_digits.push(digit); + cell.set_value_exact(CellValue::Unknown(current_digits.clone())); + + let (status, _) = + evaluate_grid_with_solve_controller(&grid, solve_controller); + match status { + SolveStatus::Complete(uniqueness) => { + let uniqueness = uniqueness.unwrap(); + match uniqueness { + Uniqueness::Unique => { + num_pencils += 1; + } + Uniqueness::NotUnique => { + // Too relaxed; can't add this pencil mark + current_digits.pop(); + } + } + } + SolveStatus::Unfinished => { + panic!("evaluate_grid_with_solve_controller should never return UNFINISHED") + } + SolveStatus::Invalid => { + println!("{}", grid); + panic!("Removing constraints should not have set the # of solutions to zero") + } + } + } + + cell.set_value_exact(CellValue::Unknown(current_digits)); + + } + + let (_, statistics) = + evaluate_grid_with_solve_controller(&grid, solve_controller); + + (grid, num_pencils, statistics) + +} + // We generate a completed grid with no mind for difficulty; afterward generate_puzzle will take out as many fields as it can with regards to the difficulty fn generate_completed_grid(rng: &mut R) -> Grid { let solve_controller = SolveController {