feat(s5): difficulty tier system — Easy/Normal/Hard with AI brood modifier and tiebreaks (V22)#149
Conversation
…ifier and tiebreaks (V22) Adds sim version V22 (SIM_VERSION_V22_DIFFICULTY=22). Player chooses difficulty before each new game via a pre-game overlay. The AI colony's egg-interval is scaled by a per-difficulty numerator (Easy=5/4×, Normal=1×, Hard=3/4×) stored in ColonyRecord.eggIntervalNumerator to avoid player-vs-enemy branching in the hot path. All four AI tier-array lookups (warfooting/invading thresholds, recovery duration, spider hunger cap) gate on V22. Two new tiebreak conditions fire in tick step 18 when both queens are alive: Timeout (tick ≥ 24 000, winner by worker count) and Stalemate (food depleted + both colonies starving). Pre-V22 saves load with difficulty='Normal' and replay byte-identically. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 31e26a69c2
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…d in stalemate P0: showDifficultySelectThenBoot now sets gamePhase=SavePrompt before opening the overlay. On a fresh install (no save) gameLoop is not yet initialized; update()'s line-2 SavePrompt guard prevents it from reaching this.gameLoop.update(delta) before bootFresh is called. P1: stalemate tiebreak now uses colonyFoodWithCarried() instead of colonyFoodTotal(), summing food on living ants (world.ants.foodCarrying) in addition to colony.foodStored + FoodStorage chambers. Prevents a false MutualDestruction on the tick the last pile is collected when foragers are still carrying enough food to recover. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3a7886c1d2
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3a7886c1d2
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
- game-scene: set gamePhase=SavePrompt before difficulty overlay in restartGame() to prevent update() ticking stale world during selection - game-scene: pass currentDifficulty to createScenario in finishBoot() so prevState replay envelope encodes the correct difficulty - game-over: move livingWorkerCount calls inside timeout/stalemate branches to avoid O(entityCount) scan on every non-tiebreak tick Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: fca4eb2673
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
livingWorkerCount was iterating world.ants.alive and counting all non-queen live entities, including eggs and larvae (which also have alive===1). The timeout tiebreak winner is defined as the colony with more *workers*, so overcounting brood could flip Victory/Defeat. Fix: iterate colony.workers (the maintained worker bucket) and check alive[id]===1 — eggs and larvae are never in this bucket. Test helper addWorker updated to push into colony.workers so the corrected code path is exercised. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f632da1751
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
The SCEN-06 replay check was calling createScenario(seed) without difficulty, causing Easy/Hard sessions to diverge from the original run. Read difficulty from the snapshot's SerializedWorldState field and pass it through; pre-V22 snapshots default to 'Normal'. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: fe6f3422c1
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
createScenario always starts at LATEST_SIM_VERSION (V22). Without restoring the snapshot's simVersion, replaying a pre-V22 capture would have V22-gated paths active (tiebreaks, brood modifier), causing false SCEN-06 divergence reports on valid historical snapshots. Fix: assign replay.simVersion from the snapshot immediately after createScenario. Emit a console.warn when the value is missing or invalid so replay divergence is visible rather than silent. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e332c45885
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Easy (220–360), Normal (330–470), and Hard (440–580) overlapped by 30px each. Clicks in the overlap bands routed to the wrong difficulty. Fix: shift Easy left to x=180 and Hard right to x=480, giving 10px gaps between all three buttons (180–320 / 330–470 / 480–620), centered in the 800px canvas. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
@codex review |
|
Codex Review: Didn't find any major issues. Swish! ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
Summary
WorldState.difficulty('Easy'|'Normal'|'Hard'), updated from V21 to V22 as LATEST_SIM_VERSIONColonyRecord.eggIntervalNumeratorstores per-colony scaling (Easy=5, Normal=4, Hard=3); lifecycle-system applies(interval * numerator) >> 2— integer-only, no division operator; hard floor atMIN_EGG_INTERVAL_TICKS=100NORMAL_TIER_INDEXtotierIndex(world.difficulty)at V22+MATCH_TIMEOUT_TICKS=24000): both queens survive to tick 24000 → winner by living worker count → Victory/Defeat/MutualDestructionSTALEMATE_FOOD_THRESHOLD_FP=512): all food piles depleted AND both colonies below threshold → MutualDestructionround_endSimEvent: emitted bycheckTiebreaks()for playtrace attribution;deriveRoundEndReason()checks it beforequeen_deathdifficulty='Normal'andeggIntervalNumerator=4(identity); all V22-gated paths fall back to Normal-tier behaviour for byte-identical replayTest plan
npm run test— 73 files, 2201 tests passnpm run test:coverage— statements 90%, branches 83%, functions 96%, lines 93% (all above 80% gate)npx tsc --noEmit— cleandifficulty: 'Hard'and AI colonyeggIntervalNumerator: 3🤖 Generated with Claude Code