Files
Ferrous-Solitaire/solitaire_engine
funman300 d489e7a31b feat(engine): solver-vetted seed selection on AsyncComputeTaskPool
"Winnable deals only" used to call `choose_winnable_seed` inline on
the main thread inside `handle_new_game`. Each rejected attempt costs
~120 ms (`SolverConfig::default()` budget); the loop caps at
`SOLVER_DEAL_RETRY_CAP` = 50, so a pathological run could stall the
UI for ~6 s on a New Game click. Quat flagged this as the highest-
impact UX regression left in the engine.

Reorganised so the solver runs on `AsyncComputeTaskPool`:

- New `PendingNewGameSeed` resource holds an `Option<PendingSeedTask>`
  carrying the in-flight `Task<u64>` plus the request's `mode` and
  `confirmed` flags so the polling system can replay them on a
  synthetic `NewGameRequestEvent` once the task resolves.
- `handle_new_game` now writes to that resource (and `continue`s)
  for the winnable-only / Classic / random-seed branch, instead of
  calling `choose_winnable_seed` synchronously.
- `poll_pending_new_game_seed` runs `.before(GameMutation)` so the
  synthetic event lands in the same frame's `handle_new_game` —
  the player sees no extra-frame visual lag once the solver
  completes.
- Cancel-on-replace: when a fresh `NewGameRequestEvent` arrives
  while a previous task is in flight, `pending_seed.inner = None`
  drops the old task (Bevy's `Task` Drop cancels cooperatively at
  the next await point) before processing the new request.

Two tests:

- `winnable_seed_search_runs_async_and_completes_eventually` —
  spawns the task, drives `app.update()` in a wall-clock-bounded
  loop with `std::thread::yield_now()` so the shared
  `AsyncComputeTaskPool` gets a chance to schedule between polls.
- `winnable_seed_search_drops_in_flight_task_on_new_request` —
  fires a winnable-only request, then before the task can complete
  fires an explicit-seed request that bypasses the solver entirely.
  Asserts the explicit seed wins, verifying the cancel-on-replace
  contract.

Existing solver tests pass unchanged: explicit-seed paths skip the
new branch and run synchronously like before.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 04:49:19 +00:00
..