pub use crate::puzzles::sudoku::rng::SimpleRng;
pub trait PuzzleClass {
type Clue;
type Puzzle;
fn seed_solution(&self, rng: &mut SimpleRng) -> Vec<u32>;
fn place_clues(&self, solution: &[u32], rng: &mut SimpleRng) -> Vec<Self::Clue>;
fn solve_candidate(
&self,
board: &[u32],
clues: &[Self::Clue],
max_solutions: usize,
) -> Vec<Vec<u32>>;
fn target_holes(&self, board_len: usize) -> usize;
fn assemble(&self, board: Vec<u32>, clues: Vec<Self::Clue>) -> Self::Puzzle;
}
pub fn generate_by_digging<C: PuzzleClass>(class: &C, rng: &mut SimpleRng) -> C::Puzzle {
let solution = class.seed_solution(rng);
let clues = class.place_clues(&solution, rng);
let target = class.target_holes(solution.len());
let mut board = solution.clone();
let mut indices: Vec<usize> = (0..solution.len()).collect();
rng.shuffle(&mut indices);
let mut holes = 0usize;
for &idx in &indices {
if holes >= target {
break;
}
let saved = board[idx];
board[idx] = 0;
if class.solve_candidate(&board, &clues, 2).len() == 1 {
holes += 1;
} else {
board[idx] = saved;
}
}
class.assemble(board, clues)
}