Files
SirRoboGarage/common_libs/tests/run_melee_strong_field.sh
T

98 lines
3.4 KiB
Bash
Executable File

#!/usr/bin/env bash
# run_melee_strong_field.sh — drive the STRONG-FIELD melee A/B
# (see common_libs/tests/measure_melee_strong_field.nim).
#
# Builds ONE frozen ModularBot (from `git archive HEAD`), then runs one process
# per arm in parallel; each process owns its own Tank Royale server on an
# ephemeral port. Output: <outdir>/<arm>/run<N>.json (+ .bot.stdout.log).
#
# common_libs/tests/run_melee_strong_field.sh [outdir]
#
# Env:
# MELEE_RUNS (default 12)
# MELEE_ROUNDS (default 5)
# MELEE_ARMS (default "pattern bb_ret bb_decay")
# MELEE_FIELD (default "/tmp/tr_bots/Diamond,/tmp/tr_bots/Dookious,/tmp/tr_bots/GresSuffurd")
# WAIT_ARENA minutes to wait for foreign battles (default 45)
#
# ARENA SERIALIZATION: refuses to start (or waits) while another job's battles
# are running; never pkills a foreign process. Kills only its own process groups
# on EXIT/INT/TERM.
set -euo pipefail
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO="$(cd "$HERE/../.." && pwd)"
OUTDIR="${1:-/tmp/melee_strong_field}"
RUNS="${MELEE_RUNS:-12}"
ROUNDS="${MELEE_ROUNDS:-5}"
ARMS_STR="${MELEE_ARMS:-pattern bb_ret bb_decay}"
WAIT_ARENA="${WAIT_ARENA:-45}"
export MELEE_FIELD="${MELEE_FIELD:-/tmp/tr_bots/Diamond,/tmp/tr_bots/Dookious,/tmp/tr_bots/GresSuffurd}"
BIN="$HERE/measure_melee_strong_field"
[[ -x "$BIN" ]] || { echo "ERROR: build the runner first: nim c --nimcache:/tmp/nc_j124 --path:common_libs $HERE/measure_melee_strong_field.nim" >&2; exit 1; }
# ── arena serialization (bracketed patterns: pgrep must not match itself) ────
FOREIGN='[r]un_bridge_battle.sh|[r]obocode_shim.TrBattleCapture|[r]obocode_shim.LegacyBotBridge|[M]odularBot_bin|[m]easure_melee'
foreign() { pgrep -af "$FOREIGN" 2>/dev/null | grep -v "$OUTDIR" || true; }
if [[ -n "$(foreign)" ]]; then
if (( WAIT_ARENA <= 0 )); then
echo "[driver] ERROR: arena busy with another job's battles:" >&2
foreign | sed 's/^/ /' >&2
exit 3
fi
echo "[driver] arena busy — waiting up to ${WAIT_ARENA} min:"
foreign | sed 's/^/ /'
deadline=$(( $(date +%s) + WAIT_ARENA * 60 ))
while :; do
sleep 60
if [[ -z "$(foreign)" ]]; then echo "[driver] arena free."; break; fi
if (( $(date +%s) >= deadline )); then
echo "[driver] ERROR: arena still busy after ${WAIT_ARENA} min; NOT starting." >&2
exit 3
fi
echo "[driver] still busy at $(date +%H:%M:%S)"
done
fi
mkdir -p "$OUTDIR"
echo "[driver] building frozen ModularBot…"
"$BIN" --outdir "$OUTDIR" --build-only
read -r -a ARMS <<< "$ARMS_STR"
PIDS=()
cleanup() {
local rc=$?
trap - EXIT INT TERM
for p in "${PIDS[@]:-}"; do
[[ -n "$p" ]] || continue
kill -TERM -- "-$p" 2>/dev/null || true
done
sleep 1
for p in "${PIDS[@]:-}"; do
[[ -n "$p" ]] || continue
kill -KILL -- "-$p" 2>/dev/null || true
done
pkill -f "[m]easure_melee_strong_field.*$OUTDIR" 2>/dev/null || true
exit "$rc"
}
trap cleanup EXIT INT TERM
for arm in "${ARMS[@]}"; do
echo "[driver] launching arm $arm (runs=$RUNS rounds=$ROUNDS) field=$MELEE_FIELD"
setsid "$BIN" --outdir "$OUTDIR" --arm "$arm" \
--run-start 1 --run-count "$RUNS" --rounds "$ROUNDS" \
> "$OUTDIR/$arm.driver.log" 2>&1 &
PIDS+=("$!")
sleep 3 # stagger so concurrent servers do not race for the same free port
done
echo "[driver] all arms launched; waiting…"
FAIL=0
for p in "${PIDS[@]}"; do
wait "$p" || FAIL=$((FAIL + 1))
done
PIDS=()
echo "[driver] done (failed arm processes: $FAIL)"
exit "$FAIL"