magicciv/tools/_dbg_contact.py
2026-06-03 03:50:10 -07:00

81 lines
2.7 KiB
Python

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()