diff --git a/examples/werewolf_game/roles/human_player.py b/examples/werewolf_game/roles/human_player.py new file mode 100644 index 000000000..8b04ae821 --- /dev/null +++ b/examples/werewolf_game/roles/human_player.py @@ -0,0 +1,40 @@ +from examples.werewolf_game.actions import Speak +from examples.werewolf_game.roles import BasePlayer +from metagpt.schema import Message +from metagpt.logs import logger + +async def _act(self): + todo = self._rc.todo + + memories = self.get_all_memories() + + input_instruction = f""" + ## As a reminder, you have access to the following game history: + {memories} + ## You are {self.name}({self.profile}) + ## Guidance: + 1. If you are performing a special action or exercising a vote, + end your response with "PlayerX" where X is the player index, e.g., "..., kill/protect/poison/.../vote Player1". + 2. If it is a daytime free speech, you can speak in whatever format. + Now, please speak: + """ + rsp = input(input_instruction) # wait for human input + + msg_cause_by = type(todo) + msg_restricted_to = "" if isinstance(todo, Speak) \ + else f"Moderator,{self.profile}" + + msg = Message( + content=rsp, role=self.profile, sent_from=self.name, + cause_by=msg_cause_by, send_to="", + restricted_to=msg_restricted_to, # 给Moderator及自身阵营发送加密消息 + ) + + logger.info(f"{self._setting}: {rsp}") + + return msg + +def prepare_human_player(player_class: BasePlayer): + # Dynamically define a human player class that inherits from a certain role class + HumanPlayer = type('HumanPlayer', (player_class,), {'_act': _act}) + return HumanPlayer diff --git a/examples/werewolf_game/roles/seer.py b/examples/werewolf_game/roles/seer.py index 3d9bdf92e..1d58b70bf 100644 --- a/examples/werewolf_game/roles/seer.py +++ b/examples/werewolf_game/roles/seer.py @@ -35,7 +35,7 @@ class Seer(BasePlayer): msg = Message( content=rsp, role=self.profile, sent_from=self.name, cause_by=Verify, send_to="", - restricted_to="Moderator", + restricted_to=f"Moderator,{self.profile}", ) logger.info(f"{self._setting}: {rsp}") diff --git a/examples/werewolf_game/start_game.py b/examples/werewolf_game/start_game.py index 541066117..12552452c 100644 --- a/examples/werewolf_game/start_game.py +++ b/examples/werewolf_game/start_game.py @@ -3,10 +3,12 @@ import platform import fire import random +from metagpt.logs import logger from examples.werewolf_game.werewolf_game import WerewolfGame from examples.werewolf_game.roles import Moderator, Villager, Werewolf, Guard, Seer, Witch +from examples.werewolf_game.roles.human_player import prepare_human_player -def init_game_setup(shuffle=False): +def init_game_setup(shuffle=True, add_human=False): roles = [ Villager, Villager, @@ -17,29 +19,39 @@ def init_game_setup(shuffle=False): Witch ] if shuffle: - random.seed(2023) + # random.seed(2023) random.shuffle(roles) + if add_human: + assigned_role_idx = random.randint(0, len(roles) - 1) + assigned_role = roles[assigned_role_idx] + roles[assigned_role_idx] = prepare_human_player(assigned_role) + players = [role(name=f"Player{i+1}") for i, role in enumerate(roles)] + + if add_human: + logger.info(f"You are assigned {players[assigned_role_idx].name}({players[assigned_role_idx].profile})") + game_setup = ["Game setup:"] + [f"{player.name}: {player.profile}," for player in players] game_setup = "\n".join(game_setup) + return game_setup, players -async def start_game(investment: float = 3.0, n_round: int = 5): +async def start_game(investment: float = 3.0, n_round: int = 5, shuffle : bool = True, add_human: bool = False): game = WerewolfGame() - game_setup, players = init_game_setup(shuffle=True) + game_setup, players = init_game_setup(shuffle=shuffle, add_human=add_human) players = [Moderator()] + players game.hire(players) game.invest(investment) game.start_project(game_setup) await game.run(n_round=n_round) -def main(investment: float = 3.0, n_round: int = 100): +def main(investment: float = 3.0, n_round: int = 100, shuffle : bool = True, add_human: bool = False): """ :param investment: contribute a certain dollar amount to watch the debate :param n_round: maximum rounds of the debate :return: """ - asyncio.run(start_game(investment, n_round)) + asyncio.run(start_game(investment, n_round, shuffle, add_human)) if __name__ == '__main__':