7fa91b6fb4
Replace the 2026-05-09 seed lists with seeds regenerated on 2026-06-04. All seeds remain verified winnable within their respective solver budgets. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
325 lines
9.5 KiB
Rust
325 lines
9.5 KiB
Rust
//! Pre-verified seed catalogs for each [`DifficultyLevel`] tier.
|
|
//!
|
|
//! Each slice contains seeds that are provably winnable in Draw-One mode and
|
|
//! that required a specific solver-budget range to solve — the **smallest**
|
|
//! budget that returns `Winnable` determines the tier. See
|
|
//! `solitaire_assetgen/src/bin/gen_difficulty_seeds.rs` for the generator.
|
|
//!
|
|
//! # Tiers and budget boundaries
|
|
//!
|
|
//! | Tier | move_budget | state_budget |
|
|
//! |-------------|-------------|--------------|
|
|
//! | Easy | 1 000 | 1 000 |
|
|
//! | Medium | 5 000 | 5 000 |
|
|
//! | Hard | 25 000 | 25 000 |
|
|
//! | Expert | 100 000 | 100 000 |
|
|
//! | Grandmaster | 200 000 | 200 000 |
|
|
//!
|
|
//! [`DifficultyLevel::Random`] has no catalog — the engine picks a system-time
|
|
//! seed and skips verification.
|
|
|
|
use solitaire_core::game_state::DifficultyLevel;
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Catalogs (populated by gen_difficulty_seeds)
|
|
// ---------------------------------------------------------------------------
|
|
|
|
/// 40 seeds proven winnable within the Easy budget (≤ 1 000 states).
|
|
pub const EASY_SEEDS: &[u64] = &[
|
|
// Generated by solitaire_assetgen::gen_difficulty_seeds (tier=Easy, date=2026-06-04)
|
|
0xD1FF_0000_0000_0009,
|
|
0xD1FF_0000_0000_0087,
|
|
0xD1FF_0000_0000_00EB,
|
|
0xD1FF_0000_0000_017F,
|
|
0xD1FF_0000_0000_01CE,
|
|
0xD1FF_0000_0000_020F,
|
|
0xD1FF_0000_0000_0251,
|
|
0xD1FF_0000_0000_0275,
|
|
0xD1FF_0000_0000_029C,
|
|
0xD1FF_0000_0000_02BD,
|
|
0xD1FF_0000_0000_02ED,
|
|
0xD1FF_0000_0000_038F,
|
|
0xD1FF_0000_0000_03C9,
|
|
0xD1FF_0000_0000_0415,
|
|
0xD1FF_0000_0000_045F,
|
|
0xD1FF_0000_0000_04C4,
|
|
0xD1FF_0000_0000_04CC,
|
|
0xD1FF_0000_0000_04EE,
|
|
0xD1FF_0000_0000_0631,
|
|
0xD1FF_0000_0000_0651,
|
|
0xD1FF_0000_0000_0689,
|
|
0xD1FF_0000_0000_0735,
|
|
0xD1FF_0000_0000_0748,
|
|
0xD1FF_0000_0000_0801,
|
|
0xD1FF_0000_0000_0820,
|
|
0xD1FF_0000_0000_08F9,
|
|
0xD1FF_0000_0000_091C,
|
|
0xD1FF_0000_0000_0937,
|
|
0xD1FF_0000_0000_09A6,
|
|
0xD1FF_0000_0000_09C3,
|
|
0xD1FF_0000_0000_09DD,
|
|
0xD1FF_0000_0000_0BD9,
|
|
0xD1FF_0000_0000_0BEC,
|
|
0xD1FF_0000_0000_0BF2,
|
|
0xD1FF_0000_0000_0C1B,
|
|
0xD1FF_0000_0000_0C26,
|
|
0xD1FF_0000_0000_0C36,
|
|
0xD1FF_0000_0000_0C4B,
|
|
0xD1FF_0000_0000_0C78,
|
|
0xD1FF_0000_0000_0CBC,
|
|
];
|
|
|
|
/// 40 seeds proven winnable within the Medium budget (≤ 5 000 states).
|
|
pub const MEDIUM_SEEDS: &[u64] = &[
|
|
// Generated by solitaire_assetgen::gen_difficulty_seeds (tier=Medium, date=2026-06-04)
|
|
0xD1FF_0000_0000_0012,
|
|
0xD1FF_0000_0000_002C,
|
|
0xD1FF_0000_0000_004B,
|
|
0xD1FF_0000_0000_0052,
|
|
0xD1FF_0000_0000_0058,
|
|
0xD1FF_0000_0000_005E,
|
|
0xD1FF_0000_0000_0063,
|
|
0xD1FF_0000_0000_0099,
|
|
0xD1FF_0000_0000_00A9,
|
|
0xD1FF_0000_0000_00AF,
|
|
0xD1FF_0000_0000_00BB,
|
|
0xD1FF_0000_0000_00D1,
|
|
0xD1FF_0000_0000_00E3,
|
|
0xD1FF_0000_0000_0108,
|
|
0xD1FF_0000_0000_010D,
|
|
0xD1FF_0000_0000_0110,
|
|
0xD1FF_0000_0000_012F,
|
|
0xD1FF_0000_0000_0139,
|
|
0xD1FF_0000_0000_013C,
|
|
0xD1FF_0000_0000_0148,
|
|
0xD1FF_0000_0000_015E,
|
|
0xD1FF_0000_0000_016A,
|
|
0xD1FF_0000_0000_016F,
|
|
0xD1FF_0000_0000_0179,
|
|
0xD1FF_0000_0000_019E,
|
|
0xD1FF_0000_0000_01A8,
|
|
0xD1FF_0000_0000_01AB,
|
|
0xD1FF_0000_0000_01B5,
|
|
0xD1FF_0000_0000_01B8,
|
|
0xD1FF_0000_0000_01D3,
|
|
0xD1FF_0000_0000_01EE,
|
|
0xD1FF_0000_0000_01F3,
|
|
0xD1FF_0000_0000_0202,
|
|
0xD1FF_0000_0000_0203,
|
|
0xD1FF_0000_0000_021E,
|
|
0xD1FF_0000_0000_022C,
|
|
0xD1FF_0000_0000_022D,
|
|
0xD1FF_0000_0000_0233,
|
|
0xD1FF_0000_0000_0245,
|
|
0xD1FF_0000_0000_024E,
|
|
];
|
|
|
|
/// 40 seeds proven winnable within the Hard budget (≤ 25 000 states).
|
|
pub const HARD_SEEDS: &[u64] = &[
|
|
// Generated by solitaire_assetgen::gen_difficulty_seeds (tier=Hard, date=2026-06-04)
|
|
0xD1FF_0000_0000_0006,
|
|
0xD1FF_0000_0000_0008,
|
|
0xD1FF_0000_0000_000F,
|
|
0xD1FF_0000_0000_0011,
|
|
0xD1FF_0000_0000_0022,
|
|
0xD1FF_0000_0000_0023,
|
|
0xD1FF_0000_0000_002A,
|
|
0xD1FF_0000_0000_002D,
|
|
0xD1FF_0000_0000_0040,
|
|
0xD1FF_0000_0000_0042,
|
|
0xD1FF_0000_0000_0050,
|
|
0xD1FF_0000_0000_005B,
|
|
0xD1FF_0000_0000_005D,
|
|
0xD1FF_0000_0000_0067,
|
|
0xD1FF_0000_0000_0069,
|
|
0xD1FF_0000_0000_006E,
|
|
0xD1FF_0000_0000_0072,
|
|
0xD1FF_0000_0000_0079,
|
|
0xD1FF_0000_0000_007C,
|
|
0xD1FF_0000_0000_0080,
|
|
0xD1FF_0000_0000_0081,
|
|
0xD1FF_0000_0000_0083,
|
|
0xD1FF_0000_0000_0091,
|
|
0xD1FF_0000_0000_009B,
|
|
0xD1FF_0000_0000_00A1,
|
|
0xD1FF_0000_0000_00B1,
|
|
0xD1FF_0000_0000_00C3,
|
|
0xD1FF_0000_0000_00D6,
|
|
0xD1FF_0000_0000_00DD,
|
|
0xD1FF_0000_0000_00E8,
|
|
0xD1FF_0000_0000_00F2,
|
|
0xD1FF_0000_0000_0101,
|
|
0xD1FF_0000_0000_010F,
|
|
0xD1FF_0000_0000_0113,
|
|
0xD1FF_0000_0000_0118,
|
|
0xD1FF_0000_0000_0119,
|
|
0xD1FF_0000_0000_012D,
|
|
0xD1FF_0000_0000_0133,
|
|
0xD1FF_0000_0000_0144,
|
|
0xD1FF_0000_0000_0147,
|
|
];
|
|
|
|
/// 40 seeds proven winnable within the Expert budget (≤ 100 000 states).
|
|
pub const EXPERT_SEEDS: &[u64] = &[
|
|
// Generated by solitaire_assetgen::gen_difficulty_seeds (tier=Expert, date=2026-06-04)
|
|
0xD1FF_0000_0000_0000,
|
|
0xD1FF_0000_0000_0002,
|
|
0xD1FF_0000_0000_000A,
|
|
0xD1FF_0000_0000_0013,
|
|
0xD1FF_0000_0000_0017,
|
|
0xD1FF_0000_0000_001C,
|
|
0xD1FF_0000_0000_001F,
|
|
0xD1FF_0000_0000_0021,
|
|
0xD1FF_0000_0000_0024,
|
|
0xD1FF_0000_0000_0029,
|
|
0xD1FF_0000_0000_002E,
|
|
0xD1FF_0000_0000_0035,
|
|
0xD1FF_0000_0000_0045,
|
|
0xD1FF_0000_0000_0048,
|
|
0xD1FF_0000_0000_0049,
|
|
0xD1FF_0000_0000_004F,
|
|
0xD1FF_0000_0000_0062,
|
|
0xD1FF_0000_0000_006D,
|
|
0xD1FF_0000_0000_0074,
|
|
0xD1FF_0000_0000_0076,
|
|
0xD1FF_0000_0000_0082,
|
|
0xD1FF_0000_0000_008F,
|
|
0xD1FF_0000_0000_0090,
|
|
0xD1FF_0000_0000_0097,
|
|
0xD1FF_0000_0000_009A,
|
|
0xD1FF_0000_0000_009F,
|
|
0xD1FF_0000_0000_00A5,
|
|
0xD1FF_0000_0000_00A8,
|
|
0xD1FF_0000_0000_00AD,
|
|
0xD1FF_0000_0000_00AE,
|
|
0xD1FF_0000_0000_00B8,
|
|
0xD1FF_0000_0000_00B9,
|
|
0xD1FF_0000_0000_00BC,
|
|
0xD1FF_0000_0000_00C5,
|
|
0xD1FF_0000_0000_00CA,
|
|
0xD1FF_0000_0000_00CE,
|
|
0xD1FF_0000_0000_00DE,
|
|
0xD1FF_0000_0000_00ED,
|
|
0xD1FF_0000_0000_00EE,
|
|
0xD1FF_0000_0000_00EF,
|
|
];
|
|
|
|
/// 40 seeds proven winnable only within the Grandmaster budget (≤ 200 000 states).
|
|
pub const GRANDMASTER_SEEDS: &[u64] = &[
|
|
// Generated by solitaire_assetgen::gen_difficulty_seeds (tier=Grandmaster, date=2026-06-04)
|
|
0xD1FF_0000_0000_003C,
|
|
0xD1FF_0000_0000_0047,
|
|
0xD1FF_0000_0000_005A,
|
|
0xD1FF_0000_0000_009C,
|
|
0xD1FF_0000_0000_00D2,
|
|
0xD1FF_0000_0000_00F4,
|
|
0xD1FF_0000_0000_00F6,
|
|
0xD1FF_0000_0000_0104,
|
|
0xD1FF_0000_0000_0106,
|
|
0xD1FF_0000_0000_0111,
|
|
0xD1FF_0000_0000_0112,
|
|
0xD1FF_0000_0000_0116,
|
|
0xD1FF_0000_0000_0117,
|
|
0xD1FF_0000_0000_011A,
|
|
0xD1FF_0000_0000_0123,
|
|
0xD1FF_0000_0000_012B,
|
|
0xD1FF_0000_0000_012E,
|
|
0xD1FF_0000_0000_0135,
|
|
0xD1FF_0000_0000_013A,
|
|
0xD1FF_0000_0000_013B,
|
|
0xD1FF_0000_0000_0141,
|
|
0xD1FF_0000_0000_014A,
|
|
0xD1FF_0000_0000_014B,
|
|
0xD1FF_0000_0000_014E,
|
|
0xD1FF_0000_0000_0150,
|
|
0xD1FF_0000_0000_0155,
|
|
0xD1FF_0000_0000_0157,
|
|
0xD1FF_0000_0000_0158,
|
|
0xD1FF_0000_0000_0159,
|
|
0xD1FF_0000_0000_015A,
|
|
0xD1FF_0000_0000_015C,
|
|
0xD1FF_0000_0000_015D,
|
|
0xD1FF_0000_0000_015F,
|
|
0xD1FF_0000_0000_0166,
|
|
0xD1FF_0000_0000_0173,
|
|
0xD1FF_0000_0000_0174,
|
|
0xD1FF_0000_0000_0178,
|
|
0xD1FF_0000_0000_017D,
|
|
0xD1FF_0000_0000_0182,
|
|
0xD1FF_0000_0000_0187,
|
|
];
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Public API
|
|
// ---------------------------------------------------------------------------
|
|
|
|
/// Type alias for the catalog lookup return: a static slice or `None` for `Random`.
|
|
pub type DifficultySeeds = Option<&'static [u64]>;
|
|
|
|
/// Return the seed catalog for `level`, or `None` for `Random` (caller must
|
|
/// use a system-time seed instead).
|
|
pub fn seeds_for(level: DifficultyLevel) -> DifficultySeeds {
|
|
match level {
|
|
DifficultyLevel::Easy => Some(EASY_SEEDS),
|
|
DifficultyLevel::Medium => Some(MEDIUM_SEEDS),
|
|
DifficultyLevel::Hard => Some(HARD_SEEDS),
|
|
DifficultyLevel::Expert => Some(EXPERT_SEEDS),
|
|
DifficultyLevel::Grandmaster => Some(GRANDMASTER_SEEDS),
|
|
DifficultyLevel::Random => None,
|
|
}
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Tests
|
|
// ---------------------------------------------------------------------------
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn all_difficulty_seeds_are_unique() {
|
|
let all: Vec<u64> = [
|
|
EASY_SEEDS,
|
|
MEDIUM_SEEDS,
|
|
HARD_SEEDS,
|
|
EXPERT_SEEDS,
|
|
GRANDMASTER_SEEDS,
|
|
]
|
|
.iter()
|
|
.flat_map(|s| s.iter().copied())
|
|
.collect();
|
|
|
|
let mut sorted = all.clone();
|
|
sorted.sort_unstable();
|
|
let before = sorted.len();
|
|
sorted.dedup();
|
|
assert_eq!(
|
|
sorted.len(),
|
|
before,
|
|
"duplicate seeds found across difficulty tiers"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn seeds_for_random_returns_none() {
|
|
assert!(seeds_for(DifficultyLevel::Random).is_none());
|
|
}
|
|
|
|
#[test]
|
|
fn seeds_for_non_random_returns_some() {
|
|
for level in [
|
|
DifficultyLevel::Easy,
|
|
DifficultyLevel::Medium,
|
|
DifficultyLevel::Hard,
|
|
DifficultyLevel::Expert,
|
|
DifficultyLevel::Grandmaster,
|
|
] {
|
|
assert!(
|
|
seeds_for(level).is_some(),
|
|
"{level:?} should return Some catalog"
|
|
);
|
|
}
|
|
}
|
|
}
|