import numpy as np import pytest from engine.game.enums import Phase from engine.game.game_state import GameState from engine.models.ability import TriggerType from engine.models.card import LiveCard @pytest.fixture def game(): # Setup a game with some live cards gs = GameState() # Mock some live cards l1 = LiveCard(card_id=1001, name="Live 1", score=1, required_hearts=np.zeros(7, dtype=np.int32), card_no="L1") l2 = LiveCard(card_id=1002, name="Live 2", score=2, required_hearts=np.zeros(7, dtype=np.int32), card_no="L2") GameState.initialize_class_db({}, {1001: l1, 1002: l2}) # Setup players with live cards in passed_lives (as if performance phase finished) gs.phase = Phase.LIVE_RESULT return gs def test_tie_one_card_each(game): """Rule 8.4.6.2: Both win. Rule 8.4.7.2: Each moves 1 card.""" game.players[0].passed_lives = [1001] game.players[1].passed_lives = [1001] # Run judgment game._do_live_result() assert game.players[0].score == 1 assert game.players[1].score == 1 assert len(game.players[0].success_lives) == 1 assert len(game.players[1].success_lives) == 1 def test_tie_two_vs_one_penalty(game): """Rule 8.4.7.1: P0 has 2 cards and ties, so moves 0 cards. P1 has 1 card and moves it.""" game.players[0].passed_lives = [1001, 1001] # Total score 2 game.players[1].passed_lives = [1002] # Total score 2 game._do_live_result() # P0 tied with 2 cards -> 0 points (Rule 8.4.7.1) assert game.players[0].score == 0 # P1 tied with 1 card -> 1 point (Rule 8.4.7.2) assert game.players[1].score == 1 # P0's cards should be discarded assert len(game.players[0].passed_lives) == 0 assert 1001 in game.players[0].discard def test_win_with_multiple_cards(game): """Rule 8.4.7.3: Winning with multiple cards requires selection, yields 1 point.""" game.players[0].passed_lives = [1001, 1001] # Total score 2 game.players[1].passed_lives = [1001] # Total score 1 game._do_live_result() # Should have a pending choice to select which card moves to success_lives assert len(game.pending_choices) == 1 # Advance choice # _handle_choice will pop from game.pending_choices print(f"DEBUG: Calling _handle_choice(600) with choices: {game.pending_choices}") game._handle_choice(600) # Choices are handled during _do_live_result. # If a choice was pending, it returned early. # In a real game, _handle_choice would trigger the next step. # Since we are testing _do_live_result logic specifically: game._finish_live_result() assert game.players[0].score == 1 assert game.players[1].score == 0 def test_on_live_success_trigger_only_for_winners(game): """Rule 8.4.6: Triggers only for winners.""" from engine.models.ability import Ability # Mock member with ON_LIVE_SUCCESS abi = Ability(raw_text="Test Success", trigger=TriggerType.ON_LIVE_SUCCESS, effects=[]) from engine.models.card import MemberCard m1 = MemberCard( card_id=1, card_no="M1", name="M1", cost=1, hearts=np.zeros(7), blade_hearts=np.zeros(7), blades=1, abilities=[abi], ) GameState.initialize_class_db({1: m1}, GameState.live_db) game.players[0].stage[0] = 1 game.players[1].stage[0] = 1 # P0 wins game.players[0].passed_lives = [1002] game.players[1].passed_lives = [1001] game._do_live_result() # Only P0's trigger should be queued assert len(game.triggered_abilities) == 1 assert game.triggered_abilities[0][0] == 0 # Player 0