File size: 3,851 Bytes
c670567
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
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