Spaces:
Running
Running
| import numpy as np | |
| import pytest | |
| from engine.game.enums import Phase | |
| from engine.game.game_state import GameState, LiveCard, MemberCard | |
| class TestPerformanceResults: | |
| 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 | |