main_cn.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. # -*- coding: utf-8 -*-
  2. """
  3. 三国狼人杀 - 基于AgentScope的中文版狼人杀游戏
  4. 融合三国演义角色和传统狼人杀玩法
  5. """
  6. import asyncio
  7. import os
  8. import random
  9. from typing import List, Dict, Optional
  10. from agentscope.agent import ReActAgent
  11. from agentscope.model import DashScopeChatModel
  12. from agentscope.pipeline import MsgHub, sequential_pipeline, fanout_pipeline
  13. from agentscope.formatter import DashScopeMultiAgentFormatter
  14. from prompt_cn import ChinesePrompts
  15. from game_roles import GameRoles
  16. from structured_output_cn import (
  17. DiscussionModelCN,
  18. get_vote_model_cn,
  19. WitchActionModelCN,
  20. get_seer_model_cn,
  21. get_hunter_model_cn,
  22. WerewolfKillModelCN
  23. )
  24. from utils_cn import (
  25. check_winning_cn,
  26. majority_vote_cn,
  27. get_chinese_name,
  28. format_player_list,
  29. GameModerator,
  30. MAX_GAME_ROUND,
  31. MAX_DISCUSSION_ROUND,
  32. )
  33. class ThreeKingdomsWerewolfGame:
  34. """三国狼人杀游戏主类"""
  35. def __init__(self):
  36. self.players: Dict[str, ReActAgent] = {}
  37. self.roles: Dict[str, str] = {}
  38. self.moderator = GameModerator()
  39. self.alive_players: List[ReActAgent] = []
  40. self.werewolves: List[ReActAgent] = []
  41. self.villagers: List[ReActAgent] = []
  42. self.seer: List[ReActAgent] = []
  43. self.witch: List[ReActAgent] = []
  44. self.hunter: List[ReActAgent] = []
  45. # 女巫道具状态
  46. self.witch_has_antidote = True
  47. self.witch_has_poison = True
  48. async def create_player(self, role: str, character: str) -> ReActAgent:
  49. """创建具有三国背景的玩家"""
  50. name = get_chinese_name(character)
  51. self.roles[name] = role
  52. agent = ReActAgent(
  53. name=name,
  54. sys_prompt=ChinesePrompts.get_role_prompt(role, character),
  55. model=DashScopeChatModel(
  56. model_name="qwen-max",
  57. api_key=os.environ["DASHSCOPE_API_KEY"],
  58. enable_thinking=True,
  59. ),
  60. formatter=DashScopeMultiAgentFormatter(),
  61. )
  62. # 角色身份确认
  63. await agent.observe(
  64. await self.moderator.announce(
  65. f"【{name}】你在这场三国狼人杀中扮演{GameRoles.get_role_desc(role)},"
  66. f"你的角色是{character}。{GameRoles.get_role_ability(role)}"
  67. )
  68. )
  69. self.players[name] = agent
  70. return agent
  71. async def setup_game(self, player_count: int = 6):
  72. """设置游戏"""
  73. print("🎮 开始设置三国狼人杀游戏...")
  74. # 获取角色配置
  75. roles = GameRoles.get_standard_setup(player_count)
  76. characters = random.sample([
  77. "刘备", "关羽", "张飞", "诸葛亮", "赵云",
  78. "曹操", "司马懿", "周瑜", "孙权"
  79. ], player_count)
  80. # 创建玩家
  81. for i, (role, character) in enumerate(zip(roles, characters)):
  82. agent = await self.create_player(role, character)
  83. self.alive_players.append(agent)
  84. # 分配到对应阵营
  85. if role == "狼人":
  86. self.werewolves.append(agent)
  87. elif role == "预言家":
  88. self.seer.append(agent)
  89. elif role == "女巫":
  90. self.witch.append(agent)
  91. elif role == "猎人":
  92. self.hunter.append(agent)
  93. else:
  94. self.villagers.append(agent)
  95. # 游戏开始公告
  96. await self.moderator.announce(
  97. f"三国狼人杀游戏开始!参与者:{format_player_list(self.alive_players)}"
  98. )
  99. print(f"✅ 游戏设置完成,共{len(self.alive_players)}名玩家")
  100. async def werewolf_phase(self, round_num: int):
  101. """狼人阶段"""
  102. if not self.werewolves:
  103. return None
  104. await self.moderator.announce(f"🐺 狼人请睁眼,选择今晚要击杀的目标...")
  105. # 狼人讨论
  106. async with MsgHub(
  107. self.werewolves,
  108. enable_auto_broadcast=True,
  109. announcement=await self.moderator.announce(
  110. f"狼人们,请讨论今晚的击杀目标。存活玩家:{format_player_list(self.alive_players)}"
  111. ),
  112. ) as werewolves_hub:
  113. # 讨论阶段
  114. for _ in range(MAX_DISCUSSION_ROUND):
  115. for wolf in self.werewolves:
  116. await wolf(structured_model=DiscussionModelCN)
  117. # 投票击杀
  118. werewolves_hub.set_auto_broadcast(False)
  119. kill_votes = await fanout_pipeline(
  120. self.werewolves,
  121. msg=await self.moderator.announce("请选择击杀目标"),
  122. structured_model=WerewolfKillModelCN,
  123. enable_gather=False,
  124. )
  125. # 统计投票
  126. votes = {}
  127. for i, vote_msg in enumerate(kill_votes):
  128. votes[self.werewolves[i].name] = vote_msg.metadata.get("target")
  129. killed_player, _ = majority_vote_cn(votes)
  130. return killed_player
  131. async def seer_phase(self):
  132. """预言家阶段"""
  133. if not self.seer:
  134. return
  135. seer_agent = self.seer[0]
  136. await self.moderator.announce("🔮 预言家请睁眼,选择要查验的玩家...")
  137. check_result = await seer_agent(
  138. structured_model=get_seer_model_cn(self.alive_players)
  139. )
  140. target_name = check_result.metadata.get("target")
  141. target_role = self.roles.get(target_name, "村民")
  142. # 告知预言家结果
  143. result_msg = f"查验结果:{target_name}是{'狼人' if target_role == '狼人' else '好人'}"
  144. await seer_agent.observe(await self.moderator.announce(result_msg))
  145. async def witch_phase(self, killed_player: str):
  146. """女巫阶段"""
  147. if not self.witch:
  148. return killed_player, None
  149. witch_agent = self.witch[0]
  150. await self.moderator.announce("🧙‍♀️ 女巫请睁眼...")
  151. # 告知女巫死亡信息
  152. death_info = f"今晚{killed_player}被狼人击杀" if killed_player else "今晚平安无事"
  153. await witch_agent.observe(await self.moderator.announce(death_info))
  154. # 女巫行动
  155. witch_action = await witch_agent(structured_model=WitchActionModelCN)
  156. saved_player = None
  157. poisoned_player = None
  158. if witch_action.metadata.get("use_antidote") and self.witch_has_antidote:
  159. if killed_player:
  160. saved_player = killed_player
  161. self.witch_has_antidote = False
  162. await witch_agent.observe(await self.moderator.announce(f"你使用解药救了{killed_player}"))
  163. if witch_action.metadata.get("use_poison") and self.witch_has_poison:
  164. poisoned_player = witch_action.metadata.get("target_name")
  165. if poisoned_player:
  166. self.witch_has_poison = False
  167. await witch_agent.observe(await self.moderator.announce(f"你使用毒药毒杀了{poisoned_player}"))
  168. # 确定最终死亡玩家
  169. final_killed = killed_player if not saved_player else None
  170. return final_killed, poisoned_player
  171. async def hunter_phase(self, shot_by_hunter: str):
  172. """猎人阶段"""
  173. if not self.hunter:
  174. return None
  175. hunter_agent = self.hunter[0]
  176. if hunter_agent.name == shot_by_hunter:
  177. await self.moderator.announce("🏹 猎人发动技能,可以带走一名玩家...")
  178. hunter_action = await hunter_agent(
  179. structured_model=get_hunter_model_cn(self.alive_players)
  180. )
  181. if hunter_action.metadata.get("shoot"):
  182. target = hunter_action.metadata.get("target")
  183. await self.moderator.announce(f"猎人{hunter_agent.name}开枪带走了{target}")
  184. return target
  185. return None
  186. def update_alive_players(self, dead_players: List[str]):
  187. """更新存活玩家列表"""
  188. for dead_name in dead_players:
  189. if dead_name:
  190. # 从存活列表移除
  191. self.alive_players = [p for p in self.alive_players if p.name != dead_name]
  192. # 从各阵营移除
  193. self.werewolves = [p for p in self.werewolves if p.name != dead_name]
  194. self.villagers = [p for p in self.villagers if p.name != dead_name]
  195. self.seer = [p for p in self.seer if p.name != dead_name]
  196. self.witch = [p for p in self.witch if p.name != dead_name]
  197. self.hunter = [p for p in self.hunter if p.name != dead_name]
  198. async def day_phase(self, round_num: int):
  199. """白天阶段"""
  200. await self.moderator.day_announcement(round_num)
  201. # 讨论阶段
  202. async with MsgHub(
  203. self.alive_players,
  204. enable_auto_broadcast=True,
  205. announcement=await self.moderator.announce(
  206. f"现在开始自由讨论。存活玩家:{format_player_list(self.alive_players)}"
  207. ),
  208. ) as all_hub:
  209. # 每人发言一轮
  210. await sequential_pipeline(self.alive_players)
  211. # 投票阶段
  212. all_hub.set_auto_broadcast(False)
  213. vote_msgs = await fanout_pipeline(
  214. self.alive_players,
  215. await self.moderator.announce("请投票选择要淘汰的玩家"),
  216. structured_model=get_vote_model_cn(self.alive_players),
  217. enable_gather=False,
  218. )
  219. # 统计投票
  220. votes = {}
  221. for i, vote_msg in enumerate(vote_msgs):
  222. votes[self.alive_players[i].name] = vote_msg.metadata.get("vote")
  223. voted_out, vote_count = majority_vote_cn(votes)
  224. await self.moderator.vote_result_announcement(voted_out, vote_count)
  225. return voted_out
  226. async def run_game(self):
  227. """运行游戏主循环"""
  228. try:
  229. await self.setup_game()
  230. for round_num in range(1, MAX_GAME_ROUND + 1):
  231. print(f"\n🌙 === 第{round_num}轮游戏开始 ===")
  232. # 夜晚阶段
  233. await self.moderator.night_announcement(round_num)
  234. # 狼人击杀
  235. killed_player = await self.werewolf_phase(round_num)
  236. # 预言家查验
  237. await self.seer_phase()
  238. # 女巫行动
  239. final_killed, poisoned_player = await self.witch_phase(killed_player)
  240. # 更新死亡玩家
  241. night_deaths = [p for p in [final_killed, poisoned_player] if p]
  242. self.update_alive_players(night_deaths)
  243. # 死亡公告
  244. await self.moderator.death_announcement(night_deaths)
  245. # 检查胜利条件
  246. winner = check_winning_cn(self.alive_players, self.roles)
  247. if winner:
  248. await self.moderator.game_over_announcement(winner)
  249. return
  250. # 白天阶段
  251. voted_out = await self.day_phase(round_num)
  252. # 猎人技能
  253. hunter_shot = await self.hunter_phase(voted_out)
  254. # 更新死亡玩家
  255. day_deaths = [p for p in [voted_out, hunter_shot] if p]
  256. self.update_alive_players(day_deaths)
  257. # 检查胜利条件
  258. winner = check_winning_cn(self.alive_players, self.roles)
  259. if winner:
  260. await self.moderator.game_over_announcement(winner)
  261. return
  262. print(f"第{round_num}轮结束,存活玩家:{format_player_list(self.alive_players)}")
  263. except Exception as e:
  264. print(f"❌ 游戏运行出错:{e}")
  265. import traceback
  266. traceback.print_exc()
  267. async def main():
  268. """主函数"""
  269. # 检查环境变量
  270. if "DASHSCOPE_API_KEY" not in os.environ:
  271. print("❌ 请设置环境变量 DASHSCOPE_API_KEY")
  272. return
  273. print("🎮 欢迎来到三国狼人杀!")
  274. # 创建并运行游戏
  275. game = ThreeKingdomsWerewolfGame()
  276. await game.run_game()
  277. if __name__ == "__main__":
  278. asyncio.run(main())