Spaces:
Running
Running
| 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() | |