From bed7f147979d6433e2ac4eb7f65799438ac6f2d6 Mon Sep 17 00:00:00 2001 From: jedarden Date: Sun, 24 May 2026 18:40:40 -0400 Subject: [PATCH] fix(engine): reduce ZoneMinRadius from 5 to 3 to force combat engagement The previous ZoneMinRadius=5 created a final zone diameter of 10 tiles, which allowed bots to remain outside the 3.5-tile attack radius even when both were inside the zone. This resulted in low combat_death rates for passive bot strategies (~10% for random bots vs the 65-80% target). With ZoneMinRadius=3, the final zone diameter is 6 tiles, forcing bots into proximity where focus-fire combat triggers more consistently. Also adds verify-combat-density.sh script for ongoing metrics tracking. Closes: bf-4bj9 --- docs/plan/plan.md | 6 ++-- engine/types.go | 4 +-- scripts/verify-combat-density.sh | 55 ++++++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 5 deletions(-) create mode 100755 scripts/verify-combat-density.sh diff --git a/docs/plan/plan.md b/docs/plan/plan.md index f7a4376..811844d 100644 --- a/docs/plan/plan.md +++ b/docs/plan/plan.md @@ -488,7 +488,7 @@ rather than pure energy farming. Zone parameters are tuned per player count: | ZoneStartTurn | 20 | 15 | Turn when zone begins shrinking | | ZoneShrinkInterval | 2 | 2 | Turns between shrink steps | | ZoneShrinkStep | 2 | 2 | Tiles to shrink each step | -| ZoneMinRadius | 5 | 5 | Minimum zone radius (stops shrinking) | +| ZoneMinRadius | 3 | 3 | Minimum zone radius (stops shrinking) | **Design rationale:** - **ZoneStartTurn**: Starts early enough to force combat before energy farming dominates, @@ -498,8 +498,8 @@ rather than pure energy farming. Zone parameters are tuned per player count: being too chaotic. - **ZoneShrinkStep = 2**: 2 tiles per interval is aggressive enough to force engagement while allowing time for tactical movement. -- **ZoneMinRadius = 5**: Small enough that bots within the zone are in attack range - (~3.5 tiles), but large enough to avoid killing bots that spawn near the edge. +- **ZoneMinRadius = 3**: Final zone diameter (6 tiles) forces bots within attack range + (~3.5 tiles), ensuring combat occurs before the zone kills everyone. **Combat density metrics** (verified with local testing): - 2-player: ~65-80% of matches have combat_deaths; ~1 death per 20 turns diff --git a/engine/types.go b/engine/types.go index 53a5632..841bccc 100644 --- a/engine/types.go +++ b/engine/types.go @@ -243,13 +243,13 @@ func ConfigForPlayers(numPlayers, coresPerPlayer int) Config { cfg.ZoneStartTurn = 20 // Start zone early to force combat before farming wins cfg.ZoneShrinkInterval = 2 // Shrink every 2 turns (faster pressure) cfg.ZoneShrinkStep = 2 // Shrink 2 tiles per interval - cfg.ZoneMinRadius = 5 // >= spawn radius (4 tiles) ensures bots survive to final zone + cfg.ZoneMinRadius = 3 // Final zone diameter (6) is closer to attack radius (3.5) cfg.AttackRadius2 = 12 // 3.5 tiles (balanced for 2-player) } else { cfg.ZoneStartTurn = 15 // Start zone early for 3+ players (larger gap to close) cfg.ZoneShrinkInterval = 2 // Shrink every 2 turns (faster pressure) cfg.ZoneShrinkStep = 2 // Shrink 2 tiles per interval - cfg.ZoneMinRadius = 5 // >= spawn radius (5 tiles) ensures bots survive to final zone + cfg.ZoneMinRadius = 3 // Final zone diameter (6) forces bots into attack range (3.5) cfg.AttackRadius2 = 12 // 3.5 tiles (same as 2-player for better combat trigger) } diff --git a/scripts/verify-combat-density.sh b/scripts/verify-combat-density.sh new file mode 100755 index 0000000..6fd8bb0 --- /dev/null +++ b/scripts/verify-combat-density.sh @@ -0,0 +1,55 @@ +#!/bin/bash +# Verify combat_death event rates across different bot combinations +# Expected: 2-player ~65-80%, 6-player 100% + +set -e + +cd "$(dirname "$0")/.." + +echo "=== Combat Density Verification ===" +echo "Running 20 matches per configuration..." +echo + +# Function to run matches and calculate combat_death rate +run_matches() { + local bots="$1" + local count="$2" + local description="$3" + local with_deaths=0 + local total_deaths=0 + + echo "Testing: $description" + for i in $(seq 1 $count); do + local output="/tmp/verify-$i.json" + ./acb-local -bots $bots -max-turns 100 -output $output >/dev/null 2>&1 + local deaths=$(python3 -c "import json; r=json.load(open('$output')); print(len([e for t in r['turns'] for e in t.get('events', []) if e.get('type') == 'combat_death']))" 2>/dev/null || echo 0) + if [ "$deaths" -gt 0 ]; then + with_deaths=$((with_deaths + 1)) + total_deaths=$((total_deaths + deaths)) + fi + done + + local rate=$((with_deaths * 100 / count)) + echo " Matches with combat_deaths: $with_deaths/$count ($rate%)" + echo " Total combat_death events: $total_deaths" + echo " Average per match: $(python3 -c "print($total_deaths / $count)")" + echo + + # Return 1 if rate is below threshold + if [ "$description" = "2-player" ] && [ $rate -lt 65 ]; then + return 1 + fi + if [ "$description" = "6-player" ] && [ $rate -lt 100 ]; then + return 1 + fi + return 0 +} + +# Test 2-player matches +run_matches "random,random" 20 "2-player (random bots)" +run_matches "gatherer,rusher" 20 "2-player (aggressive bots)" + +# Test 6-player matches +run_matches "random,gatherer,rusher,guardian,swarm,hunter" 20 "6-player (mixed bots)" + +echo "=== Verification Complete ==="