refactor(core): align Spider with upstream card_game idioms #162

Merged
funman300 merged 1 commits from refactor/spider-upstream-idioms into master 2026-07-09 05:26:50 +00:00
Owner

Follow-up to #157, addressing the upstream author's review of the Spider core. Each point maps to one of the five critiques:

  1. "invented its own RNG once again" — the inline SplitMix64 + Fisher-Yates is gone. Deals now go through rand::rngs::StdRng seeded with seed_from_u64 + SliceRandom::shuffle, byte-for-byte the same pattern as klondike::Klondike::with_seed. solitaire_core gains the exact rand dep klondike pins (0.10.1, default-features = false, features = ["std_rng"]) — already in the lockfile via klondike, so zero new transitive deps. Deals for a given seed change; Spider has no engine UI or persisted games yet, so nothing observable breaks.

  2. "missing the quatisms ... everything being an enum"SpiderInstruction::Move no longer carries from: u8, to: u8, count: u8. It's now Move(SpiderMove { from: SpiderTableau, run: RunLength, to: SpiderTableau })Tableau1..Tableau10 and Run1..Run13, each with ITER_BEGIN/next() const iteration and an ALL const. Out-of-range piles and zero-card moves are unrepresentable. Rank math uses Rank::checked_add instead of as u8 + 1.

  3. "heap allocated Vecs instead of fixed size Stacks"build_deck returns Stack<104>; possible_instructions is now SpiderIter::new().filter(is_instruction_valid) (the KlondikeIter pattern) instead of pushing into a Vec. The only remaining Vecs are the test-layout helper params and the SpiderGameState wrapper's collected return, which mirrors GameState::possible_instructions.

  4. "names functions randomly different from upstream"SpiderGameSpider (matches Klondike); tableau_face_up/_downtableau_face_up_cards/tableau_face_down_cards (klondike's names); stock_len() → a stock() accessor; tableau_top_card added; with_rng added alongside with_seed, same pair as upstream.

  5. "wraps the session type to avoid exposing solve"SpiderGameState::session() now exposes the underlying Session<Spider>, the same escape hatch GameState::session() provides. The solver was always reachable and budget-gated by SessionConfig; the wrapper no longer pretends otherwise.

Tests: all 71 core tests green (rule tests rewritten against the enum types; the out-of-range/zero-count rejection test is now a note that those shapes are unrepresentable, plus a new exhaustive-iterator test). Full workspace green, clippy -D warnings clean, fmt clean.

🤖 Generated with Claude Code

Follow-up to #157, addressing the upstream author's review of the Spider core. Each point maps to one of the five critiques: 1. **"invented its own RNG once again"** — the inline SplitMix64 + Fisher-Yates is gone. Deals now go through `rand::rngs::StdRng` seeded with `seed_from_u64` + `SliceRandom::shuffle`, byte-for-byte the same pattern as `klondike::Klondike::with_seed`. `solitaire_core` gains the exact rand dep klondike pins (`0.10.1`, `default-features = false, features = ["std_rng"]`) — already in the lockfile via klondike, so zero new transitive deps. *Deals for a given seed change; Spider has no engine UI or persisted games yet, so nothing observable breaks.* 2. **"missing the quatisms ... everything being an enum"** — `SpiderInstruction::Move` no longer carries `from: u8, to: u8, count: u8`. It's now `Move(SpiderMove { from: SpiderTableau, run: RunLength, to: SpiderTableau })` — `Tableau1..Tableau10` and `Run1..Run13`, each with `ITER_BEGIN`/`next()` const iteration and an `ALL` const. Out-of-range piles and zero-card moves are unrepresentable. Rank math uses `Rank::checked_add` instead of `as u8 + 1`. 3. **"heap allocated Vecs instead of fixed size Stacks"** — `build_deck` returns `Stack<104>`; `possible_instructions` is now `SpiderIter::new().filter(is_instruction_valid)` (the `KlondikeIter` pattern) instead of pushing into a `Vec`. The only remaining Vecs are the test-layout helper params and the `SpiderGameState` wrapper's collected return, which mirrors `GameState::possible_instructions`. 4. **"names functions randomly different from upstream"** — `SpiderGame` → `Spider` (matches `Klondike`); `tableau_face_up/_down` → `tableau_face_up_cards`/`tableau_face_down_cards` (klondike's names); `stock_len()` → a `stock()` accessor; `tableau_top_card` added; `with_rng` added alongside `with_seed`, same pair as upstream. 5. **"wraps the session type to avoid exposing solve"** — `SpiderGameState::session()` now exposes the underlying `Session<Spider>`, the same escape hatch `GameState::session()` provides. The solver was always reachable and budget-gated by `SessionConfig`; the wrapper no longer pretends otherwise. Tests: all 71 core tests green (rule tests rewritten against the enum types; the out-of-range/zero-count rejection test is now a note that those shapes are unrepresentable, plus a new exhaustive-iterator test). Full workspace green, clippy `-D warnings` clean, fmt clean. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
funman300 added 1 commit 2026-07-08 00:59:19 +00:00
refactor(core): align Spider with upstream card_game idioms
Test / test (pull_request) Successful in 37m4s
1d2b6dc5de
Addresses upstream author review of the Spider core (PR #157):

- RNG: drop the hand-rolled SplitMix64 + Fisher-Yates; deals now use
  rand::rngs::StdRng seeded via seed_from_u64 + SliceRandom::shuffle,
  exactly like klondike::with_seed. solitaire_core gains the same
  pinned rand dep klondike uses (0.10.1, std_rng only — already in the
  lock, no new transitive deps). Deals for a given seed change; Spider
  has no persisted games yet, so nothing breaks.
- Enums over integers: pile indices and card counts in the instruction
  type are now SpiderTableau (Tableau1..Tableau10, with an ALL const)
  and RunLength (Run1..Run13); out-of-range piles and zero-card moves
  are unrepresentable. Rank comparisons use Rank::checked_add instead
  of u8 arithmetic.
- Fixed-size containers: build_deck returns Stack<104> instead of
  Vec<Card>; possible_instructions is a const-iterated SpiderIter +
  validity filter (klondike's KlondikeIter pattern) instead of
  collecting into a Vec.
- Upstream naming: SpiderGame -> Spider (matches Klondike),
  tableau_face_up/_down -> tableau_face_up_cards/_down_cards,
  stock_len -> stock() accessor, with_rng added alongside with_seed.
- Solver access: SpiderGameState now exposes session(), the same
  escape hatch GameState has — the wrapper no longer pretends to hide
  solve(), which SessionConfig budgets already gate.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
funman300 merged commit db1cc58f3a into master 2026-07-09 05:26:50 +00:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: funman300/Ferrous-Solitaire#162