狼人杀相比麻将,三国杀等游戏,具有更多维的随机性,涉及到人的心理,动作,语言,甚至一个表情等等,因此它不像麻将,三国杀那样,依靠传统的计算机程序就可以很好的模拟。
不过利用AI可以做一下尝试。
至少在无聊的时间,不用呼朋唤友也可以玩上几局,聊以自慰。
程序采用langgragh,需要安装一些python扩展。
还需要有一个大模型的账户。
说实话,我不太会玩狼人杀,这些规则请教了好几个人,因此采用了最简单的9人局,三个狼人,一个猎人,一个女巫,一个预言家,三个平民,最简单的一种组队方式。目前程序写死成了这样,其实完全可以改写程序,自己设置几人局,如果愿意,弄个百人局通过程序也是简单的很。(如果真弄成个百人局,这是可以模拟一个真正的社会了吧,这将是另一个更有意思的游戏了,有兴趣的你可以尝试啊)
取名必须得显示我们中国特色:'伯翰', '仲霖', '叔瑜', '季轩', '五洲', '六韬', '七弦', '八骏', '九鼎’。
从老大到老九,可以方便区分。
我实现的第一版中没有给真人留位置,只是让大模型自己玩,也是很好玩的,你可以作为旁观者,看大模型一本正经的撒谎和胡说八道。这一版还是给真人留了个位置,开始的时候,会提示你在九兄弟中选择一个人物,但是你不可以随便的选择角色。跟现实中一样。角色的分配是程序随机进行分配的。
之后的发言,有些重复,这是因为在每个角色的记忆中都加进去了上一个角色的发言,这个发言对大模型的影响比较大,我想应该可以通过调整prompt有所改善。
代码虽然不算短,但是实现逻辑并不复杂,这里注意的一点就是要解决每个人物的记忆问题,比如角色,自己做了什么举动,能看到的别人做了什么举动等。其他如果你熟悉狼人杀的规则,就比较简单了。
值得一提的是,这个游戏还可以用作模型的推理能力的测评,不一定能定量的给出结果,但是可以通过变换大模型,然后各自玩上几把,就对不同的模型的推理能力有一个比较结果。
游戏中有三个狼人,按照规则,每晚都可以杀一个人,这个不需要推理就可以做到,但是正方人员要准确的杀掉狼人需要一些推理。因此,如果狼人获胜的几率太大,就说明大模型的推理不太行,当然跟你的prompt也有关系。
直接上代码吧。
from langchain.prompts import ChatPromptTemplate
from langchain_openai import AzureChatOpenAI
from pydantic import BaseModel, Field
from typing import List, TypedDict
from langchain_community.chat_models.tongyi import ChatTongyi
from langgraph.graph import END, StateGraph
from typing_extensions import TypedDict
from collections import Counter
import random
import os
# 模型看你选哪种,这里是千问,千问的model也有很多选择。
os.environ['DASHSCOPE_API_KEY'] = "你的key"
llm = ChatTongyi(model='qwen-plus-0624', temperature=0)
class DataCenterOfPlayer(BaseModel):
name: str = Field(..., description="the name of the player")
role: str = Field(..., description="the role of the player")
other_player: List[str] = Field(..., description="other players")
live_drug: bool = Field(..., description="if has antidote")
dead_drug: bool = Field(..., description="if has poison")
if_alive: bool = Field(..., description="True: alive, False: death")
info_player_know: str = Field(..., description="other information the player knows")
data_center = {
"伯翰": DataCenterOfPlayer(name="伯翰", role="", other_player=[], live_drug=False, dead_drug=False, if_alive=True, info_player_know=""),
"仲霖": DataCenterOfPlayer(name="仲霖", role="", other_player=[], live_drug=False, dead_drug=False, if_alive=True, info_player_know=""),
"叔瑜": DataCenterOfPlayer(name="叔瑜", role="", other_player=[], live_drug=False, dead_drug=False, if_alive=True, info_player_know=""),
"季轩": DataCenterOfPlayer(name="季轩", role="", other_player=[], live_drug=False, dead_drug=False, if_alive=True, info_player_know=""),
"五洲": DataCenterOfPlayer(name="五洲", role="", other_player=[], live_drug=False, dead_drug=False, if_alive=True, info_player_know=""),
"六韬": DataCenterOfPlayer(name="六韬", role="", other_player=[], live_drug=False, dead_drug=False, if_alive=True, info_player_know=""),
"七弦": DataCenterOfPlayer(name="七弦", role="", other_player=[], live_drug=False, dead_drug=False, if_alive=True, info_player_know=""),
"八骏": DataCenterOfPlayer(name="八骏", role="", other_player=[], live_drug=False, dead_drug=False, if_alive=True, info_player_know=""),
"九鼎": DataCenterOfPlayer(name="九鼎", role="", other_player=[], live_drug=False, dead_drug=False, if_alive=True, info_player_know="")
}
player_names = data_center.keys()
def init_role_to_data_center():
roles = ["狼人"] * 3 + ["平民"] * 3 + ["预言家"] * 1 + ["猎人"] * 1 + ["女巫"] * 1
random.shuffle(roles)
# 为每个玩家随机分配角色
for player in data_center.values():
player.role = roles.pop()
def init_other_player():
for player in player_names:
data_center[player].other_player = [p for p in player_names if p != player]
def init_drug_for_nvwu():
# 初始化女巫角色的药物
for player in data_center.values():
if player.role == "女巫":
player.live_drug = True
player.dead_drug = True
def clear_live_drug_for_nvwu(name):
data_center[name].live_drug = False
def clear_dead_drug_for_nvwu(name):
data_center[name].dead_drug = False
def set_info_player_know(name, info):
data_center[name].info_player_know += (info + '\\n')
def set_player_status(name: str, if_alive):
data_center[name].if_alive = if_alive
def get_player_status(name: str):
return data_center[name].if_alive
def get_players_by_role(role: str):
return [player.name for player in data_center.values() if player.role == role]
def get_other_player(name):
return data_center[name].other_player
def get_role_by_player(name):
return data_center[name].role
def get_history(name):
return data_center[name].info_player_know
def if_has_live_drug(name):
return data_center[name].live_drug
def if_has_dead_drug(name):
return data_center[name].dead_drug
def get_live_player():
alive_players = [player.name for player in data_center.values() if player.if_alive]
return alive_players
def werewolves_all_dead():
for player in data_center.values():
if player.role == "狼人" and player.if_alive:
return False
return True
def villagers_all_dead():
for player in data_center.values():
if player.role == "平民" and player.if_alive:
return False
return True
def special_roles_all_dead():
special_roles = ["预言家", "猎人", "女巫"]
for player in data_center.values():
if player.role in special_roles and player.if_alive:
return False
return True
def print_all_player_role():
print("玩家实际的角色:")
for player in data_center.values():
if_alive = "已挂"
if player.if_alive:
if_alive = "活着"
print(f"{player.name}: {player.role}, {if_alive}")
class answer_of_role(BaseModel):
"""the actions of rols"""
analysis: str = Field(description="the analysis of player")
name: str = Field(description=f'''who you want to kill, and the name must be included in [伯翰, 仲霖,叔瑜,季轩,五洲,六韬,七弦,八骏,九鼎] ''')
class answer_of_role_when_vote(BaseModel):
"""the actions of rols"""
analysis: str = Field(description="the analysis of player")
name: str = Field(description=f'''who you want to vote to die, and the name must be included in[伯翰, 仲霖,叔瑜,季轩,五洲,六韬,七弦,八骏,九鼎]''')
class answer_of_role_when_speech(BaseModel):
"""the analysis and speech of rols"""
analysis: str = Field(description="the analysis of player, the content can not be known by other player.")
speech: str = Field(description="the speech of player, the content is what you want to be known by other player.")
class answer_of_predict(BaseModel):
"""answer of prophets"""
analysis: str = Field(description="the analysis of prophets")
name: str = Field(description=f'''whose identity the prophet wants to know, and the name must be included in [伯翰, 仲霖,叔瑜,季轩,五洲,六韬,七弦,八骏,九鼎]''')
class anwser_of_witch_save(BaseModel):
"""the actions of rols"""
analysis: str = Field(description="the analysis of player")
if_save: bool = Field(description="if the witch save the dead tonight")
class CurrentState(BaseModel):
"""Description of the current situation of the game"""
round_num: int = Field(description="the round num of the game")
player_dead: List[str] = Field(description="the players who dead in current turn, if no one set None")
class GraphState(TypedDict):
"""
Represents the state of our graph.
Attributes:
poems_parts: history sentences
"""
human_name: str
current_describe: CurrentState
def set_init_state():
init_role_to_data_center()
init_other_player()
init_drug_for_nvwu()
# print_all_player_role() #临时
while 1:
your_name = input("请选择一个名字(伯翰,仲霖,叔瑜,季轩,五洲,六韬,七弦,八骏,九鼎): ")
if your_name not in player_names:
print("游戏中没有这个人参与")
else:
break
human_role = get_role_by_player(your_name)
print(f"你是{your_name},你的角色是{human_role}")
current_round = CurrentState(
round_num = 0,
player_dead=[]
)
return {'human_name': your_name, 'current_describe': current_round}
def chain_with_player_name_construct():
prompt = ChatPromptTemplate.from_messages(
[
(
"system",
"""你是{player_name}, 是一位出色的“狼人杀”游戏玩家,正在玩“狼人杀”游戏。你是 {role}。
其他玩家包括:
{other_player},
游戏中的所有角色为:
3个狼人
3个平民
1个预言家
1个猎人
1个女巫
这是第{round_num}晚.
{history}
根据你{role}的身份,仔细分析这些信息,不要凭空猜测,最终做出最优决定.
"""
),
("human", "{action}"),
]
)
chain = prompt | llm.with_structured_output(schema=answer_of_role)
return chain
def chain_with_if_witch_save():
prompt = ChatPromptTemplate.from_messages(
[
(
"system",
"""你是{player_name}, 是一位出色的“狼人杀”游戏玩家,正在玩“狼人杀”游戏,你的角色是{role}。
其他玩家包括:
{other_player},
游戏中的所有角色为:
3个狼人
3个平民
1个预言家
1个猎人
1个女巫
这是第{round_num}晚.
{history}
根据你{role}的身份,仔细分析你所了解的信息,对每个人的身份做出最合理的推理,最终做出最有利于你团队的决定.
"""
),
("human", "{action}"),
]
)
chain = prompt | llm.with_structured_output(schema=anwser_of_witch_save)
return chain
def prophet_chain_construct():
prompt = ChatPromptTemplate.from_messages(
[
(
"system",
"""你是{player_name}, 是一位出色的“狼人杀”游戏玩家,正在玩“狼人杀”游戏。你是 {role}。
其他玩家包括:
{other_player},
游戏中的所有角色为:
3个狼人
3个平民
1个预言家
1个猎人
1个女巫
这是第{round_num}晚.
{history}
根据你{role}的身份,仔细分析你所了解的信息,对每个人的身份做出最合理的推理,最终做出最有利于你团队的决定.
"""
),
("human", "{action}"),
]
)
chain = prompt | llm.with_structured_output(schema=answer_of_predict)
return chain
def vote_chain_construct():
prompt = ChatPromptTemplate.from_messages(
[
(
"system",
"""你是{player_name}, 是一位出色的“狼人杀”游戏玩家,正在玩“狼人杀”游戏。你是 {role}。
其他玩家包括:
{other_player},
游戏中的所有角色为:
3个狼人
3个平民
1个预言家
1个猎人
1个女巫
当前是第{round_num}天白天.
{history}
当前活着的玩家包括:{live_player}。
根据你{role}的身份,仔细分析你所了解的信息,对每个玩家的身份做出最合理的推理,推理不会被人看到,可以大胆的分析猜测。
其他玩家的发言可能是假话,注意辨别。
然后做出最利于你的团队的决定。
"""
),
("human", "{action}"),
]
)
chain = prompt | llm.with_structured_output(schema=answer_of_role_when_vote)
return chain
def speech_chain_construct():
prompt = ChatPromptTemplate.from_messages(
[
(
"system",
"""你是{player_name}, 是一位出色的“狼人杀”游戏玩家,正在玩“狼人杀”游戏。你是 {role}。
其他玩家包括:
{other_player},
游戏中的所有角色为:
3个狼人
3个平民
1个预言家
1个猎人
1个女巫
当前是第{round_num}天白天.
{history}
当前活着的玩家包括:{live_player}。
根据你{role}的身份,仔细分析你所了解的信息,对每个玩家的身份做出最合理的推理(analysis),推理不会被人看到,可以大胆的分析猜测。
然后做出最利于你的团队的发言(speech),你的发言会被其他玩家听到,必要时要隐瞒一些情况,甚至可以撒谎。
注意:很多时候,你需要隐藏你的行为和你的角色。
其他玩家的发言可能是假话,注意辨别。
给出你的
推理(analysis): 这些分析应该是玩家内心的推理(analysis),推理出谁是你的对手,但是不一定会如实说出来
发言(speech): 你的发言是对其他玩家说的,为了使你的团队获胜,如果你是狼人,应该隐瞒自己的角色,如果你是其他角色,应该视情况决定是不是需要告诉大家。
你需要分别给出推理(analysis)和发言(speech)。
"""
),
("human", "{action}"),
]
)
chain = prompt | llm.with_structured_output(schema=answer_of_role_when_speech)
return chain
prophet_chain = prophet_chain_construct()
common_chain = chain_with_player_name_construct()
witch_chain = chain_with_if_witch_save()
vote_chain = vote_chain_construct()
speech_chain = speech_chain_construct()
def scene_1_get_dark(state):
"""
scene 1
Args:
state (dict): The current graph state
Returns:
state (dict): the verse info
"""
state['current_describe'].round_num += 1
state['current_describe'].player_dead.clear()
print(f"===== 第{state['current_describe'].round_num}天 =====\\n")
live_players = get_live_player()
live_palyers_str = ",".join(live_players)
print(f"玩家剩余: {live_palyers_str}")
print(f"-- 天黑请闭眼 --")
info = f"===== 第{state['current_describe'].round_num}夜的信息 =====\\n"
for player in player_names:
set_info_player_know(player, info)
return state
def get_first_alive_wolf():
for player in data_center.values():
if player.role == "狼人" and player.if_alive:
return player.name
return None
def scene_2_wolf_action(state):
"""
the action of witch after wolf action
Args:
state (dict): The current graph state
Returns:
state (dict): the verse info
"""
print("-- 狼人请睁眼,狼人请杀人 --")
wolf_players = get_players_by_role('狼人')
random.shuffle(wolf_players)
if state['human_name'] in wolf_players and get_player_status(state['human_name']):
wolf_live_player = state['human_name']
print('狼人:', ",".join(wolf_players))
else:
wolf_live_player = get_first_alive_wolf()
round_num = state['current_describe'].round_num
other_player = get_other_player(wolf_live_player)
random.shuffle(other_player)
if round_num == 1:
for wolf_player in wolf_players:
wolf_players_copy = wolf_players.copy()
wolf_players_copy.remove(wolf_player)
info = f"你知道了你的同伙,也就是其他狼人: {wolf_players_copy[0]} 和 {wolf_players_copy[1]}\\n"
set_info_player_know(wolf_player, info)
history = get_history(wolf_live_player)
player_killed = ''
if state['human_name'] != wolf_live_player:
try:
res = common_chain.invoke({'player_name': wolf_live_player, 'role': '狼人', 'other_player': other_player, 'round_num': round_num, 'history':history, 'action': '游戏规定,狼人必须在晚上杀死一个玩家,你要杀谁。'})
except Exception as e:
print(f"scene_2_wolf_action: {e}")
return None
player_killed = res.name.replace('"', '').replace("'", '')
else:
live_players = get_live_player()
while(1):
player_killed = input(f"你作为狼人,要杀死谁({live_players}): ")
if player_killed in live_players:
break
state['current_describe'].player_dead.append(player_killed)
info = f"你们,也就是狼人团队杀死了{player_killed}\\n"
for wolf_player in wolf_players:
set_info_player_know(wolf_player, info)
print("-- 狼人请闭眼 --")
return state
def scene_2_prediction_action(state):
"""
the action of prophet after wolf action
Args:
state (dict): The current graph state
Returns:
state (dict): the verse info
"""
print("-- 预言家请睁眼 --")
pre_players = get_players_by_role('预言家')[0]
if not get_player_status(pre_players):
if state['human_name'] == pre_players:
print("你是预言家,但已出局")
return state
round_num = state['current_describe'].round_num
other_player = get_other_player(pre_players)
random.shuffle(other_player)
history = get_history(pre_players)
if state['human_name'] != pre_players:
try:
res = common_chain.invoke({'player_name': pre_players, 'role': '预言家', 'other_player': other_player, 'round_num': round_num, 'history':history, 'action': '按照游戏规则,你可以知道一名仍然活着的玩家是否是狼人团队,请分析当前形式,然后告诉我你想知道谁的身份。'})
except Exception as e:
print(f"scene_2_prediction_action: {e}")
return None
player = res.name.replace('"', '').replace("'", '')
else:
other_players = get_other_player(state['human_name'])
live_players = get_live_player()
other_live_player = list(set(other_players) & set(live_players))
while(1):
player = input(f"你作为预言家,要查看谁的身份({other_live_player}): ")
if player in other_live_player:
break
role_pre = get_role_by_player(player)
if role_pre == "狼人":
if_wolf = "是"
else:
if_wolf = "不是"
if state['human_name'] == pre_players:
print(f"{player}{if_wolf}狼人")
info = f"你知道了:{player}{if_wolf}狼人\\n"
set_info_player_know(pre_players, info)
print("-- 预言家请闭眼 --")
return state
def scene_2_witch_save_action(state):
"""
the action of witch after dark
Args:
state (dict): The current graph state
Returns:
state (dict): the verse info
"""
print("-- 女巫请睁眼,有人被杀,女巫救不救 --")
witch_players = get_players_by_role('女巫')[0]
current_dead = state['current_describe'].player_dead[0]
if not get_player_status(witch_players):
if state['human_name'] == witch_players:
print("女巫已死")
set_player_status(current_dead, False)
return state
round_num = state['current_describe'].round_num
other_player = get_other_player(witch_players)
history = get_history(witch_players)
live_drug_des = ''
info = f"{current_dead}被狼人弄伤了。"
if if_has_live_drug(witch_players):
if state['human_name'] != witch_players:
live_drug_des = f"{current_dead}被伤了,你有1瓶解药,你要救他吗"
try:
res = witch_chain.invoke({'player_name': witch_players, 'role': '女巫', 'other_player': other_player, 'round_num': round_num, 'history':history, 'action': live_drug_des})
except Exception as e:
print(f"scene_2_witch_save_action: {e}")
return None
if_to_save = res.if_save
else:
while(1):
YorN = input(f"{info}你是否要救他(Y/N):")
if YorN.lower() == 'y':
if_to_save = True
break # 跳出循环
elif YorN.lower() == 'n':
if_to_save = False
break # 跳出循环
else:
print("请输入 'Y' 或 'N'")
if if_to_save == True:
set_player_status(current_dead, True)
state['current_describe'].player_dead.remove(current_dead)
clear_live_drug_for_nvwu(witch_players)
info += f"你救了{current_dead}。\\n"
else:
set_player_status(current_dead, False)
info += f"你没有救{current_dead},他最终死了。\\n"
set_info_player_know(witch_players, info)
else:
set_player_status(current_dead, False)
info = f"{current_dead}被狼人弄伤了,你没解药再救{current_dead},他最终死了。\\n"
set_info_player_know(witch_players, info)
return state
def scene_2_witch_kill_action(state):
"""
the action of witch after dark
Args:
state (dict): The current graph state
Returns:
state (dict): the verse info
"""
print("-- 女巫要杀人吗 --")
witch_players = get_players_by_role('女巫')[0]
if not get_player_status(witch_players):
if state['human_name'] == witch_players:
print("女巫已死")
return state
round_num = state['current_describe'].round_num
other_player = get_other_player(witch_players)
history = get_history(witch_players)
live_drug_des = ''
if if_has_dead_drug(witch_players):
if state['human_name'] != witch_players:
live_drug_des = f"你有1瓶毒药,你要杀掉一位玩家吗,如果不想就回答None,如果想,就说出他的名字"
try:
res = common_chain.invoke({'player_name': witch_players, 'role': '女巫', 'other_player': other_player, 'round_num': round_num, 'history':history, 'action': live_drug_des})
except Exception as e:
print(f"scene_2_witch_kill_action: {e}")
return None
player = res.name.replace('"', '').replace("'", '')
else:
other_players = get_other_player(state['human_name'])
live_players = get_live_player()
other_live_player = list(set(other_players) & set(live_players))
while(1):
player = input(f"你作为女巫,要毒杀谁吗({other_live_player}),如果不想,请输入None: ")
if player in other_live_player or player == 'None':
break
if 'None' == player:
info = f"第{round_num}轮你没有下毒\\n"
else:
info = f"第{round_num}轮,你毒杀了{player}。\\n"
clear_dead_drug_for_nvwu(witch_players)
set_player_status(player, False)
state['current_describe'].player_dead.append(player)
set_info_player_know(witch_players, info)
else:
if state['human_name'] == witch_players:
print(f"你是女巫,但你已经没有毒药了")
print(f"-- 女巫请闭眼 --")
return state
def scene_3_it_is_dawn(state):
"""
scene 3
Args:
state (dict): The current graph state
Returns:
state (dict): the verse info
"""
print("-- 天亮了,大家请睁眼 --")
# 初始化一个对象
player_who_dead = state['current_describe'].player_dead
round_num = state['current_describe'].round_num
if len(player_who_dead) == 0:
player_who_dead = "没有人"
else:
player_who_dead = ",".join(player_who_dead)
print(f"昨晚{player_who_dead}被杀")
info = f"第{round_num}晚{player_who_dead}被杀\\n\\n"
info += f"===== 第{round_num}天亮后的信息 =====\\n"
for player_name in player_names:
set_info_player_know(player_name, info)
state['current_describe'].player_dead.clear()
return state
def scene_3_light_speech(state):
"""
scene 3
Args:
state (dict): The current graph state
Returns:
state (dict): the verse info
"""
print("-- 请依次发言 --")
round_num = state['current_describe'].round_num
live_player = get_live_player()
action = f'''天亮了,接着大家的对话,发言描述你所掌握的情况.'''
info = f"下面是第{round_num}天亮后,没有出局的人展开对话:\\n"
for player_name in player_names:
set_info_player_know(player_name, info)
for player_name in player_names:
if get_player_status(player_name):
if state['human_name'] != player_name:
role = get_role_by_player(player_name)
if role == '预言家':
role += ', 发言时注意既能指出你昨晚验证的人的身份,又能隐藏好自己的身份。'
other_player = get_other_player(player_name)
random.shuffle(other_player)
history = get_history(player_name)
try:
res = speech_chain.invoke({'player_name': player_name, 'role': role, 'other_player': other_player, 'round_num': round_num, 'history':history, 'live_player':live_player, 'action': action})
except Exception as e:
print(f"scene_3_light_speech: {e}")
continue
if res == None:
print(f'{player_name} 发言: None\\n')
continue
info = f'{player_name}: {res.speech}\\n\\n'
print(f'{player_name} 发言: {res.speech}\\n')
else:
while(1):
speech = input(f"请{state['human_name']}发言: ")
info = f'{player_name}: {speech}\\n'
break
print(f'{player_name} 发言: {speech}')
for player_name in player_names:
set_info_player_know(player_name, info)
return state
def scene_3_light_vote(state):
"""
scene 3
Args:
state (dict): The current graph state
Returns:
state (dict): the verse info
"""
print("-- 请投票 --")
round_num = state['current_describe'].round_num
live_player = get_live_player()
live_player_str = ",".join(live_player)
action = f'''给出你的分析,并选择出你希望出局的对象.'''
info = f"下面是投票结果,显示了每个人都希望谁出局:\\n"
vote = []
for player_name in player_names:
if get_player_status(player_name):
if state['human_name'] != player_name:
role = get_role_by_player(player_name)
other_player = get_other_player(player_name)
random.shuffle(other_player)
history = get_history(player_name)
try:
res = vote_chain.invoke({'player_name': player_name, 'role': role, 'other_player': other_player, 'round_num': round_num, 'history':history, 'live_player':live_player_str, 'action': action})
except Exception as e:
print(f"scene_3_light_vote: {e}")
continue
info += f'{player_name}投了: {res.name}\\n'
print(f'{player_name} 投了:{res.name}\\n')
vote.append(res.name)
else:
other_players = get_other_player(state['human_name'])
live_players = get_live_player()
other_live_player = list(set(other_players) & set(live_players))
while(1):
player = input(f"要投谁({other_live_player}): ")
if player in other_live_player:
info += f'{player_name}投了: {player}\\n'
break
vote.append(player)
print(f'{player_name}投了:{player}\\n')
for player_name in player_names:
set_info_player_know(player_name, info)
# 使用Counter计算每个元素出现的次数
counter = Counter(vote)
# 找到出现最多的元素
most_voted_player, voted_time = counter.most_common(1)[0]
set_player_status(most_voted_player, False)
info = f"第{round_num}轮天亮后,{most_voted_player}被投票投死了.\\n"
print(f"得票最多的是: {most_voted_player}, 票数是: {voted_time}, 因此他被投死了。")
state['current_describe'].player_dead.append(most_voted_player)
for player_name in player_names:
set_info_player_know(player_name, info)
return state
def scene_3_light_hunter_kill_after_vote(state):
"""
scene 3
Args:
state (dict): The current graph state
Returns:
state (dict): the verse info
"""
most_voted_player = state['current_describe'].player_dead[0]
rola_of_most_voted_player = get_role_by_player(most_voted_player)
if rola_of_most_voted_player != '猎人':
print("被杀的不是猎人")
return state
print(f"被投死的{most_voted_player}是猎人,因此他有权杀死一名玩家。")
round_num = state['current_describe'].round_num
live_players = get_live_player()
live_players_str = ",".join(live_players)
if state['human_name'] != most_voted_player:
other_player_of_voted = get_other_player(most_voted_player)
history_of_voted = get_history(most_voted_player)
action_of_voted = f"你作为猎人被投票投死了,按照游戏规则,在猎人被投死的时候,可以除掉一名玩家,当前还活着的玩家有{live_players_str},请分析当前情况,给出你要除掉的对象。如果不确定,也可以不除,给出None。"
try:
res_voted = common_chain.invoke({'player_name': most_voted_player, 'role': "猎人", 'other_player': other_player_of_voted, 'round_num': round_num, 'history':history_of_voted, 'action': action_of_voted})
except Exception as e:
print(f"scene_3_light_hunter_kill_after_vote: {e}")
return state
player_kill_by_hunter = res_voted.name
else:
other_players = get_other_player(state['human_name'])
other_live_player = list(set(other_players) & set(live_players))
while(1):
player_kill_by_hunter = input(f"作为猎人,你被投死了,按照规定可以杀掉一个玩家({other_live_player}或None): ")
if player_kill_by_hunter in other_live_player:
break
if 'None' == player_kill_by_hunter:
info = f"{most_voted_player}的角色是猎人,但临死前他没有杀玩家。\\n"
else:
info = f"{most_voted_player}的角色是猎人,按照规则在临死前他可以杀掉一个玩家,于是它把{player_kill_by_hunter}给杀了。\\n"
print(f"{most_voted_player}(猎人)杀死了{player_kill_by_hunter}")
set_player_status(player_kill_by_hunter, False)
for player_name in player_names:
set_info_player_know(player_name, info)
return state
def if_play_end(state):
if special_roles_all_dead() or villagers_all_dead():
print("===== 游戏结束,狼人获胜 =====")
print_all_player_role()
return True
if werewolves_all_dead():
print("===== 游戏结束,好人获胜 =====")
print_all_player_role()
return True
return False
def construct_app():
workflow = StateGraph(GraphState)
workflow.add_node("scene_1_get_dark", scene_1_get_dark)
workflow.add_node("scene_2_wolf_action", scene_2_wolf_action)
workflow.add_node("scene_2_prediction_action", scene_2_prediction_action)
workflow.add_node("scene_2_witch_save_action", scene_2_witch_save_action)
workflow.add_node("scene_2_witch_kill_action", scene_2_witch_kill_action)
workflow.add_node("scene_3_it_is_dawn", scene_3_it_is_dawn)
workflow.add_node("scene_3_light_speech", scene_3_light_speech)
workflow.add_node("scene_3_light_vote", scene_3_light_vote)
workflow.add_node("scene_3_light_hunter_kill_after_vote", scene_3_light_hunter_kill_after_vote)
workflow.set_entry_point("scene_1_get_dark")
workflow.add_edge("scene_1_get_dark", 'scene_2_wolf_action')
workflow.add_edge("scene_2_wolf_action", 'scene_2_prediction_action')
workflow.add_edge("scene_2_prediction_action", 'scene_2_witch_save_action')
workflow.add_edge("scene_2_witch_save_action", 'scene_2_witch_kill_action')
workflow.add_edge("scene_2_witch_kill_action", 'scene_3_it_is_dawn')
workflow.add_conditional_edges(
"scene_3_it_is_dawn",
if_play_end,
{
True: END,
False: "scene_3_light_speech",
},
)
workflow.add_edge("scene_3_light_speech", 'scene_3_light_vote')
workflow.add_conditional_edges(
"scene_3_light_vote",
if_play_end,
{
True: END,
False: "scene_3_light_hunter_kill_after_vote",
},
)
workflow.add_conditional_edges(
"scene_3_light_hunter_kill_after_vote",
if_play_end,
{
True: END,
False: "scene_1_get_dark",
},
)
app = workflow.compile()
return app
def gen_result():
RECURSION_LIMIT = 50
app = construct_app()
inputs = set_init_state()
for output in app.stream(inputs, {"recursion_limit": RECURSION_LIMIT},):
for key, value in output.items():
# Node
print(f"***")
# Optional: print full state at each node
# pprint(value)
if output == None:
print("output is none")
return None
gen_result()