게시판바둑 on-policy 학습: 대국 로그를 KataGo 라벨로 바꾸기예제 소스

예제 소스

바둑 on-policy 학습: 대국 로그를 KataGo 라벨로 바꾸기 · 파일 169개

ladder_selftest.py

#!/usr/bin/env python3
"""축 판독기 자가 점검: python scripts/ladder_selftest.py"""

from __future__ import annotations

import sys
import time
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.ladder import (  # noqa: E402
    attacker_can_capture,
    chase_verdict,
    defender_can_escape,
    futile_escapes,
    ladder_line,
)

N = 19
X, O = 1, 2


def board(black: list[tuple[int, int]], white: list[tuple[int, int]]) -> bytearray:
    b = bytearray(N * N)
    for r, c in black:
        b[r * N + c] = X
    for r, c in white:
        b[r * N + c] = O
    return b


def show(b: bytearray, marks: dict[tuple[int, int], str] | None = None) -> str:
    marks = marks or {}
    rows = []
    for r in range(N):
        row = []
        for c in range(N):
            if (r, c) in marks:
                row.append(marks[(r, c)])
            else:
                row.append(".XO"[b[r * N + c]])
        rows.append(f"{r:02d} " + " ".join(row))
    return "\n".join(rows)


# 백(5,5) 단수, 활로 (5,6) — 우하 방향 축
BASE_B = [(4, 5), (5, 4), (6, 5), (4, 6)]
BASE_W = [(5, 5)]

CASES: list[tuple[str, list, list, bool]] = [
    ("기본 축(막힘 없음) → 잡힘", BASE_B, BASE_W, False),
    ("축머리(백 돌이 진행 방향) → 탈출", BASE_B, BASE_W + [(12, 13)], True),
    ("진행 방향에 흑 돌 → 여전히 잡힘", BASE_B + [(12, 13)], BASE_W, False),
    ("몰던 흑 돌이 단수에 걸림(백 포위) → 탈출", BASE_B, BASE_W + [(3, 6), (4, 7)], True),
]


def main() -> int:
    fails = 0
    for name, bl, wh, want in CASES:
        b = board(bl, wh)
        t0 = time.perf_counter()
        got = defender_can_escape(b, 5, 5)
        ms = (time.perf_counter() - t0) * 1000
        ok = got == want
        fails += 0 if ok else 1
        print(f"[{'OK' if ok else 'FAIL'}] {name}: escape={got} (기대 {want}) {ms:.1f}ms")
        if not ok or "-v" in sys.argv:
            line = ladder_line(b, 5, 5)
            marks = {p: ("o" if w == O else "x") for w, p in line}
            print(show(b, marks))

    b = board(BASE_B, BASE_W)
    fe = futile_escapes(b, O)
    ok = [v.point for v in fe] == [(5, 6)]
    fails += 0 if ok else 1
    print(f"[{'OK' if ok else 'FAIL'}] 백 차례 헛도망 점: {[v.point for v in fe]} (기대 [(5, 6)])")

    b2 = board(BASE_B, BASE_W + [(12, 13)])
    fe2 = futile_escapes(b2, O)
    ok = fe2 == []
    fails += 0 if ok else 1
    print(f"[{'OK' if ok else 'FAIL'}] 축머리 있으면 헛도망 아님: {[v.point for v in fe2]}")

    # 흑이 먼저 단수를 치는 쪽: 백(5,5) 활로 (5,6),(6,5)
    bl = [(4, 5), (5, 4), (4, 6)]
    cap = attacker_can_capture(board(bl, BASE_W), 5, 5)
    fails += 0 if cap is True else 1
    print(f"[{'OK' if cap is True else 'FAIL'}] 흑 선수 축 성립: {cap}")
    v = chase_verdict(board(bl, BASE_W), 6, 5, X)
    ok = v is not None and v.kind == "working_chase"
    fails += 0 if ok else 1
    print(f"[{'OK' if ok else 'FAIL'}] 흑 (6,5) 단수 = {v.kind if v else None} (기대 working_chase)")
    v2 = chase_verdict(board(bl, BASE_W + [(12, 13)]), 6, 5, X)
    ok = v2 is not None and v2.kind == "broken_chase"
    fails += 0 if ok else 1
    print(f"[{'OK' if ok else 'FAIL'}] 축머리 있을 때 흑 (6,5) 단수 = {v2.kind if v2 else None} (기대 broken_chase)")

    print("PASS" if fails == 0 else f"FAIL {fails}")
    return 1 if fails else 0


if __name__ == "__main__":
    raise SystemExit(main())