AmongUS / tests /test_engine.py
5h4dy's picture
Upload folder using huggingface_hub
6c3d778 verified
from amongus_env.engine import AmongUsEngine
from amongus_env.models import (
CallMeeting,
ClaimKind,
CompleteTask,
Kill,
Move,
PassMeeting,
Phase,
PlayerRole,
ReportBody,
Speak,
Vote,
Winner,
)
def test_reset_is_deterministic_and_spawns_in_cafeteria() -> None:
first = AmongUsEngine(seed=7, impostor_ids=["blue"]).reset()
second = AmongUsEngine(seed=7, impostor_ids=["blue"]).reset()
assert first == second
assert first.role is PlayerRole.CREWMATE
assert first.location == "Cafeteria"
assert first.phase is Phase.TASKS
assert "Match reset" in first.message_log[-1]
def test_invalid_movement_is_penalized_without_changing_location() -> None:
engine = AmongUsEngine(seed=1, impostor_ids=["blue"])
engine.reset()
observation = engine.step(Move(room="Navigation"))
assert observation.location == "Cafeteria"
assert observation.reward == -0.1
assert "Invalid move" in observation.message_log[-1]
def test_location_history_tracks_reset_and_valid_moves_only() -> None:
engine = AmongUsEngine(seed=1, impostor_ids=["blue"])
engine.reset()
engine.step(Move(room="Electrical"))
engine.step(Move(room="Navigation"))
assert engine.location_history["red"] == ["Cafeteria", "Electrical"]
assert engine.location_history["blue"] == ["Cafeteria"]
def test_visibility_only_includes_living_players_in_same_room() -> None:
engine = AmongUsEngine(seed=1, impostor_ids=["blue"])
engine.reset()
engine.step(Move(room="Electrical"))
engine.players["blue"].location = "Electrical"
engine.players["green"].location = "MedBay"
engine.players["yellow"].location = "Electrical"
engine.players["yellow"].alive = False
observation = engine.observe()
assert observation.visible_players == ["blue"]
def test_crewmate_completes_current_room_task_for_dense_reward() -> None:
engine = AmongUsEngine(seed=1, impostor_ids=["blue"])
engine.reset()
engine.step(Move(room="Electrical"))
observation = engine.step(CompleteTask())
assert observation.reward == 0.2
assert observation.task_list[0].completed is True
assert "Completed task" in observation.message_log[-1]
def test_impostor_kill_marks_body_and_rewards_controlled_impostor() -> None:
engine = AmongUsEngine(seed=1, impostor_ids=["red"])
engine.reset()
engine.players["blue"].location = "Cafeteria"
observation = engine.step(Kill(target_id="blue"))
assert observation.reward == 0.5
assert engine.players["blue"].alive is False
assert "blue" in engine.dead_bodies
assert "Killed blue" in observation.message_log[-1]
def test_report_body_enters_meeting_phase() -> None:
engine = AmongUsEngine(seed=1, impostor_ids=["red"])
engine.reset()
engine.step(Kill(target_id="blue"))
observation = engine.step(ReportBody())
assert observation.phase is Phase.MEETING
assert observation.voting_open is False
assert observation.meeting_turns_remaining == 1
assert "Reported body" in observation.message_log[-1]
def test_vote_before_discussion_turn_is_illegal() -> None:
engine = AmongUsEngine(seed=1, impostor_ids=["blue"])
engine.reset()
engine.step(CallMeeting())
observation = engine.step(Vote(target_id="blue"))
assert observation.reward == -0.1
assert observation.phase is Phase.MEETING
assert observation.voting_open is False
assert observation.meeting_turns_remaining == 1
assert "Cannot vote before discussion" in observation.message_log[-1]
def test_pass_opens_voting_without_claim_reward() -> None:
engine = AmongUsEngine(seed=1, impostor_ids=["blue"])
engine.reset()
engine.step(CallMeeting())
observation = engine.step(PassMeeting())
assert observation.reward == 0.0
assert observation.phase is Phase.MEETING
assert observation.voting_open is True
assert observation.meeting_turns_remaining == 0
assert observation.discussion_log[-1] == "red: pass"
def test_meeting_speech_parses_self_location_claim() -> None:
engine = AmongUsEngine(seed=1, impostor_ids=["blue"])
engine.reset()
engine.step(Move(room="Electrical"))
engine.step(CallMeeting())
observation = engine.step(Speak(message="I was in Electrical"))
assert observation.discussion_log[-1] == "red: I was in Electrical"
assert observation.claims[-1].kind is ClaimKind.SELF_LOCATION
assert observation.claims[-1].speaker_id == "red"
assert observation.claims[-1].room == "Electrical"
assert observation.claims[-1].truth_value is True
assert observation.voting_open is True
assert observation.meeting_turns_remaining == 0
def test_meeting_speech_parses_saw_player_claim() -> None:
engine = AmongUsEngine(seed=1, impostor_ids=["blue"])
engine.reset()
engine.players["blue"].location = "MedBay"
engine.location_history["blue"].append("MedBay")
engine.step(CallMeeting())
observation = engine.step(Speak(message="I saw blue in MedBay"))
assert observation.claims[-1].kind is ClaimKind.SAW_PLAYER
assert observation.claims[-1].target_id == "blue"
assert observation.claims[-1].room == "MedBay"
assert observation.claims[-1].truth_value is True
def test_speaking_outside_meeting_is_illegal() -> None:
engine = AmongUsEngine(seed=1, impostor_ids=["blue"])
engine.reset()
observation = engine.step(Speak(message="I was in Cafeteria"))
assert observation.reward == -0.1
assert "Cannot speak outside meeting" in observation.message_log[-1]
def test_pass_outside_meeting_is_illegal() -> None:
engine = AmongUsEngine(seed=1, impostor_ids=["blue"])
engine.reset()
observation = engine.step(PassMeeting())
assert observation.reward == -0.1
assert observation.phase is Phase.TASKS
assert observation.voting_open is False
assert observation.meeting_turns_remaining == 0
assert "Cannot pass outside meeting" in observation.message_log[-1]
def test_speak_after_voting_opens_is_illegal() -> None:
engine = AmongUsEngine(seed=1, impostor_ids=["blue"])
engine.reset()
engine.step(CallMeeting())
engine.step(PassMeeting())
observation = engine.step(Speak(message="I was in Cafeteria"))
assert observation.reward == -0.1
assert observation.voting_open is True
assert "Voting is already open" in observation.message_log[-1]
def test_false_self_location_claim_gets_hallucination_penalty() -> None:
engine = AmongUsEngine(seed=1, impostor_ids=["blue"])
engine.reset()
engine.step(CallMeeting())
observation = engine.step(Speak(message="I was in Electrical"))
assert observation.reward == -1.0
assert observation.claims[-1].truth_value is False
def test_single_vote_without_bot_support_ejects_nobody() -> None:
engine = AmongUsEngine(seed=1, impostor_ids=["blue"])
engine.reset()
engine.step(CallMeeting())
engine.step(PassMeeting())
observation = engine.step(Vote(target_id="blue"))
assert observation.reward == 0.0
assert engine.players["blue"].ejected is False
assert observation.done is False
assert "No majority" in observation.message_log[-1]
def test_bot_votes_eject_speaker_caught_in_false_alibi() -> None:
engine = AmongUsEngine(seed=1, impostor_ids=["blue"])
engine.reset()
engine.step(CallMeeting())
engine.step(Speak(message="I was in Electrical"))
observation = engine.step(Vote(target_id="blue"))
assert engine.players["red"].ejected is True
assert observation.reward == -0.5
assert "Ejected red" in observation.message_log[-1]
def test_majority_voting_tie_ejects_nobody() -> None:
engine = AmongUsEngine(seed=1, impostor_ids=["blue"], player_ids=["red", "blue", "green"])
engine.reset()
engine.step(CallMeeting())
engine.step(PassMeeting())
observation = engine.step(Vote(target_id="blue"))
assert engine.players["blue"].ejected is False
assert observation.phase is Phase.TASKS
assert "No majority" in observation.message_log[-1]
def test_impostors_win_when_they_reach_parity() -> None:
engine = AmongUsEngine(seed=1, impostor_ids=["red"], player_ids=["red", "blue", "green"])
engine.reset()
observation = engine.step(Kill(target_id="blue"))
assert observation.done is True
assert observation.winner is Winner.IMPOSTORS
assert observation.reward == 1.5