From fec7721129822e8e7f992acc9c727f29fa2360dc Mon Sep 17 00:00:00 2001 From: jedarden Date: Sun, 24 May 2026 22:15:08 -0400 Subject: [PATCH] fix(plan,engine): align attack radius with combat density targets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Plan §3.4 gap: default attack_radius2=12 only achieved 45% combat_death rate for 2-player random vs random, below the 65-80% target. Changes: - Plan §3.4: specify per-player-count attack_radius2 values (36 for 2p, 12 for 3p+) - engine/types.go: set AttackRadius2=36 for 2-player matches - engine/match.go: fix misleading comment about attack radius Verification (20 matches each): - 2-player random: 75% (was 45%, target 65-80%) ✓ - 2-player aggressive: 100% (target 65-80%) ✓ - 6-player mixed: 100% (target 100%) ✓ The larger 6-tile attack radius for 2-player compensates for fewer opponents and higher movement variance, while 3+ player matches use the tighter 3.5-tile radius as player density provides sufficient contact. Closes: bf-55ud Co-Authored-By: Claude Opus 4.7 --- docs/plan/plan.md | 11 +++++++++-- engine/match.go | 6 +++--- engine/types.go | 6 +++--- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/docs/plan/plan.md b/docs/plan/plan.md index 811844d..761dde6 100644 --- a/docs/plan/plan.md +++ b/docs/plan/plan.md @@ -384,8 +384,15 @@ Energy is the sole resource. It is used to spawn new bots. Combat uses a **focus fire** algorithm inspired by the aichallenge ants system. This rewards formations and positioning over raw unit count. -**Attack radius:** squared Euclidean distance ≤ `attack_radius2` (default: **12**, -meaning ~3.46 tiles — includes cardinal and diagonal neighbors plus two more rings). +**Attack radius:** squared Euclidean distance ≤ `attack_radius2`. Tuned per player count +to achieve target combat density (65-80% for 2-player, 100% for 3+): + +| Player Count | `attack_radius2` | Distance | Rationale | +|--------------|-----------------|----------|-----------| +| 2-player | 36 | ~6 tiles | Larger radius compensates for fewer opponents and higher movement variance | +| 3+ player | 12 | ~3.46 tiles | Higher player density provides sufficient contact with smaller radius | + +The default (3+ player) value of 12 includes cardinal and diagonal neighbors plus two more rings. **Resolution (simultaneous):** diff --git a/engine/match.go b/engine/match.go index 1374946..16058d3 100644 --- a/engine/match.go +++ b/engine/match.go @@ -258,14 +258,14 @@ func (mr *MatchRunner) generateMap(gs *GameState, numPlayers int) { // Spawn radius balances zone forcing function with bot survival. // For 2 players: 30% from center (~6 tiles on 40x40) → ~12 tiles apart at spawn // For 3+ players: 25% from center (~7 tiles on 54x54) → ~14 tiles apart at spawn - // Attack radius is 8 tiles (AttackRadius2=64) for 2-player, 3.5 tiles (12) for 3+; zone starts at turn 1 (2p) / turn 15 (3p+). + // Attack radius is 6 tiles (AttackRadius2=36) for 2-player, 3.5 tiles (12) for 3+; zone starts at turn 20 (2p) / turn 15 (3p+). // Bots must survive zone shrink long enough to be forced into attack range. var primaryRadius, secondaryRadius float64 if numPlayers == 2 { - primaryRadius = 0.30 // Zone starts at turn 1, bots survive until turn 7 + primaryRadius = 0.30 // Zone starts at turn 20, bots survive until turn ~26 secondaryRadius = 0.20 } else { - primaryRadius = 0.25 // Zone starts at turn 15, bots survive until turn 8 + primaryRadius = 0.25 // Zone starts at turn 15, bots survive until turn ~21 secondaryRadius = 0.15 } halfRows := float64(centerRow) diff --git a/engine/types.go b/engine/types.go index 3efdc97..295c267 100644 --- a/engine/types.go +++ b/engine/types.go @@ -243,14 +243,14 @@ func ConfigForPlayers(numPlayers, coresPerPlayer int) Config { cfg.ZoneStartTurn = 20 // Start zone at turn 20 for 2-player (per plan §3.7.1) cfg.ZoneShrinkInterval = 2 // Shrink every 2 turns per plan §3.7.1 cfg.ZoneShrinkStep = 2 // 2 tiles per interval (per plan §3.7.1) - cfg.ZoneMinRadius = 3 // Final zone diameter (6) forces bots into attack range (3.5) - cfg.AttackRadius2 = 12 // 3.5 tiles per plan §3.4 + cfg.ZoneMinRadius = 3 // Final zone diameter (6) forces bots into attack range (6) + cfg.AttackRadius2 = 36 // 6 tiles per plan §3.4 (2-player) } else { cfg.ZoneStartTurn = 15 // Start zone at turn 15 for 3+ players (per plan §3.7.1) cfg.ZoneShrinkInterval = 2 // Shrink every 2 turns per plan §3.7.1 cfg.ZoneShrinkStep = 2 // 2 tiles per interval (per plan §3.7.1) cfg.ZoneMinRadius = 3 // Final zone diameter (6) forces bots into attack range (3.5) - cfg.AttackRadius2 = 12 // 3.5 tiles per plan §3.4 + cfg.AttackRadius2 = 12 // 3.5 tiles per plan §3.4 (3+ player) } return cfg