import numpy as np import pytest from engine.game.enums import Phase from engine.game.game_state import GameState, LiveCard, MemberCard class TestPerformanceResults: @pytest.fixture(autouse=True) def setup(self): self.game = GameState(verbose=True) self.p0 = self.game.players[0] # Setup mock databases self.game.member_db[1] = MemberCard( card_id=1, card_no="M1", name="Member 1", cost=1, hearts=np.array([1, 0, 0, 0, 0, 0, 0]), blade_hearts=np.array([0, 1, 0, 0, 0, 0, 0]), blades=1, abilities=[], img_path="m1.png", ) self.game.live_db[100] = LiveCard( card_id=100, card_no="L1", name="Live 1", score=1, required_hearts=np.array([1, 1, 0, 0, 0, 0, 0]), abilities=[], img_path="l1.png", ) def test_performance_results_population(self): """Verify that _do_performance populates performance_results correctly.""" # 1. Setup Stage & Live Zone self.p0.stage[0] = 1 # Member 1 in Area 0 self.p0.live_zone = [100] # Live 1 in Live Zone # 2. Setup Yell Card (Member 1 also used as yell) # This will provide 1 Red Blade Heart. # Member 1 in stage provides 1 Pink Heart. # Total: 1 Pink, 1 Red. Requirement for Live 1: 1 Pink, 1 Red. self.p0.main_deck = [1] # 3. Trigger Performance Phase 1 self.game.phase = Phase.PERFORMANCE_P1 self.game.current_player = 0 # Manually call _do_performance self.game._do_performance(0) # 4. Verify results assert 0 in self.game.performance_results res = self.game.performance_results[0] assert res["success"] is True assert len(res["member_contributions"]) == 1 assert res["member_contributions"][0]["id"] == 1 # Expect 7 elements for hearts (6 colors + Any/Star) assert res["member_contributions"][0]["hearts"] == [1, 0, 0, 0, 0, 0, 0] assert len(res["yell_cards"]) == 1 assert res["yell_cards"][0]["id"] == 1 assert res["yell_cards"][0]["blade_hearts"] == [0, 1, 0, 0, 0, 0, 0] # Total hearts should be [1, 1, 0, 0, 0, 0, 0] (Pink, Red, ...) assert res["total_hearts"] == [1, 1, 0, 0, 0, 0, 0] assert len(res["lives"]) == 1 assert res["lives"][0]["id"] == 100 assert res["lives"][0]["passed"] == True assert res["lives"][0]["score"] == 1 def test_performance_results_cleared_on_reset(self): """Verify that performance_results are cleared on game reset.""" self.game.performance_results[0] = {"dummy": "data"} self.game._reset() assert not self.game.performance_results def test_mixed_performance_results(self): """Verify that multiple lives track individual pass/fail status and scoring correctly.""" # Setup: Live 1 (ID 100) needs Pink+Red. Live 2 (ID 101) needs 2 Pink. self.game.live_db[101] = LiveCard( card_id=101, card_no="L2", name="Live 2", score=2, required_hearts=np.array([2, 0, 0, 0, 0, 0, 0]), abilities=[], img_path="l2.png", ) # Player has 1 Pink (Member 1) and 1 Red (Yell). # Live 1 (index 0) needs 1 Pink, 1 Red -> PASSED. # Live 2 (index 1) needs 2 Pink -> FAILED (only 0 Pink remain after consumption). self.p0.stage[0] = 1 # Member 1 self.p0.live_zone = [100, 101] self.p0.main_deck = [1] # For yell self.game.phase = Phase.PERFORMANCE_P1 self.game.current_player = 0 self.game._do_performance(0) res = self.game.performance_results[0] assert res["success"] is False # Overall success is false because not all met assert len(res["lives"]) == 2 # Live 1 should be passed assert res["lives"][0]["id"] == 100 assert res["lives"][0]["passed"] is True # Live 2 should be failed assert res["lives"][1]["id"] == 101 assert res["lives"][1]["passed"] is False # Score calculation in LiveResult phase self.game.phase = Phase.LIVE_RESULT self.game._do_live_result() # Rule 8.4.7: Because Live 2 failed, the entire performance failed (Rule 8.3.16). # Score should be 0. assert self.p0.score == 0 def test_tie_penalty(self): """Verify Rule 8.4.7.1: Tie with 2+ cards results in 0 points.""" # Setup: P0 and P1 both perform 2 lives successfully. p0, p1 = self.game.players[0], self.game.players[1] self.game.live_db[102] = LiveCard( card_id=102, card_no="L3", name="L3", score=1, required_hearts=np.array([0] * 7), abilities=[], img_path="" ) self.game.live_db[103] = LiveCard( card_id=103, card_no="L4", name="L4", score=1, required_hearts=np.array([0] * 7), abilities=[], img_path="" ) p0.passed_lives = [100, 102] p1.passed_lives = [101, 103] # Scoring: Both have 2 points (Live 1 + Live 3 vs Live 2 + Live 4) # Note: I'm manually Setting passed_lives to skip _do_performance heart checks self.game.phase = Phase.LIVE_RESULT self.game._do_live_result() # Both tied with 2+ cards -> should get 0 points assert p0.score == 0 assert p1.score == 0 assert len(p0.success_lives) == 0 assert len(p1.success_lives) == 0 def test_interactive_selection_choice(self): """Verify Rule 8.4.7.3: Multiple successful lives create a SELECT_SUCCESS_LIVE choice.""" # Setup: P0 performs 2 lives, P1 performs 0. p0 = self.game.players[0] self.game.live_db[102] = LiveCard( card_id=102, card_no="L3", name="L3", score=1, required_hearts=np.array([0] * 7), abilities=[], img_path="" ) p0.passed_lives = [100, 102] self.game.players[1].passed_lives = [] self.game.phase = Phase.LIVE_RESULT self.game._do_live_result() # P0 wins but has 2 cards -> choice pending assert len(self.game.pending_choices) == 1 assert self.game.pending_choices[0][0] == "SELECT_SUCCESS_LIVE" assert self.game.pending_choices[0][1]["player_id"] == 0 assert self.game.pending_choices[0][1]["cards"] == [100, 102] assert self.game.current_player == 0