File size: 4,352 Bytes
6bbf552
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
import pytest
from random import Random

from draft import backbone_deck, draft_anchor_indexes, draft_deck, draft_deck_from_packs, draft_order, validated_pack_choice


class DraftClient:
    # Initialize call tracking for draft generation.
    def __init__(self) -> None:
        self.calls = 0
        self.deck_sizes: list[int] = []

    # Return one legal earth card and record deck-aware call order.
    def create_card(self, payload: dict[str, object]) -> dict[str, object]:
        self.calls += 1
        self.deck_sizes.append(len(payload["current_deck"]))  # type: ignore[arg-type]
        return {"name": f"Ward {self.calls}", "effects": [{"primitive_id": "ward"}]}


class DraftPackClient:
    # Initialize call tracking for pack generation.
    def __init__(self) -> None:
        self.calls = 0
        self.deck_sizes: list[int] = []
        self.anchor_sizes: list[int] = []

    # Return one legal earth pack and record deck-aware call order.
    def create_pack(self, payload: dict[str, object]) -> dict[str, object]:
        self.calls += 1
        self.deck_sizes.append(len(payload["current_deck"]))  # type: ignore[arg-type]
        self.anchor_sizes.append(len(payload["draft_anchors"]))  # type: ignore[arg-type]
        return {
            "cards": [
                {"name": f"Ward {self.calls}A", "effects": [{"primitive_id": "ward"}]},
                {"name": f"Ward {self.calls}B", "effects": [{"primitive_id": "block"}]},
                {"name": f"Ward {self.calls}C", "effects": [{"primitive_id": "conditional"}]},
            ]
        }


# Verify backbone decks are six fixed text cards.
def test_backbone_deck_has_standard_cards() -> None:
    deck = backbone_deck("ice", "cyberpunk")
    assert len(deck) == 6
    assert deck[0].name == "Attack (weak)"
    assert deck[0].school == "ice"
    assert deck[5].rules_text() == "Draw 1 card."


# Verify synergy drafting makes nine deck-aware model calls.
def test_draft_deck_adds_nine_synergy_cards() -> None:
    client = DraftClient()
    deck = draft_deck(client, "earth", "dark fantasy", (1, 2, 3, 4, 5, 1, 2, 3, 4))
    assert len(deck) == 15
    assert client.deck_sizes == [6, 7, 8, 9, 10, 11, 12, 13, 14]
    assert deck[-1].name == "Ward 9"


# Verify pack drafting adds the selected candidate from each pack.
def test_draft_deck_from_packs_adds_selected_cards() -> None:
    client = DraftPackClient()
    choices: list[int] = []

    # Always choose the second card in the pack.
    def choose_index(current_deck: tuple[object, ...], pack: tuple[object, ...]) -> int:
        assert len(pack) == 3
        choices.append(len(current_deck))
        return 1

    deck = draft_deck_from_packs(client, "earth", "dark fantasy", (1, 2, 3, 4, 5, 1, 2, 3, 4), choose_index, rng=Random(0))
    assert len(deck) == 15
    assert client.deck_sizes == [6, 7, 8, 9, 10, 11, 12, 13, 14]
    assert client.anchor_sizes[:2] == [0, 1]
    assert client.anchor_sizes[2:] == [2, 2, 2, 2, 2, 2, 2]
    assert choices == [6, 7, 8, 9, 10, 11, 12, 13, 14]
    assert deck[-1].name == "Ward 9B"


# Verify anchor indexes are two random synergy positions.
def test_draft_anchor_indexes() -> None:
    anchors = draft_anchor_indexes(9, Random(0))
    assert len(anchors) == 2
    assert anchors <= set(range(9))
    with pytest.raises(ValueError, match="at least two"):
        draft_anchor_indexes(1, Random(0))


# Verify draft order drafts anchors before remaining cards.
def test_draft_order_starts_with_anchors() -> None:
    assert draft_order(5, frozenset((3, 1))) == (1, 3, 0, 2, 4)


# Verify draft rejects incomplete synergy cost schedules.
def test_draft_deck_requires_nine_costs() -> None:
    with pytest.raises(ValueError, match="exactly nine"):
        draft_deck(DraftClient(), "earth", "dark fantasy", (1,))
    with pytest.raises(ValueError, match="exactly nine"):
        draft_deck_from_packs(DraftPackClient(), "earth", "dark fantasy", (1,), lambda _, __: 0)


# Verify draft pack choices must point into the pack.
def test_validated_pack_choice_rejects_bad_index() -> None:
    pack = backbone_deck("earth", "dark fantasy")[:3]
    assert validated_pack_choice(2, pack) == 2
    with pytest.raises(ValueError, match="outside"):
        validated_pack_choice(3, pack)
    with pytest.raises(ValueError, match="outside"):
        validated_pack_choice(-1, pack)