Skip to content

Conversation

@sambokai
Copy link
Contributor

@sambokai sambokai commented Oct 20, 2025

Strategic Economic Spending for FakeHuman Bots

Caution

This is a work in progress. Please do not merge.

Description:

Summary

Implements sophisticated economic decision-making for FakeHuman bots that adapts spending behavior based on competitive board state and game progression. This makes bots more strategically challenging by forcing players to consider economic pressure and MIRV deterrence.

Expands on and includes unmerged changes from:

Other Related Issues and PRs:

Other

  • I have added screenshots for all UI updates
  • I process any text displayed to the user through translateText() and I've added it to the en.json file
  • I have added relevant tests to the test directory
  • I confirm I have thoroughly tested these changes and take full responsibility for any bugs introduced

Discord

samsammiliah

sambokai and others added 30 commits October 18, 2025 20:16
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 20, 2025

Walkthrough

Integrates MIRV strategy into FakeHumanExecution with cooldowns, target-selection (counter, victory-denial, steamroll), reserve-aware spending, and a dynamic build-order; adds MIRV target param typing and passes targetTile when spawning MIRVs; includes extensive MIRV retaliation tests.

Changes

Cohort / File(s) Summary
FakeHuman MIRV strategy & build-order
src/core/execution/FakeHumanExecution.ts
Adds MIRV integration: cooldowns, hesitation/victory-denial/steamroll logic, reserve budgeting, dynamic prioritized build-order (prefers Missile Silo when appropriate), many helper methods for target selection, eligibility, territory/tile calculations, MIRV lifecycle (cooldowns, pruning), and invokes considerMIRV each tick.
MIRV execution: spawn targeting
src/core/execution/MIRVExecution.ts
When spawning MIRV units, passes { targetTile: this.dst } into buildUnit so spawned MIRVs receive explicit target tile information.
Game unit param typing
src/core/game/Game.ts
Updates UnitParamsMap for UnitType.MIRV from Record<string, never> to { targetTile?: number }, exposing optional public target tile in unit params.
MIRV retaliation tests
tests/FakeHumanMIRV.test.ts
Adds comprehensive tests covering FakeHuman MIRV retaliation scenarios (direct retaliation, victory denial, steamroll interruption, team scenarios), asserting MIRV launches, targeting correctness, and interactions with tick progression and randomness seeds.

Sequence Diagram(s)

sequenceDiagram
    actor Tick as Game Tick
    participant FH as FakeHumanExecution
    participant MIRV as MIRV Logic
    participant Build as Unit Builder / MirvExecution
    participant Target as Target Selector

    Tick->>FH: tick(game)
    FH->>MIRV: considerMIRV(gameState)
    rect #e8f3ff
        MIRV->>MIRV: check cooldowns & reserves
        MIRV->>Target: evaluate scenarios (counter / deny / steamroll)
    end

    alt Threat selected
        Target->>Build: request MIRV spawn with `targetTile`
        Build->>Build: buildUnit(type=MIRV, params={targetTile})
        Build->>Target: confirm outbound MIRV
    else No action
        Note right of MIRV: continue normal spend/build flow
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Reasoning: substantial new strategic logic in FakeHumanExecution with many new helper methods plus type change and extensive tests. Review will require reading new control flow and verifying budgeting/eligibility conditions.
  • Pay extra attention to:
    • FakeHumanExecution.ts — MIRV budgeting, cooldown and reserve math, and integration into tick.
    • MIRVExecution.tick — verify targetTile use does not break spawn/warhead expectations.
    • tests/FakeHumanMIRV.test.ts — stochastic tests and seed usage; ensure flakiness is minimized.

Possibly related PRs

Suggested labels

Feature - AI, Feature - Simulation, Balance Tweak

Suggested reviewers

  • scottanderson
  • evanpelle
  • VariableVince

Poem

🚀 Missiles planned with careful code,

AI plots paths along the road.
Targets picked with tidy art,
Cooldowns guard each measured start.
Tests sing victory — logic smart.

Pre-merge checks

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title Check ✅ Passed The title "Feature: Strategic Economic Spending for FakeHumans (Nations)" directly relates to the changeset, which implements MIRV reserve budgeting, spending thresholds, and build-order prioritization based on economic state. While the PR heavily focuses on MIRV strategy integration (the main mechanism), the title accurately captures the strategic economic decision-making intent that drives the MIRV deployment logic. The title refers to a real and core aspect of the changes—sophisticated spending behavior adaptation—which aligns with the PR's objectives.
Description Check ✅ Passed The description states the PR implements "sophisticated economic decision-making for FakeHuman bots that adapts spending behavior based on competitive board state and game progression" with MIRV deterrence, which aligns with the changeset. The changes indeed add MIRV spending logic, reserve-aware budgeting, target selection based on board state, and lifecycle management. The description is related to the changeset and conveys meaningful intent, even though it's marked as work-in-progress and lacks exhaustive detail about the implementation approach.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/core/execution/MIRVExecution.ts (2)

71-88: Missing silo cooldown on MIRV launch (launch() not called).

NukeExecution triggers silo.launch() when firing; MIRVExecution should too. Otherwise silos can chain‑fire MIRVs without cooldown. Add a launch call for the silo at the spawn tile.

Apply this diff:

       this.nuke = this.player.buildUnit(UnitType.MIRV, spawn, {
         targetTile: this.dst,
       });
+      // Put the launching silo into cooldown (mirrors NukeExecution behavior)
+      const silo = this.player
+        .units(UnitType.MissileSilo)
+        .find((u) => u.tile() === spawn);
+      if (silo) {
+        silo.launch();
+      }

74-79: Bug: double x() call uses x‑coordinate as a TileRef.

this.mg.x(this.mg.x(this.nuke.tile())) calls x() with a number, not a TileRef. Use the nuke’s tile directly.

Apply this diff:

-      const x = Math.floor(
-        (this.mg.x(this.dst) + this.mg.x(this.mg.x(this.nuke.tile()))) / 2,
-      );
+      const x = Math.floor(
+        (this.mg.x(this.dst) + this.mg.x(this.nuke.tile())) / 2,
+      );
🧹 Nitpick comments (8)
src/core/execution/FakeHumanExecution.ts (6)

437-448: Build order pipeline: clear; keep it data‑driven.

Nice separation via getBuildOrder() and per‑type multipliers. Consider extracting the base array to a top‑level readonly constant and typing the multiplier as (ownedPlusOne: number) => number for readability.

Also applies to: 450-486


733-766: MIRV decision gate: OK; small enhancement.

Logic is sound: silo present, has gold, cooldown window, hesitation odds, then target selection. Optional: short‑circuit earlier by checking a cheap canBuild(UnitType.MIRV, anyEnemyTile) before heavier scans.


1000-1039: BigInt/Number mixing may overflow later; prefer BigInt.

Number(this.player.gold()) and comparisons to Number literals risk precision loss if gold scales up. Use BigInt literals (e.g., 10_000_000n) and compare with BigInt.

Apply this minimal diff:

-    const gold = Number(this.player.gold());
-    if (currentSilos < 2 && gold > 10_000_000 && territorySize > 50) {
+    const gold = this.player.gold();
+    if (currentSilos < 2 && gold > 10_000_000n && territorySize > 50) {
       return true;
     }

And similarly avoid Number() in other gold comparisons.


1045-1133: Dynamic reserve threshold: solid, but use BigInt end‑to‑end.

The benchmarking math is thorough. However, converting Gold (bigint) to Number throughout can lose precision. Recommend:

  • Keep other players’ gold as bigint; compute scaled thresholds using bigint arithmetic where possible; only convert to Number for ratios, then back once, clamped to a bigint maximum.
  • Document the intended gold magnitude to justify any Number conversions.

I can provide a bigint‑safe helper module (sum/avg/topK, ratio via fixed‑point) if helpful.

Also applies to: 1138-1156


73-75: Unused constant.

MIRV_SAVING_URGENCY_MULTIPLIER is declared but never used. Remove or wire it into reserve logic.

Apply this diff to remove:

-  /** Game progression factor - how much more urgent MIRV saving becomes over time */
-  private static readonly MIRV_SAVING_URGENCY_MULTIPLIER = 0.5;

436-448: handleUnits() returns boolean but the return value is ignored.

Either consume the boolean in tick() or change return type to void to avoid confusion.

-  private handleUnits() {
+  private handleUnits(): void {
     const buildOrder = this.getBuildOrder();
     for (const { type, multiplier } of buildOrder) {
       if (type === UnitType.Warship) {
-        if (this.maybeSpawnWarship()) return true;
+        if (this.maybeSpawnWarship()) return;
       } else {
-        if (this.maybeSpawnStructure(type, multiplier)) return true;
+        if (this.maybeSpawnStructure(type, multiplier)) return;
       }
     }
-    return false;
   }
tests/FakeHumanMIRV.test.ts (1)

99-120: Seed‑sweep to dodge hesitation odds: OK; reduce flakiness.

Looping over 20 seeds is pragmatic. For determinism, consider injecting a fixed attackRate/attackTick via a test‑only constructor or setter, and tick the game each loop (executeNextTick) while calling testExecution.tick(game.ticks()) to keep clocks aligned.

Also applies to: 259-281, 415-433, 571-589

src/core/game/Game.ts (1)

266-269: Use TileRef consistently across all bomb units in UnitParamsMap.

Construction path is confirmed: UnitImpl reads params.targetTile during construction (line 54). However, all four bomb types (AtomBomb, HydrogenBomb, MIRV, MIRVWarhead) at lines 236, 241, 267, 271 use targetTile?: number while the Unit interface and GameUpdates use targetTile?: TileRef. Since TileRef is the semantic alias for tile references, update all four bomb unit params to use targetTile?: TileRef for consistency and clarity.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 73bf583 and fd55f4b.

📒 Files selected for processing (4)
  • src/core/execution/FakeHumanExecution.ts (10 hunks)
  • src/core/execution/MIRVExecution.ts (1 hunks)
  • src/core/game/Game.ts (1 hunks)
  • tests/FakeHumanMIRV.test.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (8)
📓 Common learnings
Learnt from: sambokai
PR: openfrontio/OpenFrontIO#2225
File: src/core/execution/FakeHumanExecution.ts:172-173
Timestamp: 2025-10-18T17:54:01.293Z
Learning: In src/core/execution/FakeHumanExecution.ts, MIRVs and ground attacks should not be mutually exclusive. The considerMIRV() method should not short-circuit maybeAttack() - both actions can occur in the same tick.
📚 Learning: 2025-05-18T23:36:12.847Z
Learnt from: scottanderson
PR: openfrontio/OpenFrontIO#784
File: src/core/game/StatsImpl.ts:143-159
Timestamp: 2025-05-18T23:36:12.847Z
Learning: In this codebase, NukeType is a union type derived from UnitType values (specifically bomb-related values like AtomBomb, HydrogenBomb, MIRV, and MIRVWarhead) rather than a separate enum. This means comparing NukeType values against UnitType values in switch statements is valid and intentional.

Applied to files:

  • src/core/game/Game.ts
📚 Learning: 2025-05-18T23:36:12.847Z
Learnt from: scottanderson
PR: openfrontio/OpenFrontIO#784
File: src/core/game/StatsImpl.ts:143-159
Timestamp: 2025-05-18T23:36:12.847Z
Learning: In this codebase, NukeType is a union type derived from specific UnitType enum values (AtomBomb, HydrogenBomb, MIRV, MIRVWarhead). This means that comparisons in switch statements between a NukeType parameter and UnitType enum values are valid and will work correctly at runtime.

Applied to files:

  • src/core/game/Game.ts
📚 Learning: 2025-10-18T17:54:01.293Z
Learnt from: sambokai
PR: openfrontio/OpenFrontIO#2225
File: src/core/execution/FakeHumanExecution.ts:172-173
Timestamp: 2025-10-18T17:54:01.293Z
Learning: In src/core/execution/FakeHumanExecution.ts, MIRVs and ground attacks should not be mutually exclusive. The considerMIRV() method should not short-circuit maybeAttack() - both actions can occur in the same tick.

Applied to files:

  • tests/FakeHumanMIRV.test.ts
  • src/core/execution/FakeHumanExecution.ts
  • src/core/execution/MIRVExecution.ts
📚 Learning: 2025-10-20T20:15:28.833Z
Learnt from: sambokai
PR: openfrontio/OpenFrontIO#2225
File: src/core/execution/FakeHumanExecution.ts:51-51
Timestamp: 2025-10-20T20:15:28.833Z
Learning: In src/core/execution/FakeHumanExecution.ts, game balance constants like MIRV_COOLDOWN_TICKS, MIRV_HESITATION_ODDS, VICTORY_DENIAL_TEAM_THRESHOLD, VICTORY_DENIAL_INDIVIDUAL_THRESHOLD, and STEAMROLL_CITY_GAP_MULTIPLIER are experimental tuning parameters subject to frequent change during balance testing. Do not flag changes to these values as issues or compare them against previous values.

Applied to files:

  • tests/FakeHumanMIRV.test.ts
  • src/core/execution/FakeHumanExecution.ts
📚 Learning: 2025-10-20T11:02:16.949Z
Learnt from: sambokai
PR: openfrontio/OpenFrontIO#2225
File: src/core/execution/FakeHumanExecution.ts:57-57
Timestamp: 2025-10-20T11:02:16.949Z
Learning: In src/core/execution/FakeHumanExecution.ts, the correct MIRV victory denial thresholds are VICTORY_DENIAL_TEAM_THRESHOLD = 0.8 (80% for team games) and VICTORY_DENIAL_INDIVIDUAL_THRESHOLD = 0.65 (65% for individual players), not 0.85 and 0.7 as might be mentioned in some documentation.

Applied to files:

  • tests/FakeHumanMIRV.test.ts
  • src/core/execution/FakeHumanExecution.ts
📚 Learning: 2025-08-23T08:03:44.914Z
Learnt from: ElMelchizedek
PR: openfrontio/OpenFrontIO#1876
File: src/core/execution/FakeHumanExecution.ts:547-592
Timestamp: 2025-08-23T08:03:44.914Z
Learning: In OpenFrontIO, FakeHumanExecution is used for AI-controlled nations that simulate human behavior, which is distinct from PlayerType.Bot. FakeHumanExecution players are not PlayerType.Bot - they represent more sophisticated AI that mimics human nation behavior, while PlayerType.Bot represents basic AI players.

Applied to files:

  • src/core/execution/FakeHumanExecution.ts
📚 Learning: 2025-08-18T03:11:18.617Z
Learnt from: scottanderson
PR: openfrontio/OpenFrontIO#1851
File: src/core/execution/FakeHumanExecution.ts:433-441
Timestamp: 2025-08-18T03:11:18.617Z
Learning: In FakeHumanExecution.maybeSpawnStructure, the perceived cost multiplier (owned + 1, capped at 5) applied to structure costs is intentional. This makes AI nations build fewer structures than players could, saving gold for bombs/nukes rather than maxing out structures.

Applied to files:

  • src/core/execution/FakeHumanExecution.ts
🧬 Code graph analysis (2)
tests/FakeHumanMIRV.test.ts (5)
tests/util/Setup.ts (1)
  • setup (23-80)
src/core/game/Game.ts (2)
  • PlayerInfo (397-417)
  • Cell (304-326)
src/core/execution/MIRVExecution.ts (1)
  • MirvExecution (16-192)
tests/util/utils.ts (1)
  • executeTicks (32-36)
src/core/execution/FakeHumanExecution.ts (2)
  • FakeHumanExecution (30-1165)
  • tick (142-192)
src/core/execution/FakeHumanExecution.ts (7)
src/core/execution/utils/BotBehavior.ts (1)
  • BotBehavior (25-340)
src/core/game/Game.ts (5)
  • Tick (22-22)
  • PlayerID (21-21)
  • Nation (296-302)
  • Player (519-653)
  • Gold (23-23)
src/core/game/GameMap.ts (3)
  • TileRef (3-3)
  • x (122-124)
  • cost (248-250)
src/core/game/PlayerImpl.ts (5)
  • type (200-202)
  • team (740-742)
  • tiles (278-280)
  • target (514-517)
  • gold (764-766)
src/core/game/GameImpl.ts (5)
  • x (780-782)
  • players (402-404)
  • owner (165-167)
  • target (574-580)
  • cost (843-845)
src/core/execution/MIRVExecution.ts (2)
  • owner (181-183)
  • MirvExecution (16-192)
src/core/execution/NukeExecution.ts (3)
  • owner (325-327)
  • target (43-45)
  • tick (104-183)
🔇 Additional comments (11)
src/core/execution/FakeHumanExecution.ts (7)

190-191: Order is correct: MIRV does not block ground attacks.

considerMIRV() runs before maybeAttack() without early return, matching the “not mutually exclusive” guidance.

Based on learnings


288-296: Don’t nuke basic bots: good guard.

Skipping nukes vs PlayerType.Bot aligns with FakeHuman vs Bot distinction and avoids wasting gold.

Based on learnings


498-502: Reserve‑aware spending: good integration.

canAffordWithReserve() here enforces MIRV deterrence savings while building structures.


566-572: Warship spending respects MIRV reserve.

Using canAffordWithReserve(warshipCost) is consistent with the economic strategy.


778-821: Team victory‑denial: targets largest team member correctly.

Logic matches threshold guidance and selects the largest teammate only when team exceeds threshold.

Based on learnings


742-746: Cooldown queue logic: OK.

Queue semantics and removal by tick age are correct; pushing a representative tile for cooldown is reasonable.

Also applies to: 965-973, 975-984


888-899: API verified and correctly used.

The GameMap interface declares hasOwner(ref: TileRef): boolean, and the implementation in GameMap.ts line 176 returns this.ownerID(ref) !== 0. The code at line 894 uses this method correctly: this.mg.hasOwner(dst) follows the expected signature, and the method is consistently used throughout the codebase in similar contexts.

tests/FakeHumanMIRV.test.ts (3)

83-87: Precondition check is meaningful.

Verifying attacker’s MIRV is in flight before retaliation improves signal in failures.


516-560: Team victory‑denial: clear largest‑member expectation.

The 3:1 bias and share > 0.8 check align with code logic and retrieved learnings.

Based on learnings


78-88: No issues found. The targetTile parameter is already propagated correctly.

The code already implements the required behavior:

  • MirvExecution passes targetTile: this.dst when calling buildUnit
  • UnitImpl constructor correctly checks for targetTile in params and initializes _targetTile
  • The test assertions will pass because the full propagation chain works as expected

The test guards the API shape correctly and requires no changes.

src/core/execution/MIRVExecution.ts (1)

71-73: Verified: MIRV targetTile parameter is correctly applied during unit construction.

The code change is correct. When buildUnit is called with targetTile, the parameter is passed to UnitImpl constructor, which directly extracts and assigns it to _targetTile (UnitImpl.ts:53-54). The accessor targetTile() will return the correct value. The parameter is applied during construction, not via setTargetTile(), but the result is the same—downstream logic can read MIRV.targetTile() without undefined issues.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
src/core/execution/FakeHumanExecution.ts (1)

439-451: Add explicit return type annotation.

The method returns boolean but lacks a type annotation.

Apply this diff:

-  private handleUnits() {
+  private handleUnits(): boolean {
     const buildOrder = this.getBuildOrder();
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fd55f4b and 5e75993.

📒 Files selected for processing (2)
  • src/core/execution/FakeHumanExecution.ts (10 hunks)
  • src/core/game/Game.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/core/game/Game.ts
🧰 Additional context used
🧠 Learnings (7)
📓 Common learnings
Learnt from: sambokai
PR: openfrontio/OpenFrontIO#2225
File: src/core/execution/FakeHumanExecution.ts:172-173
Timestamp: 2025-10-18T17:54:01.311Z
Learning: In src/core/execution/FakeHumanExecution.ts, MIRVs and ground attacks should not be mutually exclusive. The considerMIRV() method should not short-circuit maybeAttack() - both actions can occur in the same tick.
Learnt from: sambokai
PR: openfrontio/OpenFrontIO#2225
File: src/core/execution/FakeHumanExecution.ts:770-795
Timestamp: 2025-10-27T09:47:26.376Z
Learning: In src/core/execution/FakeHumanExecution.ts, the selectSteamrollStopTarget() method intentionally allows MIRV targeting when secondHighest city count is 0 (e.g., nuclear endgame scenarios where structures are destroyed). This is valid game design—"if you can afford it, you're good to go"—and should not be flagged as requiring a guard condition.
Learnt from: sambokai
PR: openfrontio/OpenFrontIO#2225
File: src/core/execution/FakeHumanExecution.ts:711-723
Timestamp: 2025-10-17T19:16:57.699Z
Learning: In the OpenFrontIO game, MIRVs (Multiple Independently targetable Reentry Vehicles) have an area of effect with a radius of 1500 tiles around the aim point. To maximize efficiency, bots should aim at the center of the target player's territory rather than selecting random tiles. This differs from the initial understanding that MIRVs covered an entire player's territory regardless of aim point.
Learnt from: sambokai
PR: openfrontio/OpenFrontIO#2225
File: src/core/execution/FakeHumanExecution.ts:51-51
Timestamp: 2025-10-20T20:15:28.858Z
Learning: In src/core/execution/FakeHumanExecution.ts, game balance constants like MIRV_COOLDOWN_TICKS, MIRV_HESITATION_ODDS, VICTORY_DENIAL_TEAM_THRESHOLD, VICTORY_DENIAL_INDIVIDUAL_THRESHOLD, and STEAMROLL_CITY_GAP_MULTIPLIER are experimental tuning parameters subject to frequent change during balance testing. Do not flag changes to these values as issues or compare them against previous values.
📚 Learning: 2025-10-18T17:54:01.311Z
Learnt from: sambokai
PR: openfrontio/OpenFrontIO#2225
File: src/core/execution/FakeHumanExecution.ts:172-173
Timestamp: 2025-10-18T17:54:01.311Z
Learning: In src/core/execution/FakeHumanExecution.ts, MIRVs and ground attacks should not be mutually exclusive. The considerMIRV() method should not short-circuit maybeAttack() - both actions can occur in the same tick.

Applied to files:

  • src/core/execution/FakeHumanExecution.ts
📚 Learning: 2025-10-20T20:15:28.858Z
Learnt from: sambokai
PR: openfrontio/OpenFrontIO#2225
File: src/core/execution/FakeHumanExecution.ts:51-51
Timestamp: 2025-10-20T20:15:28.858Z
Learning: In src/core/execution/FakeHumanExecution.ts, game balance constants like MIRV_COOLDOWN_TICKS, MIRV_HESITATION_ODDS, VICTORY_DENIAL_TEAM_THRESHOLD, VICTORY_DENIAL_INDIVIDUAL_THRESHOLD, and STEAMROLL_CITY_GAP_MULTIPLIER are experimental tuning parameters subject to frequent change during balance testing. Do not flag changes to these values as issues or compare them against previous values.

Applied to files:

  • src/core/execution/FakeHumanExecution.ts
📚 Learning: 2025-10-27T09:47:26.376Z
Learnt from: sambokai
PR: openfrontio/OpenFrontIO#2225
File: src/core/execution/FakeHumanExecution.ts:770-795
Timestamp: 2025-10-27T09:47:26.376Z
Learning: In src/core/execution/FakeHumanExecution.ts, the selectSteamrollStopTarget() method intentionally allows MIRV targeting when secondHighest city count is 0 (e.g., nuclear endgame scenarios where structures are destroyed). This is valid game design—"if you can afford it, you're good to go"—and should not be flagged as requiring a guard condition.

Applied to files:

  • src/core/execution/FakeHumanExecution.ts
📚 Learning: 2025-10-20T11:02:16.969Z
Learnt from: sambokai
PR: openfrontio/OpenFrontIO#2225
File: src/core/execution/FakeHumanExecution.ts:57-57
Timestamp: 2025-10-20T11:02:16.969Z
Learning: In src/core/execution/FakeHumanExecution.ts, the correct MIRV victory denial thresholds are VICTORY_DENIAL_TEAM_THRESHOLD = 0.8 (80% for team games) and VICTORY_DENIAL_INDIVIDUAL_THRESHOLD = 0.65 (65% for individual players), not 0.85 and 0.7 as might be mentioned in some documentation.

Applied to files:

  • src/core/execution/FakeHumanExecution.ts
📚 Learning: 2025-08-23T08:03:44.914Z
Learnt from: ElMelchizedek
PR: openfrontio/OpenFrontIO#1876
File: src/core/execution/FakeHumanExecution.ts:547-592
Timestamp: 2025-08-23T08:03:44.914Z
Learning: In OpenFrontIO, FakeHumanExecution is used for AI-controlled nations that simulate human behavior, which is distinct from PlayerType.Bot. FakeHumanExecution players are not PlayerType.Bot - they represent more sophisticated AI that mimics human nation behavior, while PlayerType.Bot represents basic AI players.

Applied to files:

  • src/core/execution/FakeHumanExecution.ts
📚 Learning: 2025-08-18T03:11:18.617Z
Learnt from: scottanderson
PR: openfrontio/OpenFrontIO#1851
File: src/core/execution/FakeHumanExecution.ts:433-441
Timestamp: 2025-08-18T03:11:18.617Z
Learning: In FakeHumanExecution.maybeSpawnStructure, the perceived cost multiplier (owned + 1, capped at 5) applied to structure costs is intentional. This makes AI nations build fewer structures than players could, saving gold for bombs/nukes rather than maxing out structures.

Applied to files:

  • src/core/execution/FakeHumanExecution.ts
🧬 Code graph analysis (1)
src/core/execution/FakeHumanExecution.ts (5)
src/core/execution/utils/BotBehavior.ts (1)
  • BotBehavior (25-340)
src/core/game/Game.ts (5)
  • Tick (22-22)
  • PlayerID (21-21)
  • Nation (299-305)
  • Player (525-661)
  • Gold (23-23)
src/core/game/GameView.ts (8)
  • type (94-96)
  • type (340-342)
  • team (337-339)
  • x (671-673)
  • owner (109-111)
  • owner (636-638)
  • tile (106-108)
  • gold (362-364)
src/core/Schemas.ts (2)
  • GameID (24-24)
  • Player (116-116)
src/core/execution/MIRVExecution.ts (2)
  • owner (181-183)
  • MirvExecution (16-192)
🔇 Additional comments (10)
src/core/execution/FakeHumanExecution.ts (10)

23-23: LGTM! Clean integration of MIRV infrastructure.

The import, state tracking field, and strategic constants properly establish the foundation for MIRV decision-making. The lastMIRVSent array follows the same pattern as lastNukeSent for consistency.

Also applies to: 46-46, 49-75


191-191: LGTM! Correct integration of MIRV strategy.

The considerMIRV() call is properly sequenced before maybeAttack(), allowing both MIRV launches and ground attacks to occur in the same tick as intended.

Based on learnings.


453-489: LGTM! Clean dynamic build order implementation.

The priority-based build system elegantly handles strategic shifts (e.g., prioritizing Missile Silos in mid/late game) while maintaining a sensible base order. The conditional reordering is clear and maintainable.


501-504: LGTM! Reserve-aware spending properly integrated.

The canAffordWithReserve() checks ensure bots maintain MIRV deterrence funds while making structure and unit decisions. Clean integration with existing spawn logic.

Also applies to: 569-575


737-824: LGTM! Well-structured MIRV decision system.

The three-tiered target selection (counter-MIRV → victory denial → steamroll) provides strategic depth. The victory denial logic correctly handles both team-based and individual victory threats, and the severity scoring ensures the most critical target is prioritized.


826-938: LGTM! Efficient and strategic targeting implementation.

The steamroll detection via city count gap is sound. The caching in getValidMirvTargetPlayers reduces repeated filtering overhead, and calculateTerritoryCenter correctly implements center-mass targeting to maximize MIRV coverage within its 1500-tile radius.

Based on learnings.


941-987: LGTM! Clean MIRV execution flow.

The execution methods properly sequence cooldown tracking, territory center targeting, and fallback logic. The cooldown mechanism correctly enforces the MIRV_COOLDOWN_TICKS constraint.


994-1042: LGTM! Strategic silo prioritization well-designed.

The multi-condition checks account for game progression, economic position, and competitive pressure. The thresholds (5 min, 10 min, 10M gold, 20M competitive threshold) provide reasonable guardrails for strategic timing.


1048-1136: LGTM! Sophisticated economic pressure analysis.

The multi-factor reserve threshold calculation (top player gap, economic level, MIRV capability pressure) creates dynamic deterrence that scales with competitive state. The weighted benchmark (60% top players, 40% average) and progressive multipliers provide nuanced responses to different threat levels.


1141-1159: LGTM! Clean reserve-aware spending interface.

The getSpendableGold() and canAffordWithReserve() methods provide a clear abstraction for reserve-aware budgeting, ensuring MIRV deterrence funds are maintained across all spending decisions.

evanpelle added a commit that referenced this pull request Oct 29, 2025
…lly (#2225)

## Description:

> [!IMPORTANT]
> Try here: https://mirv-test.openfront.dev/ 

> [!NOTE]
> Blocks PRs:
> - #2244 
> - #2263

### Summary
Implements intelligent MIRV usage for fakehuman players, enabling them
to make strategic nuclear strikes based on game state analysis.
 
### Changes

#### Core FakeHuman Strategy (`FakeHumanExecution.ts`)
- **MIRV Decision System**: Added `considerMIRV()` method that evaluates
game state and determines optimal MIRV usage
- **Three Strategic Targeting Modes**:
1. **Counter-MIRV**: Retaliatory strikes against players actively
launching MIRVs at the fakehuman
2. **Victory Denial**: Preemptive strikes against players approaching
win conditions
     - Team threshold: n% of total land (configurable)
     - Individual threshold: n% of total land (configurable)
3. **Steamroll Prevention**: Strikes against players with dominant city
counts (n% ahead of next competitor)

#### FakeHuman Behavior Tuning
- **Cooldown System**: n-minute cooldown between MIRV attempts
(configurable)
- **Failure Rate**: ~n% chance of cooldown trigger without launch
(simulates human hesitation/resource management; configurable)
- **Territory Targeting**: Centers MIRV strikes on enemy territory
center-of-mass for maximum impact

#### Technical Improvements
- **Type Safety**: Updated `UnitParamsMap` to include `targetTile`
parameter for MIRV units
- **Execution Flow**: Integrated MIRV consideration into fakehuman tick
cycle outside of standard attack logic, due to its holistic strategic
nature

### Game Balance Impact
- **FakeHuman Threat Level**: Increases late-game fakehuman
competitiveness
- **Endgame Dynamics**: Prevents runaway victories, extends game tension

### Breaking Changes
None - purely additive feature

### Related GitHub Issues:
-  #2205 

------
## Other

- [x] I have added screenshots for all UI updates
- [x] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [x] I have added relevant tests to the test directory
- [x] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced

Discord Username: samsammiliah

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: Evan <evanpelle@gmail.com>
@ryanbarlow97 ryanbarlow97 modified the milestones: v27, Backlog Nov 25, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants