File size: 4,597 Bytes
463f868
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import os
import sys
import traceback
from typing import Callable

# Ensure parent directory is in path
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))

from game.game_state import GameState, Phase


class StateVerifier:
    """Helper class to verify game state properties."""

    def __init__(self, state: GameState):
        self.state = state

    def assert_phase(self, expected_phase: Phase):
        if self.state.phase != expected_phase:
            raise AssertionError(f"Expected phase {expected_phase}, but got {self.state.phase}")

    def assert_player_turn(self, expected_player: int):
        if self.state.current_player != expected_player:
            raise AssertionError(f"Expected player {expected_player}'s turn, but got {self.state.current_player}")

    def assert_hand_contains(self, player_id: int, card_id: int):
        if card_id not in self.state.players[player_id].hand:
            raise AssertionError(
                f"Player {player_id} hand does not contain card {card_id}. Hand: {self.state.players[player_id].hand}"
            )

    def assert_hand_does_not_contain(self, player_id: int, card_id: int):
        if card_id in self.state.players[player_id].hand:
            raise AssertionError(f"Player {player_id} hand contains card {card_id} but shouldn't.")

    def assert_stage_card(self, player_id: int, position: int, card_id: int):
        actual = self.state.players[player_id].stage[position]
        if actual != card_id:
            raise AssertionError(f"Player {player_id} stage[{position}] expected {card_id}, got {actual}")

    def assert_life_at(self, player_id: int, valid_hp: int):
        # This is a bit complex as HP is derived from live zone, but for now we check length of lives
        lives = len(self.state.players[player_id].live_zone)
        if lives != valid_hp:
            raise AssertionError(f"Player {player_id} expected {valid_hp} lives, got {lives}")


class ActionSequence:
    """Defines and executes a sequence of actions."""

    def __init__(self, state: GameState = None):
        self.state = state if state else GameState()
        self.verifier = StateVerifier(self.state)
        self.history = []

    def setup_inject(self, player_id: int, card_id: int, zone: str, position: int = -1):
        """Inject a card before the sequence starts properly."""
        print(f"[SETUP] Inject P{player_id} {card_id} -> {zone}@{position}")
        self.state.inject_card(player_id, card_id, zone, position)

    def action_step(self, action_id: int, comment: str = ""):
        """Execute a single game action."""
        print(f"[ACTION] {comment} (ID: {action_id})")
        # Validate legality
        legal_actions = self.state.get_legal_actions()
        if not legal_actions[action_id]:
            raise AssertionError(f"Action {action_id} is improperly illegal in phase {self.state.phase}")

        self.state = self.state.step(action_id)
        self.verifier.state = self.state  # Update verifier ref
        self.history.append((action_id, comment))

    def action_auto(self, max_steps: int = 10):
        """Advance through automatic phases."""
        print(f"[AUTO] Advancing up to {max_steps} steps...")
        steps = 0
        from game.game_state import Phase  # Local import to avoid circular dependency issues if any

        while steps < max_steps and not self.state.is_terminal():
            if self.state.phase in (Phase.ACTIVE, Phase.ENERGY, Phase.DRAW, Phase.PERFORMANCE_P1, Phase.PERFORMANCE_P2):
                self.state = self.state.step(0)
                self.verifier.state = self.state
                steps += 1
                continue
            break
        print(f"[AUTO] Done after {steps} steps. Phase: {self.state.phase}")

    def verify(self, check_func: Callable[[StateVerifier], None]):
        """Run a custom verification function."""
        print("[VERIFY] Running checks...")
        check_func(self.verifier)
        print("[VERIFY] Passed.")

    def run_wrapper(self, func):
        """Run a function and handle errors nicely."""
        try:
            func()
            print("\n✅ Sequence Completed Successfully")
        except AssertionError as e:
            print(f"\n❌ Verification Failed: {e}")
            traceback.print_exc()
            sys.exit(1)
        except Exception as e:
            print(f"\n💥 Runtime Error: {e}")
            traceback.print_exc()
            sys.exit(1)