| from __future__ import annotations |
|
|
| from enum import Enum |
| from typing import Annotated, Literal, Optional, Union |
|
|
| from pydantic import BaseModel, ConfigDict, Field, TypeAdapter |
|
|
|
|
| class StrictModel(BaseModel): |
| model_config = ConfigDict(extra="forbid", use_enum_values=False) |
|
|
|
|
| class PlayerRole(str, Enum): |
| CREWMATE = "crewmate" |
| IMPOSTOR = "impostor" |
|
|
|
|
| class Phase(str, Enum): |
| TASKS = "tasks" |
| MEETING = "meeting" |
| COMPLETE = "complete" |
|
|
|
|
| class Winner(str, Enum): |
| CREWMATES = "crewmates" |
| IMPOSTORS = "impostors" |
|
|
|
|
| class ClaimKind(str, Enum): |
| SELF_LOCATION = "self_location" |
| SAW_PLAYER = "saw_player" |
|
|
|
|
| class Move(StrictModel): |
| type: Literal["move"] = "move" |
| room: str |
|
|
|
|
| class CompleteTask(StrictModel): |
| type: Literal["complete_task"] = "complete_task" |
|
|
|
|
| class Kill(StrictModel): |
| type: Literal["kill"] = "kill" |
| target_id: str |
|
|
|
|
| class ReportBody(StrictModel): |
| type: Literal["report_body"] = "report_body" |
|
|
|
|
| class CallMeeting(StrictModel): |
| type: Literal["call_meeting"] = "call_meeting" |
|
|
|
|
| class Vote(StrictModel): |
| type: Literal["vote"] = "vote" |
| target_id: str |
|
|
|
|
| class Speak(StrictModel): |
| type: Literal["speak"] = "speak" |
| message: str |
|
|
|
|
| class PassMeeting(StrictModel): |
| type: Literal["pass"] = "pass" |
|
|
|
|
| Action = Annotated[ |
| Union[ |
| Move, |
| CompleteTask, |
| Kill, |
| ReportBody, |
| CallMeeting, |
| Vote, |
| Speak, |
| PassMeeting, |
| ], |
| Field(discriminator="type"), |
| ] |
| ActionAdapter = TypeAdapter(Action) |
|
|
|
|
| class TaskState(StrictModel): |
| room: str |
| name: str |
| completed: bool = False |
|
|
|
|
| class VisiblePlayer(StrictModel): |
| player_id: str |
| location: str |
| alive: bool = True |
|
|
|
|
| class Claim(StrictModel): |
| kind: ClaimKind |
| speaker_id: str |
| room: str |
| truth_value: bool |
| target_id: Optional[str] = None |
|
|
|
|
| class Observation(StrictModel): |
| role: PlayerRole |
| location: str |
| visible_players: list[Union[str, VisiblePlayer]] |
| task_list: list[TaskState] |
| message_log: list[str] |
| discussion_log: list[str] = Field(default_factory=list) |
| claims: list[Claim] = Field(default_factory=list) |
| phase: Phase |
| reward: float = 0.0 |
| done: bool = False |
| winner: Optional[Winner] = None |
| voting_open: bool = False |
| meeting_turns_remaining: int = 0 |
|
|
|
|
| class PlayerState(StrictModel): |
| player_id: str |
| role: PlayerRole |
| location: str |
| alive: bool = True |
| ejected: bool = False |
|
|
|
|
| class GameConfig(StrictModel): |
| seed: int = 0 |
| controlled_player_id: str = "red" |
| player_ids: list[str] = Field( |
| default_factory=lambda: ["red", "blue", "green", "yellow"] |
| ) |
|
|