게시판SGF 기보로 학습하는 바둑 LLM 인공지능예제 소스

예제 소스

SGF 기보로 학습하는 바둑 LLM 인공지능 · 파일 169개

test_cross_lessons.py

from __future__ import annotations

import json
import sys
import tempfile
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))

from scripts.monitor_mariago_web_play import (  # noqa: E402
    BLACK,
    MAX_GAME_PLIES,
    WHITE,
    _heuristic_score,
    empty_board,
    heuristic_move,
    idx,
)
from vlm_server.cross_lessons import (  # noqa: E402
    absorb_game,
    empty_book,
    heuristic_shape_delta,
    lesson_bonus_heuristic,
    lesson_bonus_r5,
    r5_live_delta,
)


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 CrossLessonTest(unittest.TestCase):
    def test_game_length_is_capped_at_200(self):
        self.assertEqual(MAX_GAME_PLIES, 200)

    def test_hogu_entry_is_penalized_on_the_heuristic(self):
        board = board_with(white=[(3, 4), (4, 3), (4, 5)])
        inside = _heuristic_score(board, 4, 4, BLACK, None)
        outside = _heuristic_score(board, 10, 10, BLACK, None)
        self.assertIsNotNone(inside)
        self.assertIsNotNone(outside)
        self.assertLess(inside, outside)
        self.assertLess(r5_live_delta(board, 4, 4, BLACK), 0)

    def test_winner_moves_teach_the_other_side(self):
        book = empty_book()
        moves = [
            "1. B Q16 (3,15)",
            "2. W D4 (15,3)",
            "3. B D16 (3,3)",
            "4. W Q4 (15,15)",
            "5. B C15 (4,2)",
            "6. W C3 (16,2)",
        ]
        # 백이 흑 한 점을 따내는 국면을 직접 넣는다.
        board = board_with(black=[(3, 3)], white=[(2, 3), (3, 2), (4, 3)])
        capture = _heuristic_score(board, 3, 4, WHITE, None)
        self.assertIsNotNone(capture)
        absorb_game(
            book,
            [
                "1. B D16 (3,3)",
                "2. W C16 (3,2)",
                "3. B C15 (4,2)",
                "4. W E16 (3,4)",
                "5. B C17 (2,2)",
                "6. W D17 (2,3)",
                "7. B PASS",
                "8. W D15 (4,3)",
            ],
            "white",
            "unit:capture",
        )
        self.assertGreater(book["to_heuristic"]["capture"], 0)
        self.assertGreater(
            lesson_bonus_heuristic(board, 3, 4, WHITE, book),
            0,
        )
        self.assertEqual(lesson_bonus_r5(board, 10, 10, BLACK, book), 0.0)
        self.assertFalse(
            absorb_game(book, moves, "black", "unit:capture"),
        )

    def test_heuristic_shape_reaches_r5_after_four_stones(self):
        board = board_with(
            black=[(3, 3), (3, 9), (3, 15), (15, 3)],
        )
        linked = heuristic_shape_delta(board, 3, 6, BLACK)
        isolated = heuristic_shape_delta(board, 9, 9, BLACK)
        self.assertGreater(linked, isolated)

    def test_lesson_file_roundtrip_does_not_change_capture_priority(self):
        board = board_with(
            black=[(2, 3), (3, 2), (4, 3)],
            white=[(3, 3)],
        )
        with tempfile.TemporaryDirectory() as tmp:
            path = Path(tmp) / "games.jsonl"
            path.write_text(
                json.dumps(
                    {
                        "game_id": 1,
                        "score": {"winner": "black"},
                        "moves": ["1. B D16 (3,3)", "2. W Q16 (3,15)"],
                    }
                )
                + "\n",
                encoding="utf-8",
            )
            from vlm_server.cross_lessons import ingest_jsonl

            book = ingest_jsonl(path, empty_book(), source="tmp")
            self.assertIn("tmp:1", book["seen_games"])
        self.assertEqual(
            heuristic_move(board, BLACK, None, __import__("random").Random(1))[:2],
            (3, 4),
        )


if __name__ == "__main__":
    unittest.main()