fix(engine): zone starts at fixed radius to force combat contact
Plan §3.7.1 zone should force bots into contact range (65-80% combat density target). Previous implementation set initial zone radius to contain all living bots + margin (updateZoneRadiusToContainBots), which defeated the forcing function—bots that spread during first 10 turns started with a large zone that shrank too slowly. New implementation (setInitialZoneRadius): - Zone starts at fixed 55% of distance from center to edge - For 40x40 2-player map: initial radius = 11 tiles (vs old ~20+) - Zone shrinks by 1 tile/turn toward ZoneMinRadius = 2 - Forces bots inward regardless of early-game positioning Combat density verification (gatherer vs rusher, 30 matches each): - 55% initial radius: 24/30 (80%) and 22/30 (73%) with combat_deaths - Within plan target of 65-80% for 2-player matches Closes: bf-1kds Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
c97912a782
commit
c11819c25c
1 changed files with 20 additions and 41 deletions
|
|
@ -123,9 +123,9 @@ func (gs *GameState) executeZone() {
|
|||
if !gs.ZoneActive && gs.Turn >= gs.Config.ZoneStartTurn {
|
||||
gs.ZoneActive = true
|
||||
zoneJustStarted = true
|
||||
// When zone starts, set radius to just contain all living bots
|
||||
// This prevents bots from having time to spread out before zone pressure begins
|
||||
gs.updateZoneRadiusToContainBots()
|
||||
// When zone starts, set radius to a fixed initial size based on map dimensions
|
||||
// This forces bots toward the center regardless of how far they've spread
|
||||
gs.setInitialZoneRadius()
|
||||
}
|
||||
|
||||
// Zone center is fixed at map center (set in NewGameState)
|
||||
|
|
@ -180,47 +180,26 @@ func (gs *GameState) executeZone() {
|
|||
}
|
||||
}
|
||||
|
||||
// updateZoneRadiusToContainBots sets the zone radius to the minimum value needed
|
||||
// to contain all living bots, plus a small margin.
|
||||
func (gs *GameState) updateZoneRadiusToContainBots() {
|
||||
var livingBots []*Bot
|
||||
for _, b := range gs.Bots {
|
||||
if b.Alive {
|
||||
livingBots = append(livingBots, b)
|
||||
}
|
||||
// setInitialZoneRadius sets the zone to a fixed initial radius based on map dimensions.
|
||||
// The zone starts at a radius that forces bots inward immediately, ensuring
|
||||
// contact is forced before energy farming dominates.
|
||||
func (gs *GameState) setInitialZoneRadius() {
|
||||
// Calculate the distance from center to the nearest map edge
|
||||
// For a rectangular grid, this is the minimum of half-rows and half-cols
|
||||
halfRows := gs.Config.Rows / 2
|
||||
halfCols := gs.Config.Cols / 2
|
||||
distToEdge := halfRows
|
||||
if halfCols < distToEdge {
|
||||
distToEdge = halfCols
|
||||
}
|
||||
|
||||
if len(livingBots) == 0 {
|
||||
return
|
||||
}
|
||||
// Set initial zone radius to ~55% of the distance from center to edge
|
||||
// This maximizes combat engagement time while still forcing bots inward
|
||||
gs.ZoneRadius = (distToEdge * 55) / 100
|
||||
|
||||
// Find the maximum distance from zone center to any bot
|
||||
maxDist2 := 0
|
||||
for _, b := range livingBots {
|
||||
dist2 := gs.Grid.Distance2(b.Position, gs.ZoneCenter)
|
||||
if dist2 > maxDist2 {
|
||||
maxDist2 = dist2
|
||||
}
|
||||
}
|
||||
|
||||
// Set zone radius to contain all bots plus margin
|
||||
// Margin gives bots time to reach each other before zone kills them
|
||||
maxDist := int(sqrt(maxDist2))
|
||||
gs.ZoneRadius = maxDist + 5 // Smaller margin to reach each other before zone kills
|
||||
}
|
||||
|
||||
// sqrt returns the integer square root of n.
|
||||
func sqrt(n int) int {
|
||||
if n <= 0 {
|
||||
return 0
|
||||
}
|
||||
x := n
|
||||
for {
|
||||
y := (x + n/x) / 2
|
||||
if y >= x {
|
||||
return x
|
||||
}
|
||||
x = y
|
||||
// Ensure minimum initial radius of 7 for very small maps
|
||||
if gs.ZoneRadius < 7 {
|
||||
gs.ZoneRadius = 7
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue