diff --git a/guide/age-of-dwarves/src/simulation/simulation.worker.ts b/guide/age-of-dwarves/src/simulation/simulation.worker.ts index fe899ae2..155dcfab 100644 --- a/guide/age-of-dwarves/src/simulation/simulation.worker.ts +++ b/guide/age-of-dwarves/src/simulation/simulation.worker.ts @@ -151,16 +151,19 @@ function stepOneTurn(state: ScenarioState, scenarioTurn: number, specJson: strin state.wasmGrid = jsGridToWasm(state.grid) } wasmPhysicsStep(state.physics, state.ecology, state.wasmGrid, absTurn, state.worldSeed, specJson) - // Sync WASM grid back to JS for stats computation - state.grid = wasmGridToJs(state.wasmGrid) + // Compute stats in Rust — avoids full 960-tile JSON deserialization every turn. const prevStats = state.stats.length > 0 ? state.stats[state.stats.length - 1] : undefined - const stats = computeTurnStats(state.grid, prevStats) + const stats: TurnStats = JSON.parse( + state.wasmGrid.computeStatsJson(prevStats?.avg_temp ?? 0.5, prevStats?.avg_moisture ?? 0.5) + ) state.cursorScenarioTurn = scenarioTurn + 1 - // WASM physics doesn't return events; events are tracked in stats return { stats, events: [] } } function addCheckpoint(state: ScenarioState, turn: number): void { + // Sync JS grid from WASM before checkpointing — checkpoints are infrequent (every 100 turns) + // so the toJSON cost here is acceptable. The per-turn hot path avoids this. + state.grid = wasmGridToJs(state.wasmGrid) state.checkpoints.set(turn, cloneGridState(state.grid)) if (state.checkpoints.size > MAX_CHECKPOINTS) {