feat(dbg-contact): ✨ Introduce debug utility for analyzing baseline run artifacts in tools/_dbg_contact.py
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
parent
ecd29a8eca
commit
49a64a899a
1 changed files with 81 additions and 0 deletions
81
tools/_dbg_contact.py
Normal file
81
tools/_dbg_contact.py
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
import sys, json
|
||||
sys.path.insert(0, '.')
|
||||
from tooling.rl_self_play.harness_client import HarnessClient, HarnessConfig
|
||||
from tooling.rl_self_play.encoders import encode_legal_actions
|
||||
from tooling.rl_self_play.record_expert import _DropStats, _resolve
|
||||
|
||||
|
||||
def adv(c, slot):
|
||||
for a in c.suggest(slot=slot):
|
||||
v = c.view(slot=slot)
|
||||
_, i2a = encode_legal_actions(v)
|
||||
idx = _resolve(a, v, i2a, _DropStats())
|
||||
if idx is None:
|
||||
continue
|
||||
r = i2a[idx]
|
||||
try:
|
||||
if r.get('type') == 'end_turn':
|
||||
c.end_turn(slot=slot)
|
||||
else:
|
||||
c.act(r, slot=slot)
|
||||
except Exception:
|
||||
break
|
||||
try:
|
||||
c.end_turn(slot=slot)
|
||||
except Exception:
|
||||
pass
|
||||
c.drain_notifications()
|
||||
|
||||
|
||||
def ents(v, slot, key):
|
||||
return [x for x in v.get(key, []) if int(x.get('owner', -1)) == slot]
|
||||
|
||||
|
||||
def pos(x):
|
||||
p = x.get('position', [-99, -99])
|
||||
return (float(p[0]), float(p[1]))
|
||||
|
||||
|
||||
def wrapdist(a, b, w=40, h=24):
|
||||
dx = abs(a[0] - b[0]); dx = min(dx, w - dx)
|
||||
dy = abs(a[1] - b[1]); dy = min(dy, h - dy)
|
||||
return (dx * dx + dy * dy) ** 0.5
|
||||
|
||||
|
||||
def min_interplayer_dist(v):
|
||||
p0 = [pos(x) for x in ents(v, 0, 'units')] + [pos(x) for x in ents(v, 0, 'cities')]
|
||||
p1 = [pos(x) for x in ents(v, 1, 'units')] + [pos(x) for x in ents(v, 1, 'cities')]
|
||||
if not p0 or not p1:
|
||||
return -1
|
||||
return min(wrapdist(a, b) for a in p0 for b in p1)
|
||||
|
||||
|
||||
for seed in (1, 6):
|
||||
c = HarnessClient(HarnessConfig(seed=seed, players=2, player_slots=(0, 1),
|
||||
map_size='duel', map_type='pangaea',
|
||||
victory_mode='domination', timeout_sec=110))
|
||||
v = c.view(1)
|
||||
cap0 = [pos(x) for x in ents(v, 0, 'cities')]
|
||||
cap1 = [pos(x) for x in ents(v, 1, 'cities')]
|
||||
print('seed%d t0: P0cap=%s P1cap=%s capdist=%.1f' % (
|
||||
seed, cap0, cap1, wrapdist(cap0[0], cap1[0]) if cap0 and cap1 else -1))
|
||||
prev0 = prev1 = 0
|
||||
combat_seen = False
|
||||
mindist_ever = 999
|
||||
for rnd in range(58):
|
||||
v = c.view(1)
|
||||
n0 = len(ents(v, 0, 'units')); n1 = len(ents(v, 1, 'units'))
|
||||
# mil drop relative to prior peak observed = combat loss signal
|
||||
if rnd > 0 and (n0 < prev0 or n1 < prev1):
|
||||
combat_seen = True
|
||||
prev0, prev1 = max(prev0, n0), max(prev1, n1)
|
||||
d = min_interplayer_dist(v)
|
||||
if d >= 0:
|
||||
mindist_ever = min(mindist_ever, d)
|
||||
if rnd % 15 == 0:
|
||||
print(' t%d: P0u=%d P1u=%d mindist=%.1f' % (
|
||||
int(v.get('turn', 0)), n0, n1, d))
|
||||
adv(c, 0); adv(c, 1)
|
||||
print(' seed%d SUMMARY: combat_seen(mil_drop)=%s min_interplayer_dist_ever=%.1f' % (
|
||||
seed, combat_seen, mindist_ever))
|
||||
c.shutdown()
|
||||
Loading…
Add table
Reference in a new issue