大家好,我是一名自学Python的高一学生,这是我写的第一篇博客,还请各位多多指教。本文中,我们将用Python制作一个谁是卧底的APP。我制作这个APP的初衷是在和小伙伴一起玩谁是卧底的时候,可以省略掉裁判这个角色,让所有人都可以一起来玩,所以发言方法和投票方法还是和卡片的方法一样的。
我们将用到:
- sys(标准库)
- random(标准库)
- time(标准库)
- PyQt5(第三方库)
制作思路
- 导入将要使用的词组文件
- 制作 输入玩家数量 的界面
- 用得到的玩家数量制作 输入玩家昵称 的界面
- 制作 游戏设置 界面
- 随机分配角色并随机选择一组词组
- 制作 玩家查看词组 界面
- 制作 玩家淘汰 界面
- 判定游戏是否结束
- 结束 界面
- 本局回顾 界面
- 再来一局 界面
词组导入
使用 open函数 打开储存词组的文件 (此处路径可以使用os库 ,由于本人太懒所有没有用 ),并将词组分离保存进入一个列表以便之后使用。第三行的文件路径,需要修改为保持文件的路径,(若与我的储存方法不同)第七行的词组分离方法也需要修改为分离储存词组的方法。
def CZ(self):
'''词组导入'''
file = open('/Volumes/E/词组.csv','r',encoding='gbk') #打开文件的路径需要修改
#将词组保持进一个列表
self.dycz = []
for line in file: #需要按照文件储存方法修改
self.dycz.append(line.strip('\n').split(','))
file.close()
输入玩家数量
此界面中只有一个输入行(QLineEdit)和一个确认按钮(QPushButton),确认按钮点击后 或 键盘上的enter/return按下后 将前往 输入玩家昵称 的界面
def startWindow(self):
'''主界面'''
self.SZWJSL = QLineEdit(self) #设置玩家数量
self.SZWJSL.setPlaceholderText('请输入玩家数量')
self.SZWJSL.returnPressed.connect(self.setting)
self.SZWJSL.setGeometry(25,25,350,25)
self.QR = QPushButton('确认',self)
self.QR.move(400,25)
self.QR.clicked.connect(self.setting)
self.setGeometry(50,100,500,75)
self.setWindowTitle('谁是卧底')
self.show()
输入玩家昵称
此处的界面会按照玩家数量而自行改变,玩家数量的不同将直接影响界面的大小以及输入行的数量,用 for循环 和 列表 的方法可以确保玩家数量在什么数都可以完成界面的制作。
def setting(self):
self.SZWJSL.hide()
self.QR.hide()
self.WJNC = [] #玩家昵称QLineEdit
for num in range(0,int(self.SZWJSL.text())):
self.WJNC.append(QLineEdit(self))
self.WJNC[num].setGeometry(25, 25 + 50 * num, 350, 25)
self.WJNC[num].setPlaceholderText('请输入玩家昵称')
self.WJNC[num].show()
self.SZQR = QPushButton('确认', self)
self.SZQR.move(400, 25)
self.SZQR.clicked.connect(self.SZNC)
self.SZQR.show()
self.setGeometry(50, 100, 500, 25 + 50 * int(self.SZWJSL.text()))
self.repaint()
设置角色数量
此处为角色数量设置界面,这里有两个输入行一个是 卧底玩家数量 还有一个是 白板玩家数量 ,确认按键点击后将前往角色分配以及词组分配。(此处setPlaceholderText函数中的 推荐角色数量 可加可不加)
同时,这个函数会将 玩家昵称 界面中填写的昵称保存到一个列表(list)中。
def SZNC(self):
self.WJMC = [] #玩家名称
for name in range(0,int(self.SZWJSL.text())):
self.WJMC.append(self.WJNC[name].text())
print(self.WJMC,end='\n\n')
for LE in self.WJNC:
LE.hide()
self.repaint()
self.SZQR.hide()
self.WDsl = QLabel('卧底数量',self)
self.WDsl.move(25,25)
self.WDsl.show()
self.wdsl = QLineEdit(self)
self.wdsl.setPlaceholderText('推荐卧底数量:{}人'.format(int(int(self.SZWJSL.text())/2-1)))
self.wdsl.move(100,25)
self.wdsl.show()
self.BBsl = QLabel('白板数量',self)
self.BBsl.move(25,75)
self.BBsl.show()
self.bbsl = QLineEdit(self)
self.bbsl.setPlaceholderText('推荐白板数量:{}人'.format(int(int(self.SZWJSL.text())/2-2)))
self.bbsl.move(100,75)
self.bbsl.show()
self.szqr = QPushButton('确认',self)
self.szqr.move(150,125)
self.szqr.clicked.connect(self.FPCZ)
self.szqr.show()
self.setGeometry(50,100,250,175)
self.repaint()
角色和词组的分配
首先我们先确认每个角色的数量,并将其保存到一个列表中。并给每个角色一个编号,如:好人为0号,卧底为1号,白板为2号;这里为每个角色编号可以方便确认每个玩家的身份并方便给与词组。
此时用 random库 为每个玩家分配角色,并用 random库 随机选择一对词组,接下来将每个玩家的 玩家昵称 , 玩家身份 , 玩家词组 保持进一个单独的列表,并将这个列表保持进一个统一列表,并将每个玩家的顺序打乱,这样只要自己不说就不会有人知道身份了,但是顺序打乱了之后需要将白板移开第一位 (因为玩家叙述顺序为领词的顺序,将白板移开第一位可以保证白板玩家的公平性) ,此处我同样使用了random库。
同时,额外创造四个列表分别为 好人 ,卧底 , 白板 , 词组 并复制一份以便之后使用
def FPCZ(self):
self.JSSL = [] #角色数量
self.JSSL.append(int(self.SZWJSL.text())-int(self.wdsl.text())-int(self.bbsl.text()))
self.JSSL.append(int(self.wdsl.text()))
self.JSSL.append(int(self.bbsl.text()))
print(self.JSSL,end='\n\n')
self.WJMCcopy = self.WJMC.copy()
self.wj = [] #玩家
self.HaoRen = [] #好人 -- 0
self.WoDi = [] #卧底 -- 1
self.BaiBan = [] #白板 -- 2
role = 0
for num in self.JSSL:
num = int(num)
for JSnum in range(num):
JSrole = []
player = random.choice(self.WJMCcopy)
JSrole.append(player)
JSrole.append(role)
if role == 0:
self.HaoRen.append(player)
if role == 1:
self.WoDi.append(player)
if role == 2:
self.BaiBan.append(player)
self.wj.append(JSrole)
self.WJMCcopy.remove(player)
role += 1
print(self.wj,end='\n\n')
print('好人:{}'.format(','.join(self.HaoRen)))
print('卧底:{}'.format(','.join(self.WoDi)))
print('白板:{}'.format(','.join(self.BaiBan)),end='\n\n')
self.HaoRenCopy = self.HaoRen.copy()
self.WoDiCopy = self.WoDi.copy()
self.BaiBanCopy = self.BaiBan.copy()
self.words = random.choice(self.dycz)
self.dycz.remove(self.words)
# f = open('/Volumes/E/词组.csv', 'w', encoding='gbk')
# for row in self.dycz:
# f.write(','.join(row) + '\n')
# f.close()
print('本次词组:{}'.format(','.join(self.words),end='\n\n'))
#顺序互换
wjWordcopy = []
for num in range(len(self.wj)):
WJword = []
WJword.append(self.wj[num][0])
WJword.append(self.wj[num][1])
if self.wj[num][1] == 0:
WJword.append(self.words[0])
if self.wj[num][1] == 1:
WJword.append(self.words[1])
if self.wj[num][1] == 2:
WJword.append(' ')
wjWordcopy.append(WJword)
wjWordtwo = []
for num in range(len(wjWordcopy)):
hl = random.choice(wjWordcopy)
wjWordtwo.append(hl)
wjWordcopy.remove(hl)
self.wjWord = [] #互换后的信息列表
for num in range(len(wjWordtwo)):
hl = random.choice(wjWordtwo)
self.wjWord.append(hl)
wjWordtwo.remove(hl)
while self.wjWord[0][1] == 2: #判定白板位置并调整
WanJia = self.wjWord[0]
self.wjWord.remove(WanJia)
WeiZhi = random.randint(1,len(self.wjWord))
self.wjWord.insert(WeiZhi,WanJia)
print(self.wjWord, end='\n\n')
self.WDsl.hide()
self.wdsl.hide()
self.BBsl.hide()
self.bbsl.hide()
self.szqr.hide()
# self.XYW = QLabel(self)
# self.XYW.setText('请 ' + self.wjWord[0][0]+' 查看他的词语')
# self.XYW.setGeometry(35,35,190,25)
# self.XYW.show()
# self.XYWbtn = QPushButton('查看',self)
# self.XYWbtn.move(150,75)
# self.XYWbtn.clicked.connect(self.tellPW)
# self.XYWbtn.show()
# self.setGeometry(50,100,260,125)
# self.repaint()
# self.rs = 0
玩家查看词组
此处使用了子窗口,可以确保玩家仅查看自己的词组,而 查看的顺序就是之前打乱的顺序 。主窗口会显示 “请某某某查看他的词组” 并有一个 确认按键 ,按键点击之后,主窗口将隐藏并显示子窗口,子窗口将显示 玩家昵称 , 玩家词组 以及 确认按钮。确认点击后,子窗口会隐藏并显示主窗口请下一位玩家查看。以此类推,直到所有玩家查看结束后,将直接前往 淘汰人选 界面。 (若玩家为白板,子界面将只显示 玩家昵称 和 确认按钮)
self.XYW = QLabel(self)
self.XYW.setText('请 ' + self.wjWord[0][0]+' 查看他的词语')
self.XYW.setGeometry(35,35,190,25)
self.XYW.show()
self.XYWbtn = QPushButton('查看',self)
self.XYWbtn.move(150,75)
self.XYWbtn.clicked.connect(self.tellPW)
self.XYWbtn.show()