Add alternate style of puzzle generation
This commit is contained in:
parent
031bdf6cd9
commit
e69db652d4
2 changed files with 109 additions and 4 deletions
|
@ -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<GeneratedGrid> {
|
||||
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<R: Rng>(
|
|||
puzzles_left: &AtomicI64,
|
||||
attempts_left: &AtomicI64,
|
||||
debug: bool,
|
||||
alternative_generation: bool,
|
||||
) -> Vec<GeneratedGrid> {
|
||||
|
||||
let mut generated_grids: Vec<GeneratedGrid> = 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);
|
||||
|
|
|
@ -178,6 +178,92 @@ pub fn generate_grid<R: Rng>(
|
|||
(grid, num_hints, statistics_option.unwrap())
|
||||
}
|
||||
|
||||
pub fn generate_alternate_grid<R: Rng>(
|
||||
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<u8>{
|
||||
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<R: Rng>(rng: &mut R) -> Grid {
|
||||
let solve_controller = SolveController {
|
||||
|
|
Loading…
Reference in a new issue