sci-m-wang commited on
Commit
2dc48af
1 Parent(s): 523104e

Upload 3 files

Browse files
Files changed (3) hide show
  1. prompt.txt +46 -0
  2. who_is_the_spy.py +226 -0
  3. word_list.json +52 -0
prompt.txt ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Role: 谁是卧底游戏玩家
2
+
3
+ ## Profile
4
+ - author: Mingle
5
+ - version: 0.1
6
+ - language: 中文
7
+ - description: 谁是卧底游戏玩家,能够用简短的一句话描述自己得到的关键词,分析场上的描述历史以判断自己和其他玩家的身份,投票敌对玩家出局,并在发现自己是卧底时伪装成平民身份。
8
+
9
+ ## Background
10
+ - 你是“谁是卧底”游戏中的一个玩家;
11
+ - 你获得的关键词是:{};
12
+
13
+ ## Skills
14
+ - 熟悉“谁是卧底”的游戏规则,了解游戏的胜利条件;
15
+ - 了解“谁是卧底”游戏的制胜技巧;
16
+
17
+ ## Commands
18
+ - /describe:用简短的一句话描述自己得到的关键词,禁止直接说出关键词。
19
+ - /vote:从玩家列表中选择一个,得票最多的玩家将会被投票出局。
20
+
21
+ ## Constraints
22
+ - 不能直接说出或暗示自己的关键词;
23
+ - 描述的内容必须符合关键词;
24
+ - 描述的内容不能与已有的描述相同;
25
+ - 在不确定自己的身份时,描述应该尽可能模糊,避免暴露;
26
+ - 描述内容必须小于20字,禁止输出与描述无关的额外内容;
27
+ - 投票时只能回复玩家id,不能输出任何额外内容;
28
+
29
+ ## Workflows
30
+ 1. 判断需要执行的动作
31
+ 1.1 如果命令为"/describe",则需要描述关键词
32
+ a. 接收关键词,代表在游戏中的身份。
33
+ b. 构思一句话来描述自己的关键词。这句话应尽量模糊或广义,避免直接暴露具体信息,但也要足够合理,以免引起其他玩家的怀疑。
34
+ - 例如,如果关键词是“苹果”,玩家可以描述为:“这是一个很常见的水果。”
35
+ c. 分析其他玩家对其关键词的描述,尝试找出其中的模糊之处或与自己关键词的差异点。
36
+ - 注意关键词之间的微妙差异,例如“苹果”和“橙子”,可能有类似的描述,但在细节上会有区别。
37
+ d. 根据其他玩家的描述和场上的讨论情况,调整自己的策略,如果有必要,稍微修改自己的描述以避免暴露。
38
+ e. 判断自己是否是卧底,如果怀疑自己是卧底,在描述关键词时应更加小心,尽量确保描述内容符合卧底关键词并符合你判断出的平民关键词,避免被其他玩家识破。
39
+ f. 生成最终不超过20字的描述,避免直接暴露关键词。
40
+ 1.2 如果命令为"/vote",则需要投票,将你认为敌对阵营的玩家投票出局
41
+ a. 接收所有玩家的描述历史记录;
42
+ - 特别关注与自己描述相似的玩家,这些玩家有可能是同一阵营。
43
+ b. 分析历史记录,描述比较模糊的玩家,尤其是描述与自己的关键词存在明显不同的玩家,就有可能是卧底;
44
+ c. 基于自己的分析,做出投票决定,从场上存活的玩家列表中,选出你认为敌对阵营的玩家;
45
+ d. 回复投票玩家的id,不要回复额外内容。
46
+
who_is_the_spy.py ADDED
@@ -0,0 +1,226 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ from random import choices, randint
3
+ from openai import OpenAI
4
+ import json
5
+
6
+ """
7
+ 谁是卧底游戏
8
+ """
9
+
10
+ state = st.session_state
11
+
12
+ # title
13
+ st.title("谁是卧底😎")
14
+
15
+ # read the word list from the json file
16
+ with open("word_list.json", "r") as f:
17
+ word_list = json.load(f)
18
+ pass
19
+
20
+ # define the avatar dict for the players
21
+ avatar_dict = {
22
+ "host": "🐼",
23
+ "P1": "🚀",
24
+ "P2": "🚄",
25
+ "P3": "🚁",
26
+ "P4": "🚂",
27
+ "P5": "🚢",
28
+ "P6": "🚤",
29
+ "P7": "🚙",
30
+ "P8": "🚠",
31
+ "P9": "🚲",
32
+ "P10": "🚜",
33
+ "H": "🤹‍♂️",
34
+ }
35
+
36
+ # define the state of the game and save some data
37
+ ## 全局消息栈
38
+ if "messages" not in state:
39
+ state.messages = []
40
+ pass
41
+ ## 玩家列表
42
+ if "players" not in state:
43
+ state.players = []
44
+ pass
45
+ ## 玩家系统提示
46
+ if "prompt" not in state:
47
+ with open("prompt.txt", "r") as f:
48
+ state.prompt = f.read()
49
+ pass
50
+ pass
51
+
52
+ # create a new OpenAI client and define the generation function
53
+ if "client" not in state:
54
+ state.client = OpenAI(
55
+ api_key="internlm2",
56
+ base_url="http://0.0.0.0:23333/v1"
57
+ )
58
+ state.model_name = state.client.models.list().data[0].id
59
+ pass
60
+ def response(messages):
61
+ return state.client.chat.completions.create(
62
+ model=state.model_name,
63
+ messages=messages,
64
+ temperature=0.5,
65
+ ).choices[0].message.content
66
+
67
+ # settings
68
+ ## 记录轮次
69
+ if "max_round" not in state:
70
+ state.max_round = 100
71
+ pass
72
+ if "round" not in state:
73
+ state.round = 0
74
+ pass
75
+ ## 侧边栏设置游戏,包括关键词,人数,回合数等
76
+ with st.sidebar:
77
+ st.write("游戏设置")
78
+ with st.form(key="game_setting"):
79
+ if "words" not in state:
80
+ words_num = randint(0, len(word_list)-1)
81
+ state.words = word_list[words_num]
82
+ total_num = st.number_input("总人数", 5, 10, 5)
83
+ spy_num = st.number_input("卧底人数", 1, total_num//2, 1)
84
+ max_round = st.number_input("最大回合数", 5, 10, 10)
85
+
86
+ submitted = st.form_submit_button("保存设置")
87
+
88
+ ## 提交后保存设置,初始化玩家、消息栈等
89
+ if submitted:
90
+ # print("游戏设置已保存")
91
+ state.spy_word = state.words["spy_word"] # 卧底关键词
92
+ state.civilian_word = state.words["civilian_word"] # 平民关键词
93
+ state.total_num = total_num # 总人数
94
+ state.spy_num = spy_num # 卧底人数
95
+ state.max_round = max_round # 最大回合数
96
+ ## 初始化玩家列表,人类玩家和AI玩家分开存
97
+ human_dignity = randint(0,1) # 人类玩家的身份,0: 平民 1: 卧底
98
+ if human_dignity == 0:
99
+ state.players = [{"id": "H", "dignity": "civilian"}]
100
+ st.write("你的关键词是{}".format(state.civilian_word))
101
+ pass
102
+ else:
103
+ state.players = [{"id": "H", "dignity": "spy"}]
104
+ st.write("你的关键词是{}".format(state.spy_word))
105
+ pass
106
+ state.players += [{"id":"P"+str(i+1)} for i in range(total_num-1)]
107
+ if human_dignity == 1 and state.spy_num-1 == 0:
108
+ spy_id = []
109
+ pass
110
+ else:
111
+ spy_id = choices([f"P{a}" for a in list(range(1,total_num))], k=state.spy_num)
112
+ pass
113
+ for each in state.players:
114
+ if each["id"] in spy_id:
115
+ each["dignity"] = "spy"
116
+ pass
117
+ else:
118
+ each["dignity"] = "civilian"
119
+ pass
120
+ pass
121
+ pass
122
+ pass
123
+ pass
124
+
125
+ # 消息显示窗口
126
+ with st.container(height=300):
127
+ for message in state.messages:
128
+ with st.chat_message(message["id"], avatar=avatar_dict[message["id"]]):
129
+ st.text(message["id"])
130
+ st.write(message["message"])
131
+ pass
132
+ # 游戏主体环节
133
+ if state.round < state.max_round:
134
+ if "description" not in state:
135
+ state.description = []
136
+ pass
137
+ ## 控制游戏轮次及开始
138
+ start = st.button("开始第{}轮游戏".format(state.round+1))
139
+ if start:
140
+ if "round" not in state:
141
+ state.round = 0
142
+ pass
143
+ state.messages.append({"id":"host", "message":f"第{state.round+1}轮游戏开始"})
144
+ ## 生成描述环节
145
+ for player in state.players:
146
+ ## 如果是人类玩家,跳过
147
+ if player["id"] == "H":
148
+ continue
149
+ if player["dignity"] == "spy":
150
+ text = response([
151
+ {"role":"system", "content":state.prompt.format(state.spy_word)},
152
+ {"role":"system", "content":"/describe "+"请根据描述历史记录描述你的关键词,需要注意不能与已有的描述重复,下面是描述历史记录:\n"+"\n".join(state.description)}
153
+ ])
154
+ else:
155
+ text = response([
156
+ {"role":"system", "content":state.prompt.format(state.civilian_word)},
157
+ {"role":"system", "content":"/describe "+"请根据描述历史记录描述你的关键词,下面是描述历史记录:\n"+"\n".join(state.description)}
158
+ ])
159
+ pass
160
+ state.messages.append({"id":player["id"], "message": text})
161
+ state.description.append(player["id"] + ":" + text)
162
+ pass
163
+ st.rerun()
164
+ pass
165
+ ## 投票环节, AI玩家生成回复,最后由人类玩家统计并选择投票对象
166
+ col1, col2 = st.columns([8,2])
167
+ with col1:
168
+ vote_id = st.selectbox("投票对象", [a["id"] for a in state.players])
169
+ pass
170
+ with col2:
171
+ if st.button("开始投票"):
172
+ for player in state.players:
173
+ if player["id"] == "H":
174
+ continue
175
+ text = response([
176
+ {"role":"system", "content":state.prompt.format(state.spy_word)},
177
+ {"role":"system", "content":"/vote "+"请根据描述历史记录选择要投出的玩家,下面是描述历史记录:\n"+"\n".join(state.description)+"\n"+"当前场上存活玩家id为:\n"+",".join([a["id"] for a in state.players])}
178
+ ])
179
+ state.messages.append({"id":player["id"], "message": text})
180
+ pass
181
+ st.rerun()
182
+ pass
183
+ pass
184
+ if st.button("投出玩家"):
185
+ state.messages.append({"id":"host", "message":f"玩家{vote_id}被投票出局"})
186
+ state.round += 1
187
+ for player in state.players:
188
+ if player["id"] == vote_id:
189
+ state.players.remove(player)
190
+ break
191
+ pass
192
+ ## 验证是否还有卧底存活
193
+ spy_live = False
194
+ for player in state.players:
195
+ if player["dignity"] == "spy":
196
+ spy_live = True
197
+ break
198
+ pass
199
+ if not spy_live and state.players:
200
+ state.messages.append({"id":"host", "message":"平民胜利!"})
201
+ pass
202
+ elif spy_live:
203
+ ## 统计当前卧底人数,如果占据一半以上则卧底胜利
204
+ spy_num = 0
205
+ for player in state.players:
206
+ if player["dignity"] == "spy":
207
+ spy_num += 1
208
+ pass
209
+ pass
210
+ if spy_num >= len(state.players)//2:
211
+ state.messages.append({"id":"host", "message":"卧底胜利!"})
212
+ pass
213
+ st.rerun()
214
+ pass
215
+ human_live = False
216
+ for player in state.players:
217
+ if player["id"] == "H":
218
+ human_live = True
219
+ break
220
+ pass
221
+ if human_live:
222
+ if des := st.chat_input():
223
+ state.messages.append({"id":"H", "message":des})
224
+ state.description.append("H:"+des)
225
+ st.rerun()
226
+
word_list.json ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [
2
+ {"spy_word": "苹果", "civilian_word": "橙子"},
3
+ {"spy_word": "饺子", "civilian_word": "包子"},
4
+ {"spy_word": "公交车", "civilian_word": "地铁"},
5
+ {"spy_word": "铅笔", "civilian_word": "圆珠笔"},
6
+ {"spy_word": "面包", "civilian_word": "蛋糕"},
7
+ {"spy_word": "白菜", "civilian_word": "青菜"},
8
+ {"spy_word": "火车", "civilian_word": "高铁"},
9
+ {"spy_word": "自行车", "civilian_word": "电动车"},
10
+ {"spy_word": "西瓜", "civilian_word": "哈密瓜"},
11
+ {"spy_word": "鞋子", "civilian_word": "袜子"},
12
+ {"spy_word": "葡萄", "civilian_word": "提子"},
13
+ {"spy_word": "牛奶", "civilian_word": "酸奶"},
14
+ {"spy_word": "电脑", "civilian_word": "手机"},
15
+ {"spy_word": "冬天", "civilian_word": "夏天"},
16
+ {"spy_word": "红酒", "civilian_word": "白酒"},
17
+ {"spy_word": "台灯", "civilian_word": "吊灯"},
18
+ {"spy_word": "篮球", "civilian_word": "足球"},
19
+ {"spy_word": "洗衣机", "civilian_word": "烘干机"},
20
+ {"spy_word": "桌子", "civilian_word": "椅子"},
21
+ {"spy_word": "手表", "civilian_word": "钟表"},
22
+ {"spy_word": "书包", "civilian_word": "钱包"},
23
+ {"spy_word": "枕头", "civilian_word": "被子"},
24
+ {"spy_word": "雨伞", "civilian_word": "雨衣"},
25
+ {"spy_word": "咖啡", "civilian_word": "茶"},
26
+ {"spy_word": "牙刷", "civilian_word": "牙膏"},
27
+ {"spy_word": "饼干", "civilian_word": "面包"},
28
+ {"spy_word": "收音机", "civilian_word": "电视"},
29
+ {"spy_word": "打印机", "civilian_word": "复印机"},
30
+ {"spy_word": "口香糖", "civilian_word": "薄荷糖"},
31
+ {"spy_word": "牛排", "civilian_word": "烤肉"},
32
+ {"spy_word": "汤", "civilian_word": "粥"},
33
+ {"spy_word": "花生", "civilian_word": "核桃"},
34
+ {"spy_word": "漫画", "civilian_word": "动画"},
35
+ {"spy_word": "日历", "civilian_word": "时钟"},
36
+ {"spy_word": "糖果", "civilian_word": "巧克力"},
37
+ {"spy_word": "吉他", "civilian_word": "小提琴"},
38
+ {"spy_word": "空调", "civilian_word": "风扇"},
39
+ {"spy_word": "牛仔裤", "civilian_word": "短裤"},
40
+ {"spy_word": "咖喱", "civilian_word": "火锅"},
41
+ {"spy_word": "面条", "civilian_word": "米饭"},
42
+ {"spy_word": "耳机", "civilian_word": "音响"},
43
+ {"spy_word": "摩托车", "civilian_word": "电动车"},
44
+ {"spy_word": "键盘", "civilian_word": "鼠标"},
45
+ {"spy_word": "钟", "civilian_word": "表"},
46
+ {"spy_word": "口红", "civilian_word": "唇膏"},
47
+ {"spy_word": "蛋挞", "civilian_word": "蛋糕"},
48
+ {"spy_word": "香水", "civilian_word": "花露水"},
49
+ {"spy_word": "西装", "civilian_word": "礼服"},
50
+ {"spy_word": "毛巾", "civilian_word": "浴巾"},
51
+ {"spy_word": "电饭锅", "civilian_word": "微波炉"}
52
+ ]