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