예제 소스
바둑 on-policy 학습: 대국 로그를 KataGo 라벨로 바꾸기 · 파일 169개
hogu_scan_logs.py
#!/usr/bin/env python3
"""운영 VLM 로그에서 AI 가 둔 수 중 호구 관련 수를 센다.
python scripts/hogu_scan_logs.py [--log ~/Library/Logs/MariGO/run-vlm-serve.log] [--since 2026-09-01] [--show 3]
"""
from __future__ import annotations
import argparse
import re
import sys
from collections import Counter
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
if str(ROOT) not in sys.path:
sys.path.insert(0, str(ROOT))
from vlm_server.shapes import hogu_verdict, tiger_mouth # noqa: E402
N = 19
REQ = re.compile(r"^(\S+ \S+) INFO GO19 request stones B=(\d+) W=(\d+) side=([BW])")
ROW = re.compile(r"^\s*(\d{1,2}) ([.XO ]+)$")
PICK = re.compile(r"INFO 계가선택 \((\d+),(\d+)\).*urgent=([Yn]) side=([BW])")
def show(cells: bytearray, mark: tuple[int, int]) -> str:
lines = []
for r in range(N):
row = []
for c in range(N):
ch = ".XO"[cells[r * N + c]]
row.append("*" if (r, c) == mark else ch)
lines.append(f"{r:2d} " + " ".join(row))
return "\n".join(lines)
def main() -> int:
ap = argparse.ArgumentParser()
ap.add_argument("--log", default=str(Path.home() / "Library/Logs/MariGO/run-vlm-serve.log"))
ap.add_argument("--since", default="")
ap.add_argument("--show", type=int, default=3)
a = ap.parse_args()
stats: Counter = Counter()
examples: dict[str, list[str]] = {"hogu_entry": [], "hogu_fill": [], "hogu_fill_edge": []}
cells: bytearray | None = None
side = 0
ts = ""
rows_read = 0
with open(a.log, encoding="utf-8", errors="replace") as f:
for line in f:
m = REQ.match(line)
if m:
ts = m.group(1)
if a.since and ts < a.since:
cells = None
continue
cells = bytearray(N * N)
side = 1 if m.group(4) == "B" else 2
rows_read = 0
continue
if cells is not None and rows_read < N:
mr = ROW.match(line.rstrip("\n"))
if mr and int(mr.group(1)) == rows_read:
toks = mr.group(2).split()
for c, t in enumerate(toks[:N]):
cells[rows_read * N + c] = {".": 0, "X": 1, "O": 2}[t]
rows_read += 1
continue
mp = PICK.search(line)
if mp and cells is not None and rows_read == N:
r, c = int(mp.group(1)), int(mp.group(2))
if (1 if mp.group(4) == "B" else 2) != side:
continue
stats["moves"] += 1
v = hogu_verdict(cells, r, c, side)
info = tiger_mouth(cells, r, c)
if info is not None:
stats["into_any_hogu_shape"] += 1
if v:
key = v + ("_edge" if v == "hogu_fill" and info and info.walls else "")
stats[key] += 1
stats[f"{key}_urgent_{mp.group(3)}"] += 1
if len(examples.setdefault(key, [])) < a.show:
examples[key].append(f"{ts} side={'BW'[side - 1]} move=({r},{c})\n{show(cells, (r, c))}")
cells = None
print(dict(stats))
n = max(1, stats["moves"])
for k in ("hogu_entry", "hogu_fill", "hogu_fill_edge"):
print(f"{k}: {stats[k]} ({100 * stats[k] / n:.2f}% of AI moves)")
for k, ex in examples.items():
for e in ex:
print(f"\n--- {k}\n{e}")
return 0
if __name__ == "__main__":
raise SystemExit(main())