Spaces:
Running on Zero
Running on Zero
| from mafia.engine.reducers import ( | |
| cast_vote, | |
| create_game, | |
| resolve_night, | |
| start_discussion, | |
| start_vote, | |
| submit_night_action, | |
| ) | |
| from mafia.engine.state import Phase, Role, Team | |
| from mafia.ui.session import GameSession, advance_ai | |
| def test_create_game_has_classic_role_counts(): | |
| state = create_game(seed=42) | |
| counts = {} | |
| for player in state.players.values(): | |
| counts[player.role] = counts.get(player.role, 0) + 1 | |
| assert counts == { | |
| Role.MAFIA: 2, | |
| Role.DETECTIVE: 1, | |
| Role.DOCTOR: 1, | |
| Role.VILLAGER: 3, | |
| } | |
| assert len(state.players) == 7 | |
| assert state.phase == Phase.NIGHT | |
| def test_doctor_save_prevents_night_kill(): | |
| state = create_game(seed=10) | |
| mafia = next(pid for pid, p in state.players.items() if p.role == Role.MAFIA) | |
| doctor = next(pid for pid, p in state.players.items() if p.role == Role.DOCTOR) | |
| target = next(pid for pid, p in state.players.items() if p.team == Team.TOWN and pid != doctor) | |
| assert submit_night_action(state, mafia, "kill", target) | |
| assert submit_night_action(state, doctor, "protect", target) | |
| resolve_night(state) | |
| assert state.players[target].alive | |
| assert state.phase == Phase.DAWN | |
| def test_doctor_cannot_protect_same_target_twice_in_a_row(): | |
| state = create_game(seed=10) | |
| doctor = next(pid for pid, p in state.players.items() if p.role == Role.DOCTOR) | |
| target = next(pid for pid, p in state.players.items() if p.team == Team.TOWN and pid != doctor) | |
| assert submit_night_action(state, doctor, "protect", target) | |
| state.night_actions.doctor_protects.clear() | |
| assert not submit_night_action(state, doctor, "protect", target) | |
| def test_doctor_can_protect_self_but_not_twice_in_a_row(): | |
| state = create_game(seed=10) | |
| doctor = next(pid for pid, p in state.players.items() if p.role == Role.DOCTOR) | |
| assert submit_night_action(state, doctor, "protect", doctor) | |
| state.night_actions.doctor_protects.clear() | |
| assert not submit_night_action(state, doctor, "protect", doctor) | |
| def test_detective_gets_private_alignment_result(): | |
| state = create_game(seed=14) | |
| detective = next(pid for pid, p in state.players.items() if p.role == Role.DETECTIVE) | |
| mafia = next(pid for pid, p in state.players.items() if p.role == Role.MAFIA) | |
| assert submit_night_action(state, detective, "check", mafia) | |
| resolve_night(state) | |
| assert state.players[detective].private_memory["investigations"][mafia] is True | |
| def test_vote_eliminates_plurality_target(): | |
| state = create_game(seed=3) | |
| resolve_night(state) | |
| start_discussion(state) | |
| state.phase = Phase.VOTE | |
| alive = state.alive_players() | |
| target = alive[-1] | |
| for voter in alive[:-1]: | |
| cast_vote(state, voter, target) | |
| assert not state.players[target].alive | |
| assert target in state.eliminated_order | |
| def test_mafia_night_disagreement_still_resolves_team_kill(): | |
| state = create_game(seed=42) | |
| mafia = [pid for pid, player in state.players.items() if player.role == Role.MAFIA] | |
| targets = [pid for pid, player in state.players.items() if player.team == Team.TOWN] | |
| assert len(mafia) == 2 | |
| assert submit_night_action(state, mafia[0], "kill", targets[0]) | |
| assert submit_night_action(state, mafia[1], "kill", targets[1]) | |
| resolve_night(state) | |
| assert len([pid for pid in targets if not state.players[pid].alive]) == 1 | |
| assert any(event.type == "mafia_consensus" for event in state.events) | |
| def test_vote_phase_waits_for_living_human_vote_before_ai_votes(): | |
| state = create_game(seed=33) | |
| resolve_night(state) | |
| start_discussion(state) | |
| start_vote(state) | |
| session = GameSession(state=state) | |
| advance_ai(session, max_steps=3) | |
| assert state.phase == Phase.VOTE | |
| assert state.human_player_id not in state.locked_votes | |
| assert not state.votes | |