예제 소스
SGF 기보로 학습하는 바둑 LLM 인공지능 · 파일 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())