modified: solitaire_engine/src/game_plugin.rs

This commit is contained in:
funman300
2026-04-24 20:12:10 -07:00
parent 0fdfbced6d
commit 6b793aa2ab
+68 -1
View File
@@ -48,10 +48,46 @@ impl Plugin for GamePlugin {
)
.chain()
.in_set(GameMutation),
);
)
.add_systems(Update, tick_elapsed_time);
}
}
/// Pure, testable helper. Updates `elapsed_seconds` and drains the
/// fractional accumulator into whole-second ticks. No-op when `is_won`.
pub fn advance_elapsed(
elapsed_seconds: &mut u64,
accumulator: &mut f32,
delta_secs: f32,
is_won: bool,
) {
if is_won {
return;
}
*accumulator += delta_secs;
while *accumulator >= 1.0 {
*elapsed_seconds = elapsed_seconds.saturating_add(1);
*accumulator -= 1.0;
}
}
/// Increment `GameState.elapsed_seconds` once per real-world second while
/// the game is in progress (not won). Stops counting on win so the final
/// time reflects how long the player took to solve the deal.
fn tick_elapsed_time(
time: Res<Time>,
mut game: ResMut<GameStateResource>,
mut accumulator: Local<f32>,
) {
let is_won = game.0.is_won;
advance_elapsed(
&mut game.0.elapsed_seconds,
&mut accumulator,
time.delta_secs(),
is_won,
);
}
fn seed_from_system_time() -> u64 {
SystemTime::now()
.duration_since(UNIX_EPOCH)
@@ -232,6 +268,37 @@ mod tests {
assert_ne!(before, after);
}
#[test]
fn advance_elapsed_drains_accumulator_into_whole_seconds() {
let mut elapsed = 0;
let mut acc = 0.0;
advance_elapsed(&mut elapsed, &mut acc, 2.5, false);
assert_eq!(elapsed, 2);
// Remaining 0.5 should still be in the accumulator.
advance_elapsed(&mut elapsed, &mut acc, 0.5, false);
assert_eq!(elapsed, 3);
}
#[test]
fn advance_elapsed_is_noop_when_won() {
let mut elapsed = 100;
let mut acc = 0.0;
advance_elapsed(&mut elapsed, &mut acc, 5.0, true);
assert_eq!(elapsed, 100);
assert_eq!(acc, 0.0);
}
#[test]
fn advance_elapsed_handles_subsecond_deltas_without_skipping() {
let mut elapsed = 0;
let mut acc = 0.0;
// 16ms × 60 frames/sec ≈ 1 second; should produce 1 tick.
for _ in 0..60 {
advance_elapsed(&mut elapsed, &mut acc, 1.0 / 60.0, false);
}
assert!(elapsed == 1, "expected 1 second, got {elapsed}");
}
#[test]
fn invalid_move_does_not_fire_state_changed() {
let mut app = test_app(42);