From 0c238d2b0d04aaf0bd533ff765d117792fcadf1d Mon Sep 17 00:00:00 2001 From: yzlin Date: Mon, 9 Oct 2023 14:36:55 +0800 Subject: [PATCH] update win mechanism --- .../actions/moderator_actions.py | 18 ++++++------- examples/werewolf_game/roles/moderator.py | 25 ++++++++++++++----- 2 files changed, 28 insertions(+), 15 deletions(-) diff --git a/examples/werewolf_game/actions/moderator_actions.py b/examples/werewolf_game/actions/moderator_actions.py index fc897474e..c0b540a44 100644 --- a/examples/werewolf_game/actions/moderator_actions.py +++ b/examples/werewolf_game/actions/moderator_actions.py @@ -65,13 +65,13 @@ STEP_INSTRUCTIONS = { 15: {"content": "{player_current_dead} was killed last night!", "send_to": "Moderator", "restricted_to": ""}, - 16: {"content": """Now freely talk about roles of other players with each other based on your observation and - reflection with few sentences. Decide whether to reveal your identity based on your reflection.""", + 16: {"content": """Living players: {living_players}, now freely talk about the current situation based on your observation and + reflection with a few sentences. Decide whether to reveal your identity based on your reflection.""", "send_to": "", # send to all to speak in daytime "restricted_to": ""}, 17: {"content": """Now vote and tell me who you think is the werewolf. Don’t mention your role. You only choose one from the following living options please: - {living_players}. Or you can pass. For example: I vote to kill ...""", + {living_players}. Say ONLY: I vote to eliminate ...""", "send_to": "", "restricted_to": ""}, 18: {"content": """{player_current_dead} was eliminated.""", @@ -91,12 +91,12 @@ class InstructSpeak(Action): }) content = instruction_info["content"] if "{living_players}" in content and "{werewolf_players}" in content: - content = content.format(living_players=",".join(living_players), - werewolf_players=",".join(werewolf_players)) + content = content.format(living_players=living_players, + werewolf_players=werewolf_players) if "{living_players}" in content: - content = content.format(living_players=",".join(living_players)) + content = content.format(living_players=living_players) if "{werewolf_players}" in content: - content = content.format(werewolf_players=",".join(werewolf_players)) + content = content.format(werewolf_players=werewolf_players) if "{player_hunted}" in content: content = content.format(player_hunted=player_hunted) if "{player_current_dead}" in content: @@ -140,8 +140,8 @@ class SummarizeDay(Action): class AnnounceGameResult(Action): - async def run(self, winner: str): - return f"Game over! The winner is the {winner}" + async def run(self, winner: str, win_reason: str): + return f"Game over! {win_reason}. The winner is the {winner}" async def main(): rst1 = await SummarizeDay().run({"Player1": 0, "Player2": 0, "Player3": 0, "Player4": 0}) diff --git a/examples/werewolf_game/roles/moderator.py b/examples/werewolf_game/roles/moderator.py index 95af332db..f4bad6c96 100644 --- a/examples/werewolf_game/roles/moderator.py +++ b/examples/werewolf_game/roles/moderator.py @@ -24,12 +24,15 @@ class Moderator(Role): self._watch([UserRequirement, InstructSpeak, ParseSpeak]) self._init_actions([InstructSpeak, ParseSpeak, AnnounceGameResult]) self.step_idx = 0 + self.eval_step_idx = [] # game states self.living_players = [] self.werewolf_players = [] - self.good_guys = [] + self.villager_players = [] + self.special_role_players = [] self.winner = None + self.win_reason = None self.witch_poison_left = 1 self.witch_antidote_left = 1 @@ -44,7 +47,10 @@ class Moderator(Role): self.living_players = re.findall(r"Player[0-9]+", game_setup) self.werewolf_players = re.findall(r"Player[0-9]+: Werewolf", game_setup) self.werewolf_players = [p.replace(": Werewolf", "") for p in self.werewolf_players] - self.good_guys = [p for p in self.living_players if p not in self.werewolf_players] + self.villager_players = re.findall(r"Player[0-9]+: Villager", game_setup) + self.villager_players = [p.replace(": Villager", "") for p in self.villager_players] + self.special_role_players = [p for p in self.living_players \ + if p not in self.werewolf_players + self.villager_players] def update_player_status(self, player_names: list[str]): if not player_names: @@ -114,8 +120,10 @@ class Moderator(Role): def _update_game_states(self, memories): step_idx = self.step_idx % len(STEP_INSTRUCTIONS) - if step_idx not in [15, 18]: # FIXME: hard code + if step_idx not in [15, 18] or self.step_idx in self.eval_step_idx: # FIXME: hard code return + else: + self.eval_step_idx.append(self.step_idx) # record evaluation, avoid repetitive evaluation at the same step if step_idx == 15: # FIXME: hard code # night ends: after all special roles acted, process the whole night @@ -135,6 +143,7 @@ class Moderator(Role): self.player_poisoned = None elif step_idx == 18: # FIXME: hard code + print("*" * 10, step_idx) # day ends: after all roles voted, process all votings voting_msgs = memories[-len(self.living_players):] voted_all = [] @@ -144,16 +153,20 @@ class Moderator(Role): continue voted_all.append(voted.group(0)) self.player_current_dead = [Counter(voted_all).most_common()[0][0]] # 平票时,杀序号小的 + # print("*" * 10, "dead", self.player_current_dead) self.living_players = [p for p in self.living_players if p not in self.player_current_dead] self.update_player_status(self.player_current_dead) # game's termination condition living_werewolf = [p for p in self.werewolf_players if p in self.living_players] - living_good_guys = [p for p in self.good_guys if p in self.living_players] + living_villagers = [p for p in self.villager_players if p in self.living_players] + living_special_roles = [p for p in self.special_role_players if p in self.living_players] if not living_werewolf: self.winner = "good guys" - elif not living_good_guys: + self.win_reason = "werewolves all dead" + elif not living_villagers or not living_special_roles: self.winner = "werewolf" + self.win_reason = "villagers all dead" if not living_villagers else "special roles all dead" def _record_game_history(self): if self.step_idx % len(STEP_INSTRUCTIONS) == 0 or self.winner is not None: @@ -210,7 +223,7 @@ class Moderator(Role): cause_by=ParseSpeak, send_to="", restricted_to=msg_restriced_to) elif isinstance(todo, AnnounceGameResult): - msg_content = await AnnounceGameResult().run(winner=self.winner) + msg_content = await AnnounceGameResult().run(winner=self.winner, win_reason=self.win_reason) msg = Message(content=msg_content, role=self.profile, sent_from=self.name, cause_by=AnnounceGameResult) logger.info(f"{self._setting}: {msg_content}")