refactor: delete solitaire_data::solver wrapper; solve via card_game directly

Remove the standalone solver wrapper module. Its thin shaping — build a
solve-budgeted Session, run card_game::Session::solve(), extract the first
useful move — moves onto the domain type in solitaire_core as
GameState::solve_first_move() / GameState::solve_fresh_deal(), with the budget
consts and the SolveOutcome alias re-exported from solitaire_core.

Solving is deterministic, IO-free game logic, so core (which already owns
GameState and exposes session().solve()) is its correct home; solitaire_data is
the persistence/sync layer and never should have owned it.

Consumers now call the core API directly:
- engine: pending_hint (solve_first_move), game_plugin + play_by_seed_plugin
  (solve_fresh_deal), input_plugin (budget consts)
- assetgen: gen_seeds + gen_difficulty_seeds (solve_fresh_deal)

The solver tests move to solitaire_core. cargo test --workspace and
clippy --workspace --all-targets -- -D warnings both green.

Resolves the "delete the solver" directive — card_game provides the solver.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
funman300
2026-06-11 15:04:47 -07:00
parent 424c8b2d50
commit e841a7ab4f
12 changed files with 151 additions and 168 deletions
+4 -5
View File
@@ -11,7 +11,7 @@
//! 3. `handle_text_input` appends decimal digits / handles Backspace while
//! the modal is open, updating [`SeedInputBuffer`] each frame.
//! 4. `tick_debounce_and_spawn_solver_task` waits for 12 frames (~200 ms at
//! 60 Hz) of no input before spawning a [`try_solve`] task on
//! 60 Hz) of no input before spawning a [`GameState::solve_fresh_deal`] task on
//! [`AsyncComputeTaskPool`]. Any fresh keypress drops the in-flight task
//! by resetting the resource.
//! 5. `poll_solver_task` polls the in-flight task each frame and updates the
@@ -24,9 +24,8 @@ use bevy::input::ButtonInput;
use bevy::prelude::*;
use bevy::tasks::{AsyncComputeTaskPool, Task, futures_lite::future};
use solitaire_core::DrawMode;
use solitaire_data::solver::{
DEFAULT_SOLVE_MOVES_BUDGET, DEFAULT_SOLVE_STATES_BUDGET, SolveOutcome, try_solve,
};
use solitaire_core::game_state::GameState;
use solitaire_core::{DEFAULT_SOLVE_MOVES_BUDGET, DEFAULT_SOLVE_STATES_BUDGET, SolveOutcome};
use crate::events::{NewGameRequestEvent, StartPlayBySeedRequestEvent};
use crate::font_plugin::FontResource;
@@ -343,7 +342,7 @@ fn tick_debounce_and_spawn_solver_task(
.as_ref()
.map_or(DrawMode::DrawOne, |s| s.0.draw_mode);
let task = AsyncComputeTaskPool::get().spawn(async move {
try_solve(
GameState::solve_fresh_deal(
seed,
draw_mode,
DEFAULT_SOLVE_MOVES_BUDGET,