refactor(core): derive score/undo/recycle from upstream session stats

Replace the bespoke WXP scoring engine with the upstream
card_game/klondike session stats, eliminating duplicated state that
could drift from the single source of truth.

score()/undo_count()/recycle_count() now read session.stats(); the -15
undo penalty is configured as SessionConfig::undo_penalty and applied by
the upstream score formula. Save schema bumped v4 -> v5 (the three
counters are no longer persisted -- they are rebuilt by replaying the
forward instruction history on load).

- Remove GameState fields score, undo_count, recycle_count (#87)
- Remove score_history / is_recycle_history undo journal (#86)
- Remove KlondikeAdapter::apply_undo_score and the score_for_* helpers,
  plus pre_instruction_score_delta / will_flip_tableau_source (#84)

These three issues are a single atomic change: each removed field/helper
is consumed by the same draw/apply_instruction/undo/serde/PartialEq
paths, so they cannot compile or pass tests in isolation.

Behaviour changes (intentional): the escalating recycle penalty and
per-step score floor are gone (upstream linear scoring, floored once at
0); recycle_count is now cumulative; undo_count resets across save/load.

Refs #84, #86, #87

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
funman300
2026-06-11 10:36:31 -07:00
parent 9e3c6b06b0
commit 372b6423d8
10 changed files with 237 additions and 381 deletions
+2 -2
View File
@@ -88,7 +88,7 @@ fn award_xp_on_win(
mut progress: ResMut<ProgressResource>,
) {
for ev in wins.read() {
let used_undo = game.0.undo_count > 0;
let used_undo = game.0.undo_count() > 0;
let amount = xp_for_win(ev.time_seconds, used_undo);
let prev_level = progress.0.add_xp(amount);
xp_awarded.write(XpAwardedEvent { amount });
@@ -151,7 +151,7 @@ mod tests {
app.world_mut()
.resource_mut::<GameStateResource>()
.0
.undo_count = 1;
.force_test_undos(1);
app.world_mut().write_message(GameWonEvent {
score: 500,