예제 소스
바둑 on-policy 학습: 대국 로그를 KataGo 라벨로 바꾸기 · 파일 169개
test_nolimit_recheck.py
from __future__ import annotations
import asyncio
import random
import sys
import unittest
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
if str(ROOT) not in sys.path:
sys.path.insert(0, str(ROOT))
import scripts.monitor_mariago_web_play as mon # noqa: E402
from scripts.monitor_mariago_web_play import ( # noqa: E402
BLACK,
BOARD_SIZE,
EMPTY,
SAFETY_PLIES,
WHITE,
_fills_own_region,
empty_board,
heuristic_move,
idx,
recheck_pass,
resolve_max_moves,
)
from vlm_server.cross_lessons import effective_winner, midgame_pass_counts # noqa: E402
from vlm_server.dataset_passfix import collect, pass_positions # noqa: E402
def board_with(*, black=(), white=()):
board = empty_board()
for r, c in black:
board[idx(r, c)] = BLACK
for r, c in white:
board[idx(r, c)] = WHITE
return board
class NoLimitTest(unittest.TestCase):
def test_zero_means_unlimited_with_safety_cap(self):
self.assertEqual(resolve_max_moves(0), SAFETY_PLIES)
self.assertEqual(resolve_max_moves(-1), SAFETY_PLIES)
self.assertEqual(resolve_max_moves(150), 150)
self.assertEqual(resolve_max_moves(500), 200)
def test_heuristic_does_not_fill_own_corner(self):
wall = [(3, c) for c in range(4)] + [(r, 3) for r in range(3)]
board = board_with(black=wall, white=[(10, 10)])
self.assertTrue(_fills_own_region(board, 1, 1, BLACK, None))
self.assertFalse(_fills_own_region(board, 9, 9, BLACK, None))
def test_heuristic_passes_when_only_own_eyes_remain(self):
board = [BLACK] * (BOARD_SIZE * BOARD_SIZE)
for r in range(1, BOARD_SIZE, 4):
for c in range(1, BOARD_SIZE, 4):
board[idx(r, c)] = EMPTY
_r, _c, is_pass = heuristic_move(board, BLACK, None, random.Random(3))
self.assertTrue(is_pass)
def test_heuristic_still_plays_in_the_opening(self):
_r, _c, is_pass = heuristic_move(empty_board(), BLACK, None, random.Random(3))
self.assertFalse(is_pass)
class PassRecheckTest(unittest.TestCase):
def _run(self, reply: dict):
async def fake(*_args, **_kwargs):
return reply
orig = mon.ws_request_move
mon.ws_request_move = fake
try:
board = board_with(black=[(3, 3)], white=[(15, 15)])
return asyncio.run(
recheck_pass("ws://x", board, None, 1, [], 1.0, ply=10, first_dt=0.5)
)
finally:
mon.ws_request_move = orig
def test_confirmed_pass(self):
flip, rec = self._run({"ok": True, "pass": True})
self.assertIsNone(flip)
self.assertEqual(rec["result"], "pass_confirmed")
self.assertEqual(rec["phase"], "midgame")
def test_flipped_to_legal_move(self):
flip, rec = self._run({"ok": True, "pass": False, "row": 9, "col": 9})
self.assertEqual(flip, (9, 9))
self.assertEqual(rec["result"], "pass_flipped")
def test_flipped_to_illegal_move_counts_as_pass(self):
flip, rec = self._run({"ok": True, "pass": False, "row": 3, "col": 3})
self.assertIsNone(flip)
self.assertEqual(rec["result"], "flipped_illegal")
class ForfeitWeightTest(unittest.TestCase):
MOVES = [
"1. B D16 (3,3)",
"2. W PASS (2.0s)",
"3. B Q16 (3,15)",
"4. W PASS (2.0s)",
"5. B D4 (15,3)",
"6. W PASS (2.0s)",
]
def test_midgame_passes_are_counted(self):
self.assertEqual(midgame_pass_counts(self.MOVES), {"black": 0, "white": 3})
def test_win_over_repeated_passes_gets_no_winner_weight(self):
self.assertIsNone(effective_winner(self.MOVES, "black"))
def test_normal_win_keeps_weight(self):
moves = ["1. B D16 (3,3)", "2. W Q4 (15,15)"]
self.assertEqual(effective_winner(moves, "black"), "black")
self.assertEqual(effective_winner(self.MOVES, "white"), "white")
class PassfixPositionsTest(unittest.TestCase):
def test_replay_yields_board_before_each_white_pass(self):
moves = ForfeitWeightTest.MOVES + ["7. W Q4 (15,15) (1.0s, recheck)"]
got = list(pass_positions(moves))
self.assertEqual([ply for ply, _ in got], [1, 3, 5])
_, last = got[-1]
self.assertEqual(last[3 * BOARD_SIZE + 3], BLACK)
self.assertEqual(last[15 * BOARD_SIZE + 3], BLACK)
self.assertEqual(sum(1 for v in last if v), 3)
def test_collect_dedups_and_filters_endgame(self):
import json
import tempfile
with tempfile.TemporaryDirectory() as td:
games = Path(td) / "games.jsonl"
rec = {"game_id": 1, "moves": ForfeitWeightTest.MOVES}
games.write_text(json.dumps(rec) + "\n" + json.dumps(rec) + "\n", encoding="utf-8")
cases = Path(td) / "pass_cases.jsonl"
full = [BLACK] * (BOARD_SIZE * BOARD_SIZE - 10) + [EMPTY] * 10
cases.write_text(
json.dumps({"game_id": 2, "board": full, "result": "pass_confirmed"}) + "\n",
encoding="utf-8",
)
pos = collect([games], [cases], min_empty=120)
self.assertEqual(len(pos), 3)
self.assertTrue(all(p["empty"] >= 120 for p in pos))
if __name__ == "__main__":
unittest.main()