This commit is contained in:
CakeCN
2024-12-03 16:21:19 +08:00
commit 4198ca63b1
975 changed files with 333413 additions and 0 deletions

View File

@@ -0,0 +1,81 @@
# Werewolf Game in AgentScope
This example demonstrates how to use AgentScope to play the Werewolf game, where six agents play against each other as werewolves and villagers.
You will learn the following features in AgentScope:
- How to make an agent respond with **different specified fields** in **different situations** in AgentScope (Like a finite state machine!)
- How to use **msghub** and **pipeline** in AgentScope to construct a game with **COMPLEX SOP**
## Background
The werewolf game involves a complex SOP with multiple roles and different phases. In these phases, players with different roles should take different actions, e.g. discussion, voting, checking roles (seer), using potions (witch), and so on.
Therefore, for an agent in werewolf game, it should be able to switch its status according to the game phase and its role, and respond accordingly.
Of course, we can hard code the SOP (or finite state machine) within the agent, but we expect the agent to be more **flexible**, **intelligent**, and **adaptive**, which means **the agent shouldn't be designed for a specific game only**. It should be able to adapt to different tasks and SOPs!
To achieve this goal, in AgentScope, we use a built-in [DictDialogAgent](https://github.com/modelscope/agentscope/blob/main/src/agentscope/agents/dict_dialog_agent.py) class, together with a [parser](https://modelscope.github.io/agentscope/en/tutorial/203-parser.html) module to construct the werewolf game.
Moreover, the [pipeline and msghub](https://modelscope.github.io/agentscope/en/tutorial/202-pipeline.html) in AgentScope enable us to easily construct a complex SOP with multiple agents. We hope the implementation is concise, clear and readable!
More details please refer to our tutorial:
- [Parser](https://modelscope.github.io/agentscope/en/tutorial/203-parser.html)
- [Pipeline and msghub](https://modelscope.github.io/agentscope/en/tutorial/202-pipeline.html)
https://github.com/DavdGao/AgentScope/assets/102287034/86951418-e1cc-486b-a3dc-b237a0108994
## Tested Models
This example has been tested with the following models:
- dashscope_chat (qwen-turbo)
- ollama_chat (llama3_8b)
## Prerequisites
To run this example, you need to:
- Set your API key in `./configs/model_configs.json`
[Optional] To play the game in person, see [werewolf.py](werewolf.py) for the complete code.
## Code Snippets
### About Pipeline and MsgHub
The following code is the implementation of daytime discussion in Werewolf. With msghub and pipeline, it's very easy to program a discussion among agents.
```python
# ...
with msghub(survivors, announcement=hints) as hub:
# discuss
set_parsers(survivors, Prompts.survivors_discuss_parser)
x = sequentialpipeline(survivors)
# ...
```
### About Parser
The parser is used to specify the required fields in the agent's response and how to handle them. Here's an example of a parser configuration:
```python
to_wolves_vote = "Which player do you vote to kill?"
wolves_vote_parser = MarkdownJsonDictParser(
content_hint={
"thought": "what you thought",
"vote": "player_name",
},
required_keys=["thought", "vote"],
keys_to_memory="vote",
keys_to_content="vote",
)
```
In this example, the `MarkdownJsonDictParser` is used to parse the agent's response. The `content_hint` parameter specifies the expected fields and their descriptions. The `required_keys` parameter indicates the mandatory fields in the response. The `keys_to_memory` and `keys_to_content` parameters determine which fields should be stored in memory and included in the content of the returned message, respectively.

View File

@@ -0,0 +1,56 @@
[
{
"class": "DictDialogAgent",
"args": {
"name": "Player1",
"sys_prompt": "Act as a player in a werewolf game. You are Player1 and\nthere are totally 6 players, named Player1, Player2, Player3, Player4, Player5 and Player6.\n\nPLAYER ROLES:\nIn werewolf game, players are divided into two werewolves, two villagers, one seer and one witch. Note only werewolves know who are their teammates.\nWerewolves: They know their teammates' identities and attempt to eliminate a villager each night while trying to remain undetected.\nVillagers: They do not know who the werewolves are and must work together during the day to deduce who the werewolves might be and vote to eliminate them.\nSeer: A villager with the ability to learn the true identity of one player each night. This role is crucial for the villagers to gain information.\nWitch: A character who has a one-time ability to save a player from being eliminated at night (sometimes this is a potion of life) and a one-time ability to eliminate a player at night (a potion of death).\n\nGAME RULE:\nThe game is consisted of two phases: night phase and day phase. The two phases are repeated until werewolf or villager win the game.\n1. Night Phase: During the night, the werewolves discuss and vote for a player to eliminate. Special roles also perform their actions at this time (e.g., the Seer chooses a player to learn their role, the witch chooses a decide if save the player).\n2. Day Phase: During the day, all surviving players discuss who they suspect might be a werewolf. No one reveals their role unless it serves a strategic purpose. After the discussion, a vote is taken, and the player with the most votes is \"lynched\" or eliminated from the game.\n\nVICTORY CONDITION:\nFor werewolves, they win the game if the number of werewolves is equal to or greater than the number of remaining villagers.\nFor villagers, they win if they identify and eliminate all of the werewolves in the group.\n\nCONSTRAINTS:\n1. Your response should be in the first person.\n2. This is a conversational game. You should response only based on the conversation history and your strategy.\n\nYou are playing werewolf in this game.\n",
"model_config_name": "gpt-4",
"use_memory": true
}
},
{
"class": "DictDialogAgent",
"args": {
"name": "Player2",
"sys_prompt": "Act as a player in a werewolf game. You are Player2 and\nthere are totally 6 players, named Player1, Player2, Player3, Player4, Player5 and Player6.\n\nPLAYER ROLES:\nIn werewolf game, players are divided into two werewolves, two villagers, one seer and one witch. Note only werewolves know who are their teammates.\nWerewolves: They know their teammates' identities and attempt to eliminate a villager each night while trying to remain undetected.\nVillagers: They do not know who the werewolves are and must work together during the day to deduce who the werewolves might be and vote to eliminate them.\nSeer: A villager with the ability to learn the true identity of one player each night. This role is crucial for the villagers to gain information.\nWitch: A character who has a one-time ability to save a player from being eliminated at night (sometimes this is a potion of life) and a one-time ability to eliminate a player at night (a potion of death).\n\nGAME RULE:\nThe game is consisted of two phases: night phase and day phase. The two phases are repeated until werewolf or villager win the game.\n1. Night Phase: During the night, the werewolves discuss and vote for a player to eliminate. Special roles also perform their actions at this time (e.g., the Seer chooses a player to learn their role, the witch chooses a decide if save the player).\n2. Day Phase: During the day, all surviving players discuss who they suspect might be a werewolf. No one reveals their role unless it serves a strategic purpose. After the discussion, a vote is taken, and the player with the most votes is \"lynched\" or eliminated from the game.\n\nVICTORY CONDITION:\nFor werewolves, they win the game if the number of werewolves is equal to or greater than the number of remaining villagers.\nFor villagers, they win if they identify and eliminate all of the werewolves in the group.\n\nCONSTRAINTS:\n1. Your response should be in the first person.\n2. This is a conversational game. You should response only based on the conversation history and your strategy.\n\nYou are playing werewolf in this game.\n",
"model_config_name": "gpt-4",
"use_memory": true
}
},
{
"class": "DictDialogAgent",
"args": {
"name": "Player3",
"sys_prompt": "Act as a player in a werewolf game. You are Player3 and\nthere are totally 6 players, named Player1, Player2, Player3, Player4, Player5 and Player6.\n\nPLAYER ROLES:\nIn werewolf game, players are divided into two werewolves, two villagers, one seer and one witch. Note only werewolves know who are their teammates.\nWerewolves: They know their teammates' identities and attempt to eliminate a villager each night while trying to remain undetected.\nVillagers: They do not know who the werewolves are and must work together during the day to deduce who the werewolves might be and vote to eliminate them.\nSeer: A villager with the ability to learn the true identity of one player each night. This role is crucial for the villagers to gain information.\nWitch: A character who has a one-time ability to save a player from being eliminated at night (sometimes this is a potion of life) and a one-time ability to eliminate a player at night (a potion of death).\n\nGAME RULE:\nThe game is consisted of two phases: night phase and day phase. The two phases are repeated until werewolf or villager win the game.\n1. Night Phase: During the night, the werewolves discuss and vote for a player to eliminate. Special roles also perform their actions at this time (e.g., the Seer chooses a player to learn their role, the witch chooses a decide if save the player).\n2. Day Phase: During the day, all surviving players discuss who they suspect might be a werewolf. No one reveals their role unless it serves a strategic purpose. After the discussion, a vote is taken, and the player with the most votes is \"lynched\" or eliminated from the game.\n\nVICTORY CONDITION:\nFor werewolves, they win the game if the number of werewolves is equal to or greater than the number of remaining villagers.\nFor villagers, they win if they identify and eliminate all of the werewolves in the group.\n\nCONSTRAINTS:\n1. Your response should be in the first person.\n2. This is a conversational game. You should response only based on the conversation history and your strategy.\n\nYou are playing villager in this game.\n",
"model_config_name": "gpt-4",
"use_memory": true
}
},
{
"class": "DictDialogAgent",
"args": {
"name": "Player4",
"sys_prompt": "Act as a player in a werewolf game. You are Player4 and\nthere are totally 6 players, named Player1, Player2, Player3, Player4, Player5 and Player6.\n\nPLAYER ROLES:\nIn werewolf game, players are divided into two werewolves, two villagers, one seer and one witch. Note only werewolves know who are their teammates.\nWerewolves: They know their teammates' identities and attempt to eliminate a villager each night while trying to remain undetected.\nVillagers: They do not know who the werewolves are and must work together during the day to deduce who the werewolves might be and vote to eliminate them.\nSeer: A villager with the ability to learn the true identity of one player each night. This role is crucial for the villagers to gain information.\nWitch: A character who has a one-time ability to save a player from being eliminated at night (sometimes this is a potion of life) and a one-time ability to eliminate a player at night (a potion of death).\n\nGAME RULE:\nThe game is consisted of two phases: night phase and day phase. The two phases are repeated until werewolf or villager win the game.\n1. Night Phase: During the night, the werewolves discuss and vote for a player to eliminate. Special roles also perform their actions at this time (e.g., the Seer chooses a player to learn their role, the witch chooses a decide if save the player).\n2. Day Phase: During the day, all surviving players discuss who they suspect might be a werewolf. No one reveals their role unless it serves a strategic purpose. After the discussion, a vote is taken, and the player with the most votes is \"lynched\" or eliminated from the game.\n\nVICTORY CONDITION:\nFor werewolves, they win the game if the number of werewolves is equal to or greater than the number of remaining villagers.\nFor villagers, they win if they identify and eliminate all of the werewolves in the group.\n\nCONSTRAINTS:\n1. Your response should be in the first person.\n2. This is a conversational game. You should response only based on the conversation history and your strategy.\n\nYou are playing villager in this game.\n",
"model_config_name": "gpt-4",
"use_memory": true
}
},
{
"class": "DictDialogAgent",
"args": {
"name": "Player5",
"sys_prompt": "Act as a player in a werewolf game. You are Player5 and\nthere are totally 6 players, named Player1, Player2, Player3, Player4, Player5 and Player6.\n\nPLAYER ROLES:\nIn werewolf game, players are divided into two werewolves, two villagers, one seer and one witch. Note only werewolves know who are their teammates.\nWerewolves: They know their teammates' identities and attempt to eliminate a villager each night while trying to remain undetected.\nVillagers: They do not know who the werewolves are and must work together during the day to deduce who the werewolves might be and vote to eliminate them.\nSeer: A villager with the ability to learn the true identity of one player each night. This role is crucial for the villagers to gain information.\nWitch: A character who has a one-time ability to save a player from being eliminated at night (sometimes this is a potion of life) and a one-time ability to eliminate a player at night (a potion of death).\n\nGAME RULE:\nThe game is consisted of two phases: night phase and day phase. The two phases are repeated until werewolf or villager win the game.\n1. Night Phase: During the night, the werewolves discuss and vote for a player to eliminate. Special roles also perform their actions at this time (e.g., the Seer chooses a player to learn their role, the witch chooses a decide if save the player).\n2. Day Phase: During the day, all surviving players discuss who they suspect might be a werewolf. No one reveals their role unless it serves a strategic purpose. After the discussion, a vote is taken, and the player with the most votes is \"lynched\" or eliminated from the game.\n\nVICTORY CONDITION:\nFor werewolves, they win the game if the number of werewolves is equal to or greater than the number of remaining villagers.\nFor villagers, they win if they identify and eliminate all of the werewolves in the group.\n\nCONSTRAINTS:\n1. Your response should be in the first person.\n2. This is a conversational game. You should response only based on the conversation history and your strategy.\n\nYou are playing seer in this game.\n",
"model_config_name": "gpt-4",
"use_memory": true
}
},
{
"class": "DictDialogAgent",
"args": {
"name": "Player6",
"sys_prompt": "Act as a player in a werewolf game. You are Player6 and\nthere are totally 6 players, named Player1, Player2, Player3, Player4, Player5 and Player6.\n\nPLAYER ROLES:\nIn werewolf game, players are divided into two werewolves, two villagers, one seer and one witch. Note only werewolves know who are their teammates.\nWerewolves: They know their teammates' identities and attempt to eliminate a villager each night while trying to remain undetected.\nVillagers: They do not know who the werewolves are and must work together during the day to deduce who the werewolves might be and vote to eliminate them.\nSeer: A villager with the ability to learn the true identity of one player each night. This role is crucial for the villagers to gain information.\nWitch: A character who has a one-time ability to save a player from being eliminated at night (sometimes this is a potion of life) and a one-time ability to eliminate a player at night (a potion of death).\n\nGAME RULE:\nThe game is consisted of two phases: night phase and day phase. The two phases are repeated until werewolf or villager win the game.\n1. Night Phase: During the night, the werewolves discuss and vote for a player to eliminate. Special roles also perform their actions at this time (e.g., the Seer chooses a player to learn their role, the witch chooses a decide if save the player).\n2. Day Phase: During the day, all surviving players discuss who they suspect might be a werewolf. No one reveals their role unless it serves a strategic purpose. After the discussion, a vote is taken, and the player with the most votes is \"lynched\" or eliminated from the game.\n\nVICTORY CONDITION:\nFor werewolves, they win the game if the number of werewolves is equal to or greater than the number of remaining villagers.\nFor villagers, they win if they identify and eliminate all of the werewolves in the group.\n\nCONSTRAINTS:\n1. Your response should be in the first person.\n2. This is a conversational game. You should response only based on the conversation history and your strategy.\n\nYou are playing witch in this game.\n",
"model_config_name": "gpt-4",
"use_memory": true
}
}
]

View File

@@ -0,0 +1,19 @@
[
{
"model_type": "openai_chat",
"config_name": "gpt-4",
"model_name": "gpt-4",
"api_key": "xxx",
"organization": "xxx",
"generate_args": {
"temperature": 0.5
}
},
{
"model_type": "post_api_chat",
"config_name": "my_post_api",
"api_url": "https://xxx",
"headers": {},
"json_args": {}
}
]

View File

@@ -0,0 +1,152 @@
# -*- coding: utf-8 -*-
"""Used to record prompts, will be replaced by configuration"""
from agentscope.parsers.json_object_parser import MarkdownJsonDictParser
class Prompts:
"""Prompts for werewolf game"""
to_wolves = (
"{}, if you are the only werewolf, eliminate a player. Otherwise, "
"discuss with your teammates and reach an agreement."
)
wolves_discuss_parser = MarkdownJsonDictParser(
content_hint={
"thought": "what you thought",
"speak": "what you speak",
"finish_discussion": "whether the discussion reached an "
"agreement or not (true/false)",
},
required_keys=["thought", "speak", "finish_discussion"],
keys_to_memory="speak",
keys_to_content="speak",
keys_to_metadata=["finish_discussion"],
)
to_wolves_vote = "Which player do you vote to kill?"
wolves_vote_parser = MarkdownJsonDictParser(
content_hint={
"thought": "what you thought",
"vote": "player_name",
},
required_keys=["thought", "vote"],
keys_to_memory="vote",
keys_to_content="vote",
)
to_wolves_res = "The player with the most votes is {}."
to_witch_resurrect = (
"{witch_name}, you're the witch. Tonight {dead_name} is eliminated. "
"Would you like to resurrect {dead_name}?"
)
to_witch_resurrect_no = "The witch has chosen not to resurrect the player."
to_witch_resurrect_yes = "The witch has chosen to resurrect the player."
witch_resurrect_parser = MarkdownJsonDictParser(
content_hint={
"thought": "what you thought",
"speak": "whether to resurrect the player and the reason",
"resurrect": "whether to resurrect the player or not (true/false)",
},
required_keys=["thought", "speak", "resurrect"],
keys_to_memory="speak",
keys_to_content="speak",
keys_to_metadata=["resurrect"],
)
to_witch_poison = (
"Would you like to eliminate one player? If yes, "
"specify the player_name."
)
witch_poison_parser = MarkdownJsonDictParser(
content_hint={
"thought": "what you thought",
"speak": "what you speak",
"eliminate": "whether to eliminate a player or not (true/false)",
},
required_keys=["thought", "speak", "eliminate"],
keys_to_memory="speak",
keys_to_content="speak",
keys_to_metadata=["eliminate"],
)
to_seer = (
"{}, you're the seer. Which player in {} would you like to check "
"tonight?"
)
seer_parser = MarkdownJsonDictParser(
content_hint={
"thought": "what you thought",
"speak": "player_name",
},
required_keys=["thought", "speak"],
keys_to_memory="speak",
keys_to_content="speak",
)
to_seer_result = "Okay, the role of {} is a {}."
to_all_danger = (
"The day is coming, all the players open your eyes. Last night, "
"the following player(s) has been eliminated: {}."
)
to_all_peace = (
"The day is coming, all the players open your eyes. Last night is "
"peaceful, no player is eliminated."
)
to_all_discuss = (
"Now the alive players are {}. Given the game rules and your role, "
"based on the situation and the information you gain, to vote a "
"player eliminated among alive players and to win the game, what do "
"you want to say to others? You can decide whether to reveal your "
"role."
)
survivors_discuss_parser = MarkdownJsonDictParser(
content_hint={
"thought": "what you thought",
"speak": "what you speak",
},
required_keys=["thought", "speak"],
keys_to_memory="speak",
keys_to_content="speak",
)
survivors_vote_parser = MarkdownJsonDictParser(
content_hint={
"thought": "what you thought",
"vote": "player_name",
},
required_keys=["thought", "vote"],
keys_to_memory="vote",
keys_to_content="vote",
)
to_all_vote = (
"Given the game rules and your role, based on the situation and the"
" information you gain, to win the game, it's time to vote one player"
" eliminated among the alive players. Which player do you vote to "
"kill?"
)
to_all_res = "{} has been voted out."
to_all_wolf_win = (
"The werewolves have prevailed and taken over the village. Better "
"luck next time!"
)
to_all_village_win = (
"The game is over. The werewolves have been defeated, and the village "
"is safe once again!"
)
to_all_continue = "The game goes on."

View File

@@ -0,0 +1,149 @@
# -*- coding: utf-8 -*-
"""A werewolf game implemented by agentscope."""
from functools import partial
from prompt import Prompts
from werewolf_utils import (
check_winning,
update_alive_players,
majority_vote,
extract_name_and_id,
n2s,
set_parsers,
)
from agentscope.message import Msg
from agentscope.msghub import msghub
from agentscope.pipelines.functional import sequentialpipeline
import agentscope
# pylint: disable=too-many-statements
def main() -> None:
"""werewolf game"""
# default settings
HostMsg = partial(Msg, name="Moderator", role="assistant", echo=True)
healing, poison = True, True
MAX_WEREWOLF_DISCUSSION_ROUND = 3
MAX_GAME_ROUND = 6
# read model and agent configs, and initialize agents automatically
survivors = agentscope.init(
model_configs="./configs/model_configs.json",
agent_configs="./configs/agent_configs.json",
project="Werewolf",
)
roles = ["werewolf", "werewolf", "villager", "villager", "seer", "witch"]
wolves, witch, seer = survivors[:2], survivors[-1], survivors[-2]
# start the game
for _ in range(1, MAX_GAME_ROUND + 1):
# night phase, werewolves discuss
hint = HostMsg(content=Prompts.to_wolves.format(n2s(wolves)))
with msghub(wolves, announcement=hint) as hub:
set_parsers(wolves, Prompts.wolves_discuss_parser)
for _ in range(MAX_WEREWOLF_DISCUSSION_ROUND):
x = sequentialpipeline(wolves)
if x.metadata.get("finish_discussion", False):
break
# werewolves vote
set_parsers(wolves, Prompts.wolves_vote_parser)
hint = HostMsg(content=Prompts.to_wolves_vote)
votes = [
extract_name_and_id(wolf(hint).content)[0] for wolf in wolves
]
# broadcast the result to werewolves
dead_player = [majority_vote(votes)]
hub.broadcast(
HostMsg(content=Prompts.to_wolves_res.format(dead_player[0])),
)
# witch
healing_used_tonight = False
if witch in survivors:
if healing:
hint = HostMsg(
content=Prompts.to_witch_resurrect.format_map(
{
"witch_name": witch.name,
"dead_name": dead_player[0],
},
),
)
set_parsers(witch, Prompts.witch_resurrect_parser)
if witch(hint).metadata.get("resurrect", False):
healing_used_tonight = True
dead_player.pop()
healing = False
HostMsg(content=Prompts.to_witch_resurrect_yes)
else:
HostMsg(content=Prompts.to_witch_resurrect_no)
if poison and not healing_used_tonight:
set_parsers(witch, Prompts.witch_poison_parser)
x = witch(HostMsg(content=Prompts.to_witch_poison))
if x.metadata.get("eliminate", False):
dead_player.append(extract_name_and_id(x.content)[0])
poison = False
# seer
if seer in survivors:
hint = HostMsg(
content=Prompts.to_seer.format(seer.name, n2s(survivors)),
)
set_parsers(seer, Prompts.seer_parser)
x = seer(hint)
player, idx = extract_name_and_id(x.content)
role = "werewolf" if roles[idx] == "werewolf" else "villager"
hint = HostMsg(content=Prompts.to_seer_result.format(player, role))
seer.observe(hint)
survivors, wolves = update_alive_players(
survivors,
wolves,
dead_player,
)
if check_winning(survivors, wolves, "Moderator"):
break
# daytime discussion
content = (
Prompts.to_all_danger.format(n2s(dead_player))
if dead_player
else Prompts.to_all_peace
)
hints = [
HostMsg(content=content),
HostMsg(content=Prompts.to_all_discuss.format(n2s(survivors))),
]
with msghub(survivors, announcement=hints) as hub:
# discuss
set_parsers(survivors, Prompts.survivors_discuss_parser)
x = sequentialpipeline(survivors)
# vote
set_parsers(survivors, Prompts.survivors_vote_parser)
hint = HostMsg(content=Prompts.to_all_vote.format(n2s(survivors)))
votes = [
extract_name_and_id(_(hint).content)[0] for _ in survivors
]
vote_res = majority_vote(votes)
# broadcast the result to all players
result = HostMsg(content=Prompts.to_all_res.format(vote_res))
hub.broadcast(result)
survivors, wolves = update_alive_players(
survivors,
wolves,
vote_res,
)
if check_winning(survivors, wolves, "Moderator"):
break
hub.broadcast(HostMsg(content=Prompts.to_all_continue))
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,86 @@
# -*- coding: utf-8 -*-
"""utils."""
import re
from typing import Union, Any, Sequence
import numpy as np
from loguru import logger
from prompt import Prompts
from agentscope.agents import AgentBase
from agentscope.message import Msg
def check_winning(alive_agents: list, wolf_agents: list, host: str) -> bool:
"""check which group wins"""
if len(wolf_agents) * 2 >= len(alive_agents):
msg = Msg(host, Prompts.to_all_wolf_win, role="assistant")
logger.chat(msg)
return True
if alive_agents and not wolf_agents:
msg = Msg(host, Prompts.to_all_village_win, role="assistant")
logger.chat(msg)
return True
return False
def update_alive_players(
survivors: Sequence[AgentBase],
wolves: Sequence[AgentBase],
dead_names: Union[str, list[str]],
) -> tuple[list, list]:
"""update the list of alive agents"""
if not isinstance(dead_names, list):
dead_names = [dead_names]
return [_ for _ in survivors if _.name not in dead_names], [
_ for _ in wolves if _.name not in dead_names
]
def majority_vote(votes: list) -> Any:
"""majority_vote function"""
votes_valid = [item for item in votes if item != "Abstain"]
# Count the votes excluding abstentions.
unit, counts = np.unique(votes_valid, return_counts=True)
return unit[np.argmax(counts)]
def extract_name_and_id(name: str) -> tuple[str, int]:
"""extract player name and id from a string"""
try:
name = re.search(r"\b[Pp]layer\d+\b", name).group(0)
idx = int(re.search(r"[Pp]layer(\d+)", name).group(1)) - 1
except AttributeError:
# In case Player remains silent or speaks to abstain.
logger.warning(f"vote: invalid name {name}, set to Abstain")
name = "Abstain"
idx = -1
return name, idx
def n2s(agents: Sequence[Union[AgentBase, str]]) -> str:
"""combine agent names into a string, and use "and" to connect the last
two names."""
def _get_name(agent_: Union[AgentBase, str]) -> str:
return agent_.name if isinstance(agent_, AgentBase) else agent_
if len(agents) == 1:
return _get_name(agents[0])
return (
", ".join([_get_name(_) for _ in agents[:-1]])
+ " and "
+ _get_name(agents[-1])
)
def set_parsers(
agents: Union[AgentBase, list[AgentBase]],
parser_name: str,
) -> None:
"""Add parser to agents"""
if not isinstance(agents, list):
agents = [agents]
for agent in agents:
agent.set_parser(parser_name)