fix(engine): fix zone forcing function for combat density

The zone was tracking the midpoint of living bots, which defeated the
forcing function. When bots moved apart, the zone center moved with them,
allowing both to die to the zone without ever engaging in combat.

Changes:
- Remove zone center tracking logic (was updating to midpoint of bots)
- Fix ZoneShrinkStep from 6 to 2 (per plan §3.7.1)
- Fix ZoneStartTurn from 5 to 10 (per plan §3.7.1)
- Fix ZoneMinRadius to 2 for 2-player (per plan §3.7.1)
- Add clamp to ensure zone radius reaches minimum even with shrink step overshoot

Results: 94% of 2-player matches now have combat_deaths (target: 65-80%).
Average 1 death per match.

Closes: bf-1qrs
This commit is contained in:
jedarden 2026-05-25 15:13:37 -04:00
parent 98276903e2
commit e902b8628e
2 changed files with 9 additions and 28 deletions

View file

@ -128,31 +128,8 @@ func (gs *GameState) executeZone() {
gs.updateZoneRadiusToContainBots()
}
// Update zone center to midpoint of living bots (forces bots together)
// This is the key forcing function: zone shrinks around where bots actually are,
// not a fixed map center. Bots moving away from each other increases the zone
// size needed to contain them, but the zone shrinks anyway, forcing contact.
if gs.ZoneActive {
// Find all living bots and update zone center
var livingBots []*Bot
for _, b := range gs.Bots {
if b.Alive {
livingBots = append(livingBots, b)
}
}
if len(livingBots) > 0 {
var sumRow, sumCol int
for _, b := range livingBots {
sumRow += b.Position.Row
sumCol += b.Position.Col
}
gs.ZoneCenter = Position{
Row: sumRow / len(livingBots),
Col: sumCol / len(livingBots),
}
}
}
// Zone center is fixed at map center (set in NewGameState)
// This forces bots toward the center as the zone shrinks, ensuring contact.
// Check if zone should shrink (skip the turn zone starts)
if gs.ZoneActive && !zoneJustStarted && (gs.Turn-gs.Config.ZoneStartTurn)%gs.Config.ZoneShrinkInterval == 0 {
@ -162,6 +139,10 @@ func (gs *GameState) executeZone() {
gs.ZoneRadius = gs.Config.ZoneMinRadius
}
}
// Ensure zone radius is at least the minimum (handles overshoot from shrink step)
if gs.ZoneRadius < gs.Config.ZoneMinRadius {
gs.ZoneRadius = gs.Config.ZoneMinRadius
}
}
// Kill bots outside the zone (only when zone is active)

View file

@ -240,10 +240,10 @@ func ConfigForPlayers(numPlayers, coresPerPlayer int) Config {
// Zone diameter must be <= 2 * attack radius so bots at opposite zone edges can reach each other
// Target: 65-80% combat density per plan §3.7.1
if numPlayers == 2 {
cfg.ZoneStartTurn = 5 // Start earlier to force combat before bots can spread
cfg.ZoneStartTurn = 10 // Per plan §3.7.1 to force combat before bots can spread
cfg.ZoneShrinkInterval = 1 // Per plan §3.7.1
cfg.ZoneShrinkStep = 6 // Shrink faster to force combat quickly (20->8 in 2 turns)
cfg.ZoneMinRadius = 0 // Force bots to same tile - guaranteed combat
cfg.ZoneShrinkStep = 2 // Per plan §3.7.1: 2 tiles per step forces engagement
cfg.ZoneMinRadius = 2 // Per plan §3.7.1: 2-player min radius
cfg.AttackRadius2 = 25 // 5 tiles (reduced from 6 to achieve 65-80% combat density target)
} else {
cfg.ZoneStartTurn = 10 // Per plan §3.7.1