use csp_solver::ordering::Ordering;
use csp_solver::puzzles::futoshiki::{
Difficulty, FutoshikiPuzzle, create_futoshiki_csp, generate_futoshiki_difficulty_seeded,
};
use csp_solver::{Pruning, SolveConfig};
const N: u32 = 5;
const TIERS: [Difficulty; 3] = [Difficulty::Easy, Difficulty::Medium, Difficulty::Hard];
fn given_count(board: &[u32]) -> usize {
board.iter().filter(|&&v| v != 0).count()
}
fn givens(board: &[u32]) -> Vec<(usize, u32)> {
board
.iter()
.enumerate()
.filter(|&(_, &v)| v != 0)
.map(|(i, &v)| (i, v))
.collect()
}
fn solve_up_to_two(puzzle: &FutoshikiPuzzle) -> Vec<Vec<u32>> {
let mut csp = create_futoshiki_csp(puzzle);
let config = SolveConfig {
pruning: Pruning::Ac3,
ordering: Ordering::FailFirst,
max_solutions: 2,
..Default::default()
};
csp.solve(&config)
}
#[test]
fn axis_is_seeded_deterministic() {
for &d in &TIERS {
for seed in [1u64, 42, 12345, 0xBEEF] {
let a = generate_futoshiki_difficulty_seeded(N, d, seed);
let b = generate_futoshiki_difficulty_seeded(N, d, seed);
assert_eq!(
a, b,
"n={N} {d:?} seed={seed}: same seed+difficulty must deal the same puzzle"
);
}
}
}
#[test]
fn givens_strictly_decrease_easy_to_hard() {
for seed in [1u64, 2, 3, 7, 42, 99, 12345, 0xF00D] {
let e = given_count(&generate_futoshiki_difficulty_seeded(N, Difficulty::Easy, seed).0);
let m = given_count(&generate_futoshiki_difficulty_seeded(N, Difficulty::Medium, seed).0);
let h = given_count(&generate_futoshiki_difficulty_seeded(N, Difficulty::Hard, seed).0);
assert!(
e > m && m > h,
"seed={seed}: givens must strictly decrease Easy→Hard, got E={e} M={m} H={h}"
);
}
}
#[test]
fn each_tier_is_unique_30_of_30() {
for &d in &TIERS {
for seed in 0u64..30 {
let (board, inequalities) = generate_futoshiki_difficulty_seeded(N, d, seed);
assert_eq!(
board.len(),
(N * N) as usize,
"{d:?} seed={seed}: board size"
);
let puzzle = FutoshikiPuzzle::from_parts(N, givens(&board), inequalities)
.unwrap_or_else(|e| {
panic!("{d:?} seed={seed}: from_parts rejected a generated board: {e}")
});
let solutions = solve_up_to_two(&puzzle);
assert_eq!(
solutions.len(),
1,
"{d:?} seed={seed}: generated puzzle must have exactly one solution"
);
}
}
}