File size: 5,320 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
import os
import sys

# Add project root to path
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "../../../")))

import os

from engine.game.data_loader import CardDataLoader
from engine.game.enums import Phase
from engine.game.game_state import GameState


# Mock DB loader if needed, or use real one
def get_test_db():
    base_path = os.path.dirname(os.path.abspath(__file__))
    project_root = os.path.abspath(os.path.join(base_path, "../../../"))
    cards_path = os.path.join(project_root, "data/cards.json")
    loader = CardDataLoader(cards_path)
    return loader.load()


def test_order_deck_logic():
    m, l, e = get_test_db()

    # Initialize DB for GameState
    GameState.initialize_class_db(m, l)
    GameState.energy_db = e
    GameState._init_jit_arrays()

    gs = GameState()
    p0 = gs.players[0]

    # Find PL!N-bp1-002-P (Nakasuv Kasumi)
    # Trigger: ON_PLAY -> LOOK_AND_CHOOSE_ORDER(3) -> DECK_TOP
    target_card_no = "PL!N-bp1-002-P"
    target_card_id = -1
    for cid, card in m.items():
        if card.card_no == target_card_no:
            target_card_id = int(cid)
            break

    assert target_card_id != -1, f"Card {target_card_no} not found in DB"

    # Isolate card in hand, clear deck to controllable state
    p0.hand = [target_card_id]
    p0.energy_zone = [20000, 20000]  # Enough energy
    # Fix: Ensure tapped_energy is numpy array
    import numpy as np

    p0.tapped_energy = np.zeros(100, dtype=bool)
    p0.tapped_energy[0] = False
    p0.tapped_energy[1] = False

    # Setup Deck: [C, B, A] -> Top is A
    # We want known cards to verify ordering
    # Let's use some dummy IDs if possible or just other members
    deck_cards = [1001, 1002, 1003, 1004, 1005]  # Assumptions
    p0.deck = deck_cards[:]

    # Setup Phase
    gs.phase = Phase.MAIN
    gs.current_player = 0
    gs.turn = 1

    print("\n--- Playing Card ---\n")
    # Play to Center (Slot 1). Action ID: 1 + 0*3 + 1 = 2
    gs.step(2)

    print("DEBUG RULE LOG:", gs.rule_log)

    # 1. Verify we paused for ORDER_DECK
    assert gs.phase == Phase.RESPONSE, f"Expected Response phase, got {gs.phase}"
    assert gs.pending_choice_type == "ORDER_DECK", f"Expected ORDER_DECK choice, got {gs.pending_choice_type}"

    # 2. Verify looked_cards populated
    looked = p0.looked_cards
    print(f"Looked Cards: {looked}")
    assert len(looked) == 3, f"Expected 3 looked cards, got {len(looked)}"
    # Should be the popped cards from deck. Since deck pops from end:
    # Deck was [..., 1003, 1004, 1005]
    # Pop 1: 1005, Pop 2: 1004, Pop 3: 1003
    # Looked should be [1005, 1004, 1003] (or visible order)

    # 3. Check Legal Actions
    # Should offer choices 0, 1, 2 (corresponding to the 3 cards)
    # Action ID range: 550 + area_idx*100 + ab_idx*10 + c
    # area_idx = 1 (Center)
    # ab_idx for OnPlay usually -1 -> mapped to 0 safely in our new logic?
    # Let's check get_legal_actions output mask
    legal_mask = gs.get_legal_actions()
    legal_indices = [i for i, v in enumerate(legal_mask) if v]
    print(f"Legal Actions: {legal_indices}")

    # Calculate Expected IDs
    # area=1, ab=0 (safe_ab), c=0..2
    # 550 + 100 + 0 + 0 = 650
    # 550 + 100 + 0 + 1 = 651
    # 550 + 100 + 0 + 2 = 652
    expected_ids = [650, 651, 652]
    for eid in expected_ids:
        assert eid in legal_indices, f"Expected Action ID {eid} not found in {legal_indices}"

    print("\n--- Selecting First Card to Top ---\n")
    # Choose Index 1 (Card 1004) to put on TOP
    gs.step(651)

    # 4. Verify Card Moved
    # Deck should now have 1004 on top (end of list)
    assert p0.deck[-1] == looked[1], "Chosen card not on top of deck"

    # 5. Verify Loop (Still in Response, fewer cards)
    assert gs.phase == Phase.RESPONSE, "Should still be in Response phase for next card"
    assert len(p0.looked_cards) == 2, "Should have 2 cards left in looked_cards"

    print("\n--- Discarding Rest ---\n")
    # If we want to test "Done"/Discard logic, we need to know what ID triggers that.
    # In my implementation plan, I said "Invalid choice implies discard rest".
    # But get_legal_actions only gives valid choices [0, 1].
    # Wait, the logic handles "Invalid choice" but UI prevents it usually.
    # The logic says: `if choice >= 0 && choice < looked_len: ... else: discard all`
    # So we need to send an action that maps to a choice >= looked_len?
    # Or maybe we rely on the fact that we can just pick all cards one by one.

    # Let's pick another card. Index 0 of REMAINING list.
    # Remaining: [1005, 1003] (Original 0 and 2)
    # We pick 1005 (Current Index 0)
    gs.step(650)  # Same ID 650 is valid for index 0
    assert p0.deck[-1] == looked[0], "Next chosen card not on top"
    assert len(p0.looked_cards) == 1

    # Pick last card
    gs.step(650)
    assert p0.deck[-1] == looked[2], "Last card not on top"
    assert len(p0.looked_cards) == 0

    # 6. Verify Phase Transition
    assert gs.phase == Phase.MAIN, "Should return to Main phase after cards depleted"

    print("Test Passed: O_ORDER_DECK logic verified.")


if __name__ == "__main__":
    test_order_deck_logic()