File size: 7,431 Bytes
bb3fbf9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
import numpy as np
import pytest

from engine.game.game_state import GameState, LiveCard, MemberCard


class TestPerformanceWildcard:
    @pytest.fixture(autouse=True)
    def setup(self):
        self.game = GameState()
        # Ensure clean DBs
        GameState.member_db = {}
        GameState.live_db = {}
        self.p0 = self.game.players[0]

    def test_check_hearts_exact_match(self):
        """Test specific colors match requirements exactly."""
        # Need: 1 Pink (0), 1 Blue (4)
        need = np.array([1, 0, 0, 0, 1, 0, 0], dtype=np.int32)
        # Have: 1 Pink, 1 Blue
        have = np.array([1, 0, 0, 0, 1, 0, 0], dtype=np.int32)

        assert self.game._check_hearts_meet_requirement(have, need)

    def test_check_hearts_insufficient_specific(self):
        """Test failure when specific colors are missing."""
        need = np.array([1, 0, 0, 0, 0, 0, 0], dtype=np.int32)
        have = np.array([0, 0, 0, 0, 0, 0, 0], dtype=np.int32)
        assert not self.game._check_hearts_meet_requirement(have, need)

    def test_check_hearts_wildcard_for_specific(self):
        """Test Wildcard (index 6) filling specific color deficit."""
        # Need: 2 Pink
        need = np.array([2, 0, 0, 0, 0, 0, 0], dtype=np.int32)
        # Have: 0 Pink, 2 Wildcards
        have = np.array([0, 0, 0, 0, 0, 0, 2], dtype=np.int32)

        assert self.game._check_hearts_meet_requirement(have, need)

    def test_check_hearts_wildcard_partial_specific(self):
        """Test Wildcard filling partial specific deficit."""
        # Need: 3 Pink
        need = np.array([3, 0, 0, 0, 0, 0, 0], dtype=np.int32)
        # Have: 1 Pink, 2 Wildcards
        have = np.array([1, 0, 0, 0, 0, 0, 2], dtype=np.int32)

        assert self.game._check_hearts_meet_requirement(have, need)

    def test_check_hearts_any_requirement_surplus(self):
        """Test Surplus specific colors filling 'Any' requirement."""
        # Need: 1 Any (index 6)
        need = np.array([0, 0, 0, 0, 0, 0, 1], dtype=np.int32)
        # Have: 1 Pink (Surplus since 0 Pink needed)
        have = np.array([1, 0, 0, 0, 0, 0, 0], dtype=np.int32)

        assert self.game._check_hearts_meet_requirement(have, need)

    def test_check_hearts_any_requirement_wildcard(self):
        """Test Wildcard filling 'Any' requirement."""
        # Need: 1 Any
        need = np.array([0, 0, 0, 0, 0, 0, 1], dtype=np.int32)
        # Have: 1 Wildcard
        have = np.array([0, 0, 0, 0, 0, 0, 1], dtype=np.int32)

        assert self.game._check_hearts_meet_requirement(have, need)

    def test_check_hearts_complex_mix(self):
        """Test simultaneous use of Wildcards for specific deficits and 'Any' requirements."""
        # Need: 2 Pink, 1 Any
        need = np.array([2, 0, 0, 0, 0, 0, 1], dtype=np.int32)

        # Scenario A: 1 Pink, 2 Wildcards
        # 1 Wildcard checks Pink deficit (1), Remaining 1 Wildcard checks Any (1) -> Pass
        have_a = np.array([1, 0, 0, 0, 0, 0, 2], dtype=np.int32)
        assert self.game._check_hearts_meet_requirement(have_a, need)

        # Scenario B: 3 Pink, 0 Wildcards
        # 2 Pink satisfy specific, 1 Pink surplus satisfies Any -> Pass
        have_b = np.array([3, 0, 0, 0, 0, 0, 0], dtype=np.int32)
        assert self.game._check_hearts_meet_requirement(have_b, need)

        # Scenario C: 1 Pink, 1 Wildcard
        # 1 Pink used. Deficit 1 Pink. 1 Wildcard used. Deficit 0.
        # Any need 1. Remaining surplus/wildcard 0. -> Fail
        have_c = np.array([1, 0, 0, 0, 0, 0, 1], dtype=np.int32)
        assert not self.game._check_hearts_meet_requirement(have_c, need)

    def test_consume_hearts_logic(self):
        """Test that _consume_hearts correctly updates the 'have' array in-place."""
        # Need: 1 Pink, 1 Any
        need = np.array([1, 0, 0, 0, 0, 0, 1], dtype=np.int32)

        # Have: 3 Pink
        have = np.array([3, 0, 0, 0, 0, 0, 0], dtype=np.int32)

        # Check first
        assert self.game._check_hearts_meet_requirement(have, need)

        # Consume
        self.game._consume_hearts(have, need)

        # Expect: 1 Pink consumed for specific, 1 Pink consumed for Any. Total 2 Pink consumed.
        # Remaining: 1 Pink
        expected = np.array([1, 0, 0, 0, 0, 0, 0], dtype=np.int32)
        np.testing.assert_array_equal(have, expected)

    def test_consume_hearts_wildcard_preference(self):
        """

        Verify consumption order:

        1. Specific Need -> Specific Color

        2. Specific Need -> Wildcard (if specific missing)

        3. Any Need -> Surplus Specific

        4. Any Need -> Wildcard

        """
        # Need: 1 Pink, 1 Any
        need = np.array([1, 0, 0, 0, 0, 0, 1], dtype=np.int32)

        # Have: 0 Pink, 1 Blue (Surplus), 2 Wildcards
        # 1 Wildcard needed for Pink.
        # For Any: Surplus Blue available? Yes. Should use Blue or Wildcard?
        # Logic says: "First consume surplus specific colors" then "consume Wildcards"
        have = np.array([0, 0, 0, 0, 1, 0, 2], dtype=np.int32)

        self.game._consume_hearts(have, need)

        # Expect:
        # Pink deficit covered by 1 Wildcard. (Wildcards: 2->1)
        # Any covered by 1 Blue (Surplus). (Blue: 1->0)
        # Remaining: 1 Wildcard
        expected = np.array([0, 0, 0, 0, 0, 0, 1], dtype=np.int32)
        np.testing.assert_array_equal(have, expected)

    def test_real_data_flow(self):
        """

        Integration test using real mock objects to simulate a full performance check.

        Using a Member Card providing hearts and a Live Card with requirements.

        """
        # Create a Mock Member: "Honoka" (Pink)
        # Provides 1 Pink Heart
        member = MemberCard(
            card_id=101,
            card_no="test",
            name="Honoka",
            cost=1,
            hearts=np.array([1, 0, 0, 0, 0, 0, 0], dtype=np.int32),  # 1 Pink
            blade_hearts=np.array([0, 0, 0, 0, 0, 0, 0], dtype=np.int32),
            blades=1,
        )
        GameState.member_db[101] = member

        # Create a Mock Live: "Snow Halation"
        # Require: 1 Any heart (using index 6 for test even if real card uses strict colors)
        req = np.zeros(7, dtype=np.int32)
        req[6] = 1  # 1 Any

        live = LiveCard(card_id=201, card_no="test-live", name="Test Live", score=10, required_hearts=req)
        GameState.live_db[201] = live

        # Setup Player
        self.p0.stage[0] = 101  # Place Honoka
        self.p0.live_zone = [201]  # Place Live
        self.p0 = self.game.players[0]

        # We need to simulate the heart gathering part of _do_performance manually
        # or mock the method calls?
        # Actually, let's just reuse the underlying calculation logic which is what we care about.

        # 1. Gather Hearts
        total_hearts = np.zeros(7, dtype=np.int32)
        hraw = self.p0.get_effective_hearts(0, GameState.member_db)  # Should be length 7 now [1,0,0,0,0,0,0]
        total_hearts += hraw

        # 2. Check Requirement
        # Have: [1, 0, ...], Need: [0, ... 1 (Any)]
        success = self.game._check_hearts_meet_requirement(total_hearts, live.required_hearts)

        assert success, "Pink heart should satisfy 'Any' requirement in integration flow"