Skip to content

Game Builders

This is the code reference for the Game Builder API and classes.

open_mafia_engine.core.builder

GameBuilder

Specification for a Game Builder.

TODO: Allow lazy loading of specs, somehow.

available() -> List[str] classmethod

Returns the names of available builders.

Source code in core/builder.py
@classmethod
def available(cls) -> List[str]:
    """Returns the names of available builders."""
    global __builders__
    return list(__builders__.keys())

build(self, player_names: List[str], *args, **kwargs) -> Game

Builds the game based on passed players and other options.

Source code in core/builder.py
def build(self, player_names: List[str], *args, **kwargs) -> Game:
    """Builds the game based on passed players and other options."""
    return self.func(player_names, *args, **kwargs)

load(name: str) -> GameBuilder classmethod

Load a spec by exact or closest name.

Source code in core/builder.py
@classmethod
def load(cls, name: str) -> GameBuilder:
    """Load a spec by exact or closest name."""
    global __builders__
    matcher = FuzzyMatcher(__builders__, score_cutoff=10)
    return matcher[name]

game_builder(name: str = None) -> Callable[[_GameBuilderFunc], _GameBuilderFunc]

Decorator factor for game builders.

Source code in core/builder.py
def game_builder(name: str = None) -> Callable[[_GameBuilderFunc], _GameBuilderFunc]:
    """Decorator factor for game builders."""

    def inner(func: _GameBuilderFunc) -> _GameBuilderFunc:
        nonlocal name

        if name is None:
            name = func.__qualname__
        GameBuilder(func, name=name)

        return func

    return inner

open_mafia_engine.builders.for_testing

make_test_game(player_names: List[str], n_mafia: int = 1) -> Game

Game builder for testing purposes.

Always assigns mafia, then non-mafia, in player name order. Must be at least 2 players (1 mafia, 1 town).

Parameters

n_mafia : int = 1 How many mafia players to add.

Source code in builders/for_testing.py
@game_builder("test")
def make_test_game(player_names: List[str], n_mafia: int = 1) -> Game:
    """Game builder for testing purposes.

    Always assigns mafia, then non-mafia, in player name order.
    Must be at least 2 players (1 mafia, 1 town).

    Parameters
    ----------
    n_mafia : int = 1
        How many mafia players to add.
    """

    n_mafia = int(n_mafia)

    n = len(player_names)
    assert isinstance(n_mafia, int)
    assert n_mafia > 0
    assert n > n_mafia

    game = Game()
    mafia = Faction(game, "Mafia")
    OCLastFactionStanding(game, mafia)
    FactionChatCreatorAux(game, mafia)

    town = Faction(game, "Town")
    OCLastFactionStanding(game, town)

    # Aux objects
    GameEnder(game)  # ends the game when all factions get an Outcome
    tally = LynchTally(game)  # lynch tally

    n_town = n - n_mafia

    vote_desc = "Vote for your target. This is a free action."

    for i in range(n_mafia):
        act = Actor(game, player_names[i])
        mafia.add_actor(act)
        # Voting
        vote = VoteAbility(game, act, name="Vote", tally=tally, desc=vote_desc)
        PhaseConstraint(game, vote, phase="day")
        # Mafia kill
        mk = KillAbility(
            game,
            act,
            name="Mafia Kill",
            desc="Kill the target. Only 1 mafioso can use this.",
        )
        LimitPerPhaseActorConstraint(game, mk, limit=1)
        LimitPerPhaseKeyConstraint(game, mk, key="mafia_kill_limit")
        PhaseConstraint(game, mk, phase="night")
        ConstraintNoSelfFactionTarget(game, mk)
        if i == 2:
            # Second mafioso can roleblock
            block = RoleBlockAbility(
                game,
                act,
                name="Roleblock",
                desc="Blocks the target from acting this night.",
            )
            PhaseConstraint(game, block, phase="night")
            LimitPerPhaseActorConstraint(game, block, limit=1)
            ConstraintNoSelfFactionTarget(game, block)

    for i in range(n_town):
        act = Actor(game, player_names[n_mafia + i])
        town.add_actor(act)
        # Voting
        vote = VoteAbility(game, act, name="Vote", tally=tally, desc=vote_desc)
        PhaseConstraint(game, vote, phase="day")
        if i == 1:
            # Second townie is a protector/doctor
            prot = ProtectFromKillAbility(game, act, name="Protect")
            PhaseConstraint(game, prot, phase="night")
            LimitPerPhaseActorConstraint(game, prot, limit=1)
            ConstraintNoSelfTarget(game, prot)
        elif i == 2:
            # Third townie is a detective
            insp = InspectFactionAbility(game, act, name="Faction Inspect")
            LimitPerPhaseActorConstraint(game, insp, limit=1)
            PhaseConstraint(game, insp, phase="night")
            ConstraintNoSelfTarget(game, insp)
            pass
        elif i == 3:
            # Fourth townie is a redirector
            redir = CreateRedirectAbility(game, act, name="Redirect")
            LimitPerPhaseActorConstraint(game, redir, limit=1)
            PhaseConstraint(game, redir, phase="night")
        # TODO: Other abilities

    return game