File size: 3,828 Bytes
1c66cf8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
110
111
112
113
114
"""Tests for features/clusters.py."""
from __future__ import annotations

from werewolftown.features.clusters import (
    achievable_size,
    calc_cluster_gain,
    find_full_count_gaps,
    find_typed_clusters,
)


class TestFindTypedClusters:
    def test_single_cluster(self):
        built = {4: "Happy", 5: "Happy"}
        clusters = find_typed_clusters(built, "Happy")
        assert len(clusters) == 1
        assert clusters[0] == [4, 5]

    def test_multiple_clusters(self):
        built = {4: "Happy", 5: "Happy", 8: "Happy"}
        # 4 adj 5 (same row), 8 adj 4 (vertical) → all connected
        clusters = find_typed_clusters(built, "Happy")
        assert len(clusters) == 1
        assert sorted(clusters[0]) == [4, 5, 8]

    def test_empty_built(self):
        assert find_typed_clusters({}, "Happy") == []

    def test_wrong_type(self):
        built = {4: "Happy", 5: "猫天天"}
        assert find_typed_clusters(built, "Happy") == [[4]]


class TestCalcClusterGain:
    def test_gain_from_extending_cluster(self, make_state):
        state = make_state(
            plots=frozenset({4, 5, 6}),
            built_on={4: "Happy", 5: "Happy"},
            shops=("Happy",),
        )
        # Building Happy on 6 (adjacent to 5): 3-cluster vs 2-cluster
        # rev(3,4)=50000 - rev(2,4)=30000 = 20000
        gain = calc_cluster_gain(state, 6, "Happy")
        assert gain == 20000

    def test_zero_for_already_built(self, make_state):
        state = make_state(
            plots=frozenset({4, 5}),
            built_on={4: "Happy", 5: "Happy"},
        )
        assert calc_cluster_gain(state, 4, "Happy") == 0

    def test_zero_for_isolated_plot(self, make_state):
        # Plot 7 is not adjacent to 4/5
        state = make_state(
            plots=frozenset({4, 5, 7}),
            built_on={4: "Happy", 5: "Happy"},
        )
        gain = calc_cluster_gain(state, 7, "Happy")
        # 7 is isolated → building creates a new 1-cluster = 10000 revenue
        assert gain == 10000


class TestAchievableSize:
    def test_with_adjacent_empty_and_cards(self, make_state):
        state = make_state(
            plots=frozenset({4, 5, 6}),
            built_on={4: "Happy", 5: "Happy"},
            shops=("Happy", "Happy"),
        )
        # existing=2, adjacent_empties={6}, cards=2 → min(1,2)=1 → total=3
        assert achievable_size(state, "Happy") == 3

    def test_fc5_capped_at_3(self, make_state):
        state = make_state(
            plots=frozenset({4, 5, 6, 1, 2}),
            built_on={4: "淘小宝", 5: "淘小宝"},
            shops=("淘小宝", "淘小宝", "淘小宝"),
        )
        # fc=5 but capped at 3
        assert achievable_size(state, "淘小宝") == 3

    def test_zero_for_no_cards_no_built(self, make_state):
        state = make_state(plots=frozenset({4, 5}))
        assert achievable_size(state, "Happy") == 0


class TestFindFullCountGaps:
    def test_finds_2_cluster_gap(self, make_state):
        state = make_state(
            plots=frozenset({4, 5, 6}),
            built_on={4: "Happy", 5: "Happy"},
            shops=("Happy",),
        )
        gaps = find_full_count_gaps(state)
        assert len(gaps) >= 1
        gap = gaps[0]
        assert gap.shop_type == "Happy"
        assert gap.gap == 2  # fc=4, size=2, gap=2
        assert gap.gain_if_filled > 0

    def test_empty_for_full_cluster(self, make_state):
        state = make_state(
            plots=frozenset({4, 5}),
            built_on={4: "钉三多", 5: "钉三多"},
        )
        # fc=2, 2-cluster = full → no gap
        gaps = find_full_count_gaps(state)
        assert len(gaps) == 0

    def test_empty_for_no_built(self, make_state):
        state = make_state(plots=frozenset({4, 5}))
        assert find_full_count_gaps(state) == []