diff --git a/tools/_dbg_contact.py b/tools/_dbg_contact.py new file mode 100644 index 00000000..f0405518 --- /dev/null +++ b/tools/_dbg_contact.py @@ -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()