"""Pytest fixtures for the core game engine tests. This module provides reusable fixtures for testing the game engine: - Sample card definitions (Pokemon, Trainer, Energy) - Pre-configured game states - Seeded RNG instances for deterministic testing - Helper functions for creating test data Usage: def test_something(sample_pokemon, seeded_rng): # sample_pokemon is a CardDefinition # seeded_rng is a SeededRandom instance pass """ import pytest from app.core.config import RulesConfig from app.core.models.card import ( Ability, Attack, CardDefinition, CardInstance, WeaknessResistance, ) from app.core.models.enums import ( CardType, EnergyType, PokemonStage, PokemonVariant, TrainerType, TurnPhase, ) from app.core.models.game_state import GameState, PlayerState from app.core.rng import SeededRandom # ============================================================================ # RNG Fixtures # ============================================================================ @pytest.fixture def seeded_rng() -> SeededRandom: """Provide a SeededRandom instance with a fixed seed for deterministic tests. The seed 42 is used consistently across tests for reproducibility. """ return SeededRandom(seed=42) @pytest.fixture def rng_factory(): """Factory fixture to create SeededRandom instances with custom seeds. Usage: def test_something(rng_factory): rng1 = rng_factory(seed=100) rng2 = rng_factory(seed=200) """ def _create_rng(seed: int = 42) -> SeededRandom: return SeededRandom(seed=seed) return _create_rng # ============================================================================ # Card Definition Fixtures - Pokemon # ============================================================================ @pytest.fixture def pikachu_def() -> CardDefinition: """Basic Lightning Pokemon - Pikachu. A simple Basic Pokemon with one attack and standard stats. Used as the canonical "basic Pokemon" in tests. """ return CardDefinition( id="pikachu_base_001", name="Pikachu", card_type=CardType.POKEMON, stage=PokemonStage.BASIC, variant=PokemonVariant.NORMAL, hp=60, pokemon_type=EnergyType.LIGHTNING, attacks=[ Attack( name="Thunder Shock", cost=[EnergyType.LIGHTNING], damage=20, effect_id="may_paralyze", effect_params={"chance": 0.5}, effect_description="Flip a coin. If heads, the Defending Pokemon is now Paralyzed.", ), ], weakness=WeaknessResistance(energy_type=EnergyType.FIGHTING, modifier=2), retreat_cost=1, rarity="common", set_id="base", ) @pytest.fixture def raichu_def() -> CardDefinition: """Stage 1 Lightning Pokemon - Raichu. Evolves from Pikachu. Used for evolution tests. """ return CardDefinition( id="raichu_base_001", name="Raichu", card_type=CardType.POKEMON, stage=PokemonStage.STAGE_1, variant=PokemonVariant.NORMAL, evolves_from="Pikachu", hp=90, pokemon_type=EnergyType.LIGHTNING, attacks=[ Attack( name="Thunder", cost=[EnergyType.LIGHTNING, EnergyType.LIGHTNING, EnergyType.COLORLESS], damage=60, ), ], weakness=WeaknessResistance(energy_type=EnergyType.FIGHTING, modifier=2), retreat_cost=1, rarity="rare", set_id="base", ) @pytest.fixture def charizard_def() -> CardDefinition: """Stage 2 Fire Pokemon - Charizard. Classic high-HP Stage 2 Pokemon. Evolves from Charmeleon. """ return CardDefinition( id="charizard_base_001", name="Charizard", card_type=CardType.POKEMON, stage=PokemonStage.STAGE_2, variant=PokemonVariant.NORMAL, evolves_from="Charmeleon", hp=120, pokemon_type=EnergyType.FIRE, attacks=[ Attack( name="Fire Spin", cost=[EnergyType.FIRE, EnergyType.FIRE, EnergyType.FIRE, EnergyType.FIRE], damage=100, effect_id="discard_energy", effect_params={"count": 2, "type": "fire"}, ), ], weakness=WeaknessResistance(energy_type=EnergyType.WATER, modifier=2), resistance=WeaknessResistance(energy_type=EnergyType.FIGHTING, modifier=-30), retreat_cost=3, rarity="rare_holo", set_id="base", ) @pytest.fixture def mewtwo_ex_def() -> CardDefinition: """Basic EX Pokemon - Mewtwo EX. High-HP Pokemon worth 2 knockout points. """ return CardDefinition( id="mewtwo_ex_001", name="Mewtwo EX", card_type=CardType.POKEMON, stage=PokemonStage.BASIC, variant=PokemonVariant.EX, hp=170, pokemon_type=EnergyType.PSYCHIC, attacks=[ Attack( name="Psydrive", cost=[EnergyType.PSYCHIC, EnergyType.COLORLESS], damage=120, effect_id="discard_energy", effect_params={"count": 1, "type": "any"}, ), ], weakness=WeaknessResistance(energy_type=EnergyType.PSYCHIC, modifier=2), retreat_cost=2, rarity="ultra_rare", set_id="ex_series", ) @pytest.fixture def pikachu_v_def() -> CardDefinition: """Basic V Pokemon - Pikachu V. V Pokemon worth 2 knockout points. """ return CardDefinition( id="pikachu_v_001", name="Pikachu V", card_type=CardType.POKEMON, stage=PokemonStage.BASIC, variant=PokemonVariant.V, hp=190, pokemon_type=EnergyType.LIGHTNING, attacks=[ Attack( name="Volt Tackle", cost=[EnergyType.LIGHTNING, EnergyType.LIGHTNING, EnergyType.COLORLESS], damage=210, effect_id="self_damage", effect_params={"amount": 30}, ), ], weakness=WeaknessResistance(energy_type=EnergyType.FIGHTING, modifier=2), retreat_cost=2, rarity="ultra_rare", set_id="v_series", ) @pytest.fixture def pikachu_vmax_def() -> CardDefinition: """VMAX Pokemon - Pikachu VMAX. Evolves from Pikachu V, worth 3 knockout points. """ return CardDefinition( id="pikachu_vmax_001", name="Pikachu VMAX", card_type=CardType.POKEMON, stage=PokemonStage.BASIC, # Stage is still Basic variant=PokemonVariant.VMAX, # Variant indicates V evolution evolves_from="Pikachu V", hp=310, pokemon_type=EnergyType.LIGHTNING, attacks=[ Attack( name="G-Max Volt Crash", cost=[EnergyType.LIGHTNING, EnergyType.LIGHTNING, EnergyType.LIGHTNING], damage=270, ), ], weakness=WeaknessResistance(energy_type=EnergyType.FIGHTING, modifier=2), retreat_cost=3, rarity="secret_rare", set_id="vmax_series", ) @pytest.fixture def pokemon_with_ability_def() -> CardDefinition: """Pokemon with an Ability - Shaymin EX. Used for ability testing. """ return CardDefinition( id="shaymin_ex_001", name="Shaymin EX", card_type=CardType.POKEMON, stage=PokemonStage.BASIC, variant=PokemonVariant.EX, hp=110, pokemon_type=EnergyType.COLORLESS, abilities=[ Ability( name="Set Up", effect_id="draw_until_hand_size", effect_params={"count": 6}, effect_description="When you play this Pokemon from your hand to your Bench, " "you may draw cards until you have 6 cards in your hand.", once_per_turn=True, ), ], attacks=[ Attack( name="Sky Return", cost=[EnergyType.COLORLESS, EnergyType.COLORLESS], damage=30, effect_id="return_to_hand", ), ], retreat_cost=1, rarity="ultra_rare", set_id="ex_series", ) # ============================================================================ # Card Definition Fixtures - Trainers # ============================================================================ @pytest.fixture def potion_def() -> CardDefinition: """Item card - Potion. Basic healing item. """ return CardDefinition( id="potion_base_001", name="Potion", card_type=CardType.TRAINER, trainer_type=TrainerType.ITEM, effect_id="heal", effect_params={"amount": 30}, effect_description="Heal 30 damage from one of your Pokemon.", rarity="common", set_id="base", ) @pytest.fixture def professor_oak_def() -> CardDefinition: """Supporter card - Professor Oak. Classic draw supporter. """ return CardDefinition( id="professor_oak_001", name="Professor Oak", card_type=CardType.TRAINER, trainer_type=TrainerType.SUPPORTER, effect_id="discard_hand_draw", effect_params={"draw_count": 7}, effect_description="Discard your hand and draw 7 cards.", rarity="uncommon", set_id="base", ) @pytest.fixture def pokemon_center_def() -> CardDefinition: """Stadium card - Pokemon Center. Example stadium that stays in play. """ return CardDefinition( id="pokemon_center_001", name="Pokemon Center", card_type=CardType.TRAINER, trainer_type=TrainerType.STADIUM, effect_id="stadium_heal_between_turns", effect_params={"amount": 20}, effect_description="Between turns, heal 20 damage from each player's Active Pokemon.", rarity="uncommon", set_id="base", ) @pytest.fixture def choice_band_def() -> CardDefinition: """Tool card - Choice Band. Damage-boosting tool. """ return CardDefinition( id="choice_band_001", name="Choice Band", card_type=CardType.TRAINER, trainer_type=TrainerType.TOOL, effect_id="damage_boost_vs_ex_gx", effect_params={"amount": 30}, effect_description="The attacks of the Pokemon this is attached to do 30 more damage " "to your opponent's Active Pokemon-EX or Pokemon-GX.", rarity="uncommon", set_id="modern", ) # ============================================================================ # Card Definition Fixtures - Energy # ============================================================================ @pytest.fixture def lightning_energy_def() -> CardDefinition: """Basic Lightning Energy.""" return CardDefinition( id="lightning_energy_001", name="Lightning Energy", card_type=CardType.ENERGY, energy_type=EnergyType.LIGHTNING, energy_provides=[EnergyType.LIGHTNING], rarity="common", set_id="base", ) @pytest.fixture def fire_energy_def() -> CardDefinition: """Basic Fire Energy.""" return CardDefinition( id="fire_energy_001", name="Fire Energy", card_type=CardType.ENERGY, energy_type=EnergyType.FIRE, energy_provides=[EnergyType.FIRE], rarity="common", set_id="base", ) @pytest.fixture def double_colorless_energy_def() -> CardDefinition: """Special Energy - Double Colorless Energy. Provides 2 Colorless energy. """ return CardDefinition( id="dce_001", name="Double Colorless Energy", card_type=CardType.ENERGY, energy_provides=[EnergyType.COLORLESS, EnergyType.COLORLESS], rarity="uncommon", set_id="base", ) # ============================================================================ # Card Registry Fixtures # ============================================================================ @pytest.fixture def basic_card_registry( pikachu_def, raichu_def, charizard_def, potion_def, professor_oak_def, lightning_energy_def, fire_energy_def, ) -> dict[str, CardDefinition]: """A basic card registry with common test cards. Includes: Pikachu, Raichu, Charizard, Potion, Professor Oak, basic energy. """ cards = [ pikachu_def, raichu_def, charizard_def, potion_def, professor_oak_def, lightning_energy_def, fire_energy_def, ] return {card.id: card for card in cards} # ============================================================================ # Card Instance Factory # ============================================================================ @pytest.fixture def card_instance_factory(): """Factory fixture to create CardInstance objects. Usage: def test_something(card_instance_factory): card = card_instance_factory("pikachu_base_001") card_with_damage = card_instance_factory("pikachu_base_001", damage=30) card_evolved = card_instance_factory("raichu_base_001", turn_evolved=2) """ _counter = [0] def _create_instance( definition_id: str, instance_id: str | None = None, damage: int = 0, turn_played: int | None = None, turn_evolved: int | None = None, ) -> CardInstance: if instance_id is None: _counter[0] += 1 instance_id = f"inst_{definition_id}_{_counter[0]}" card = CardInstance( instance_id=instance_id, definition_id=definition_id, damage=damage, turn_played=turn_played, ) if turn_evolved is not None: card.turn_evolved = turn_evolved return card return _create_instance # ============================================================================ # Game State Fixtures # ============================================================================ @pytest.fixture def empty_game_state(basic_card_registry) -> GameState: """An empty game state ready for setup. Has two players with empty zones, in SETUP phase. """ return GameState( game_id="test_game_001", rules=RulesConfig(), card_registry=basic_card_registry, players={ "player1": PlayerState(player_id="player1"), "player2": PlayerState(player_id="player2"), }, turn_order=["player1", "player2"], current_player_id="player1", turn_number=0, phase=TurnPhase.SETUP, ) @pytest.fixture def mid_game_state(basic_card_registry, card_instance_factory) -> GameState: """A game state in the middle of play. - Turn 3, player1's turn, MAIN phase - Player1: Pikachu active, Raichu on bench, 3 cards in hand, score 1 - Player2: Charizard active, 4 cards in hand, score 0 - Both players have cards in deck and discard """ player1 = PlayerState(player_id="player1") player2 = PlayerState(player_id="player2") # Player 1 setup player1.active.add(card_instance_factory("pikachu_base_001", turn_played=1)) player1.bench.add(card_instance_factory("raichu_base_001", turn_played=2)) for _ in range(3): player1.hand.add(card_instance_factory("lightning_energy_001")) for _ in range(10): player1.deck.add(card_instance_factory("pikachu_base_001")) player1.discard.add(card_instance_factory("potion_base_001")) player1.score = 1 # Player 2 setup player2.active.add(card_instance_factory("charizard_base_001", turn_played=1, damage=40)) for _ in range(4): player2.hand.add(card_instance_factory("fire_energy_001")) for _ in range(8): player2.deck.add(card_instance_factory("charizard_base_001")) player2.discard.add(card_instance_factory("professor_oak_001")) player2.score = 0 return GameState( game_id="test_game_mid", rules=RulesConfig(), card_registry=basic_card_registry, players={"player1": player1, "player2": player2}, turn_order=["player1", "player2"], current_player_id="player1", turn_number=3, phase=TurnPhase.MAIN, first_turn_completed=True, ) @pytest.fixture def game_near_win_state(basic_card_registry, card_instance_factory) -> GameState: """A game state where player1 is about to win (3/4 points). Used for testing win condition detection. """ player1 = PlayerState(player_id="player1") player2 = PlayerState(player_id="player2") # Player 1 setup - one knockout away from winning player1.active.add(card_instance_factory("pikachu_base_001")) player1.score = 3 # 4 points needed to win # Player 2 setup - low HP Pokemon active damaged_pikachu = card_instance_factory("pikachu_base_001", damage=50) # 10 HP remaining player2.active.add(damaged_pikachu) return GameState( game_id="test_game_near_win", rules=RulesConfig(), # Default: 4 points to win card_registry=basic_card_registry, players={"player1": player1, "player2": player2}, turn_order=["player1", "player2"], current_player_id="player1", turn_number=5, phase=TurnPhase.ATTACK, first_turn_completed=True, ) # ============================================================================ # Rules Config Fixtures # ============================================================================ @pytest.fixture def default_rules() -> RulesConfig: """Default Mantimon TCG rules. 40-card deck, 4 points to win, Pokemon Pocket-style energy. """ return RulesConfig() @pytest.fixture def standard_tcg_rules() -> RulesConfig: """Standard Pokemon TCG rules. 60-card deck, 6 prizes, no energy deck. """ return RulesConfig.standard_pokemon_tcg() # ============================================================================ # Additional Card Definition Fixtures for Evolution Testing # ============================================================================ @pytest.fixture def charmander_def() -> CardDefinition: """Basic Fire Pokemon - Charmander. Used for evolution chain testing (Charmander -> Charmeleon -> Charizard). """ return CardDefinition( id="charmander_base_001", name="Charmander", card_type=CardType.POKEMON, stage=PokemonStage.BASIC, variant=PokemonVariant.NORMAL, hp=50, pokemon_type=EnergyType.FIRE, attacks=[ Attack( name="Scratch", cost=[EnergyType.COLORLESS], damage=10, ), ], weakness=WeaknessResistance(energy_type=EnergyType.WATER, modifier=2), retreat_cost=1, rarity="common", set_id="base", ) @pytest.fixture def charmeleon_def() -> CardDefinition: """Stage 1 Fire Pokemon - Charmeleon. Evolves from Charmander. Used for evolution chain testing. """ return CardDefinition( id="charmeleon_base_001", name="Charmeleon", card_type=CardType.POKEMON, stage=PokemonStage.STAGE_1, variant=PokemonVariant.NORMAL, evolves_from="Charmander", hp=80, pokemon_type=EnergyType.FIRE, attacks=[ Attack( name="Slash", cost=[EnergyType.FIRE, EnergyType.COLORLESS], damage=30, ), ], weakness=WeaknessResistance(energy_type=EnergyType.WATER, modifier=2), retreat_cost=1, rarity="uncommon", set_id="base", ) # ============================================================================ # Extended Card Registry Fixture # ============================================================================ @pytest.fixture def extended_card_registry( pikachu_def, raichu_def, charmander_def, charmeleon_def, charizard_def, mewtwo_ex_def, pikachu_v_def, pikachu_vmax_def, pokemon_with_ability_def, potion_def, professor_oak_def, pokemon_center_def, choice_band_def, lightning_energy_def, fire_energy_def, double_colorless_energy_def, ) -> dict[str, CardDefinition]: """Extended card registry with all test cards. Includes full evolution chains and all card types for comprehensive testing. """ cards = [ pikachu_def, raichu_def, charmander_def, charmeleon_def, charizard_def, mewtwo_ex_def, pikachu_v_def, pikachu_vmax_def, pokemon_with_ability_def, potion_def, professor_oak_def, pokemon_center_def, choice_band_def, lightning_energy_def, fire_energy_def, double_colorless_energy_def, ] return {card.id: card for card in cards} # ============================================================================ # Game State Fixtures for Rules Validation # ============================================================================ @pytest.fixture def game_in_main_phase(extended_card_registry, card_instance_factory) -> GameState: """Game state in MAIN phase for testing main phase actions. - Turn 2, player1's turn, MAIN phase - Player1: Pikachu active (with 1 lightning energy), Charmander on bench, cards in hand - Player2: Raichu active """ player1 = PlayerState(player_id="player1") player2 = PlayerState(player_id="player2") # Player 1 setup - active with energy, bench pokemon, cards in hand pikachu = card_instance_factory("pikachu_base_001", turn_played=1) pikachu.attach_energy("energy_lightning_1") player1.active.add(pikachu) player1.bench.add(card_instance_factory("charmander_base_001", turn_played=1)) # The attached energy card needs to exist somewhere so find_card_instance can find it # In real gameplay, attached energy stays "on" the Pokemon but is tracked by ID # For testing, we put it in discard (where it can be found but isn't "in hand") player1.discard.add( card_instance_factory("lightning_energy_001", instance_id="energy_lightning_1") ) # Cards in hand: evolution card, energy, trainer player1.hand.add(card_instance_factory("raichu_base_001", instance_id="hand_raichu")) player1.hand.add(card_instance_factory("charmeleon_base_001", instance_id="hand_charmeleon")) player1.hand.add(card_instance_factory("lightning_energy_001", instance_id="hand_energy")) player1.hand.add(card_instance_factory("potion_base_001", instance_id="hand_potion")) player1.hand.add(card_instance_factory("professor_oak_001", instance_id="hand_supporter")) player1.hand.add(card_instance_factory("pokemon_center_001", instance_id="hand_stadium")) player1.hand.add(card_instance_factory("pikachu_base_001", instance_id="hand_basic")) # Energy in energy zone (for Pokemon Pocket style) player1.energy_zone.add( card_instance_factory("lightning_energy_001", instance_id="zone_energy") ) # Some deck cards for i in range(10): player1.deck.add(card_instance_factory("pikachu_base_001", instance_id=f"deck_{i}")) # Player 2 setup player2.active.add(card_instance_factory("raichu_base_001", turn_played=1)) for i in range(10): player2.deck.add(card_instance_factory("pikachu_base_001", instance_id=f"p2_deck_{i}")) return GameState( game_id="test_main_phase", rules=RulesConfig(), card_registry=extended_card_registry, players={"player1": player1, "player2": player2}, turn_order=["player1", "player2"], current_player_id="player1", turn_number=2, phase=TurnPhase.MAIN, first_turn_completed=True, ) @pytest.fixture def game_in_attack_phase(extended_card_registry, card_instance_factory) -> GameState: """Game state in ATTACK phase for testing attack validation. - Turn 2, player1's turn, ATTACK phase - Player1: Pikachu active with enough energy for Thunder Shock - Player2: Raichu active """ player1 = PlayerState(player_id="player1") player2 = PlayerState(player_id="player2") # Player 1 - Pikachu with 1 lightning energy (enough for Thunder Shock) pikachu = card_instance_factory("pikachu_base_001", turn_played=1) pikachu.attach_energy("energy_lightning_1") player1.active.add(pikachu) player1.bench.add(card_instance_factory("charmander_base_001", turn_played=1)) # The attached energy card needs to exist somewhere so find_card_instance can find it player1.discard.add( card_instance_factory("lightning_energy_001", instance_id="energy_lightning_1") ) for i in range(10): player1.deck.add(card_instance_factory("pikachu_base_001", instance_id=f"deck_{i}")) # Player 2 player2.active.add(card_instance_factory("raichu_base_001", turn_played=1)) return GameState( game_id="test_attack_phase", rules=RulesConfig(), card_registry=extended_card_registry, players={"player1": player1, "player2": player2}, turn_order=["player1", "player2"], current_player_id="player1", turn_number=2, phase=TurnPhase.ATTACK, first_turn_completed=True, ) @pytest.fixture def game_in_setup_phase(extended_card_registry, card_instance_factory) -> GameState: """Game state in SETUP phase for testing setup actions. - Turn 0, SETUP phase - Both players have empty zones but basic pokemon in hand """ player1 = PlayerState(player_id="player1") player2 = PlayerState(player_id="player2") # Player 1 - basic pokemon in hand for setup player1.hand.add(card_instance_factory("pikachu_base_001", instance_id="p1_hand_basic1")) player1.hand.add(card_instance_factory("charmander_base_001", instance_id="p1_hand_basic2")) # Player 2 - basic pokemon in hand player2.hand.add(card_instance_factory("pikachu_base_001", instance_id="p2_hand_basic1")) return GameState( game_id="test_setup", rules=RulesConfig(), card_registry=extended_card_registry, players={"player1": player1, "player2": player2}, turn_order=["player1", "player2"], current_player_id="player1", turn_number=0, phase=TurnPhase.SETUP, first_turn_completed=False, ) @pytest.fixture def game_first_turn(extended_card_registry, card_instance_factory) -> GameState: """Game state on the first turn for testing first-turn restrictions. - Turn 1, player1's turn, MAIN phase - First turn restrictions apply """ player1 = PlayerState(player_id="player1") player2 = PlayerState(player_id="player2") # Player 1 - just placed basic, has cards in hand player1.active.add(card_instance_factory("pikachu_base_001", turn_played=1)) player1.hand.add(card_instance_factory("lightning_energy_001", instance_id="hand_energy")) player1.hand.add(card_instance_factory("raichu_base_001", instance_id="hand_raichu")) player1.hand.add(card_instance_factory("professor_oak_001", instance_id="hand_supporter")) for i in range(10): player1.deck.add(card_instance_factory("pikachu_base_001", instance_id=f"deck_{i}")) # Player 2 player2.active.add(card_instance_factory("raichu_base_001", turn_played=1)) return GameState( game_id="test_first_turn", rules=RulesConfig(), card_registry=extended_card_registry, players={"player1": player1, "player2": player2}, turn_order=["player1", "player2"], current_player_id="player1", turn_number=1, phase=TurnPhase.MAIN, first_turn_completed=False, # Still first turn ) @pytest.fixture def game_with_forced_action(extended_card_registry, card_instance_factory) -> GameState: """Game state with a forced action pending. - Player2's active was knocked out, must select new active - Player1 just attacked and knocked out player2's active """ from app.core.models.game_state import ForcedAction player1 = PlayerState(player_id="player1") player2 = PlayerState(player_id="player2") # Player 1 - active pokemon player1.active.add(card_instance_factory("pikachu_base_001", turn_played=1)) # Player 2 - no active (knocked out), but has bench player2.bench.add(card_instance_factory("charmander_base_001", instance_id="p2_bench1")) player2.bench.add(card_instance_factory("pikachu_base_001", instance_id="p2_bench2")) game = GameState( game_id="test_forced_action", rules=RulesConfig(), card_registry=extended_card_registry, players={"player1": player1, "player2": player2}, turn_order=["player1", "player2"], current_player_id="player1", turn_number=3, phase=TurnPhase.ATTACK, first_turn_completed=True, forced_action=ForcedAction( player_id="player2", action_type="select_active", reason="Active Pokemon was knocked out", ), ) return game @pytest.fixture def game_over_state(extended_card_registry, card_instance_factory) -> GameState: """Game state where the game is over. - Player1 has won """ from app.core.models.enums import GameEndReason player1 = PlayerState(player_id="player1") player2 = PlayerState(player_id="player2") player1.active.add(card_instance_factory("pikachu_base_001")) player1.score = 4 # Won! return GameState( game_id="test_game_over", rules=RulesConfig(), card_registry=extended_card_registry, players={"player1": player1, "player2": player2}, turn_order=["player1", "player2"], current_player_id="player1", turn_number=10, phase=TurnPhase.END, first_turn_completed=True, winner_id="player1", end_reason=GameEndReason.PRIZES_TAKEN, )