这软工老师真的犬や豚には及ばない!comme la merde du chien et cochon!
点击开始游戏(单人模式),进入博饼,自动生产6个骰子的点数,并判断玩家本次博饼的结果(奖励):
Qt Designer (基本UI可视化设计)
Pycharm/Jupyter Notebook (功能程序设计)
这里我就简单介绍下我这次项目的各个控件的功能,具体使用方法请参考:参考1 参考2 参考3
Label
控件更名为Background
,用于插入背景图片,右键置于底层:1.jpg
并存放于名为image
的文件夹内。同时,我用XML格式写一个.qrc
文件,将上述图片的相对路径添加进去。具体如何使用请参考:Qt designer 插入背景图片方法Push Button
控件更名为StartGame
,这样直接点击是无法有任何反应的,若要实现点击后与用户的交互功能(如显示游戏结果等)则需要增加“信号/槽slot”:windowIcon
的图标为骰子,toolTip
设置了控件提示(提示工具在鼠标移动到指定元素后触发)。按照自己的需求设计,这里不过多赘述。一切就绪后,我将其命名为Game
并会默认保存为.ui
文件,该文件类型打开后是这样的(你看得懂吗?反正我看不懂,寄!):
<ui version="4.0">
<class>Formclass>
<widget class="QWidget" name="Form">
<property name="geometry">
<rect>
<x>0x>
<y>0y>
<width>297width>
<height>300height>
rect>
property>
<property name="windowTitle">
<string>好兄弟博饼string>
property>
<property name="windowIcon">
<iconset>
<normaloff>Desktop/骰子图标.jpgnormaloff>Desktop/骰子图标.jpgiconset>
property>
<property name="toolTip">
<string><html><head/><body><p align="center">点击开始博饼</p></body></html>string>
property>
<widget class="QPushButton" name="StartGame">
<property name="geometry">
<rect>
<x>100x>
<y>260y>
<width>93width>
<height>28height>
rect>
property>
<property name="toolTip">
<string><html><head/><body><p>点击开始博饼</p></body></html>string>
property>
<property name="text">
<string>开始游戏string>
property>
<property name="autoDefault">
<bool>falsebool>
property>
<property name="flat">
<bool>falsebool>
property>
widget>
<widget class="QLabel" name="Background">
<property name="geometry">
<rect>
<x>0x>
<y>0y>
<width>301width>
<height>301height>
rect>
property>
<property name="text">
<string/>
property>
<property name="pixmap">
<pixmap resource="Desktop/picture.qrc">:/image/1.jpgpixmap>
property>
widget>
<zorder>Backgroundzorder>
<zorder>StartGamezorder>
widget>
<resources>
<include location="Desktop/picture.qrc"/>
resources>
<connections>
<connection>
<sender>StartGamesender>
<signal>clicked()signal>
<receiver>Formreceiver>
<slot>show_message()slot>
<hints>
<hint type="sourcelabel">
<x>192x>
<y>260y>
hint>
<hint type="destinationlabel">
<x>296x>
<y>252y>
hint>
hints>
connection>
connections>
<slots>
<slot>show_message()slot>
slots>
ui>
若要使用Python进行程序的编写,所以还需要将其转换为.py
格式的文件才行,在命令行中使用如下一行代码可以实现转换:
pyuic5 -o Game.py Game.ui # Game为文件名,可按需修改
另外,上文提到的用于添加背景图路径的.qrc
文件也需要进行类似转换,否则会报错,命令行输入(参考文章):
pyrcc5 -o picture.py picture.qrc # picture为文件名,可按需修改
.ui
格式转.py
后如下:
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName("Form")
Form.resize(297, 300)
icon = QtGui.QIcon()
icon.addPixmap(QtGui.QPixmap("Desktop/骰子图标.jpg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) # windowIcon自定义图片
Form.setWindowIcon(icon)
self.StartGame = QtWidgets.QPushButton(Form)
self.StartGame.setGeometry(QtCore.QRect(100, 260, 93, 28))
self.StartGame.setAutoDefault(False)
self.StartGame.setFlat(False)
self.StartGame.setObjectName("StartGame") # objectName更名为StartGame
self.Background = QtWidgets.QLabel(Form)
self.Background.setGeometry(QtCore.QRect(0, 0, 301, 301))
self.Background.setText("")
self.Background.setPixmap(QtGui.QPixmap(":/image/1.jpg")) # 自定义背景图片
self.Background.setObjectName("Background") # objectName更名为Background
self.Background.raise_()
self.StartGame.raise_()
self.retranslateUi(Form)
self.StartGame.clicked.connect(Form.show_message) # StartGame控件点击后弹窗功能
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
_translate = QtCore.QCoreApplication.translate
Form.setWindowTitle(_translate("Form", "好兄弟博饼")) # windowTitle设置为“好兄弟博饼”
Form.setToolTip(_translate("Form", "点击开始博饼
")) # 设置toolTip文本
self.StartGame.setToolTip(_translate("Form", "点击开始博饼
"))
self.StartGame.setText(_translate("Form", "开始游戏")) # StartGame控件上显示“开始游戏”
import picture # 导入背景图.py文件
# 创建Die类
from random import randint
class Die():
def __init__(self,num_sides=6):
self.num_sides = num_sides
def roll(self):
#随机返回一个1到num_sides之间的数
return randint(1, self.num_sides)
# 掷骰子
die = Die()
>>> results = []
>>> for roll_num in range(6):
result = die.roll()
results.append(result)
>>> print(sorted(results))
[1, 2, 2, 4, 6, 6]
简单的词频统计,但是这里需要把点数为0的也统计进去,可以参考文章:Python词频统计
>>> sides = [1,2,3,4,5,6]
>>> countDict = {
}
>>> for i in results:
if i in countDict:
countDict[i] += 1 #对于重复出现的,每出现一次,次数增加1
else:
countDict[i] = 1
for j in sides:
if j not in results:
countDict[j] = 0
for i in range(1,7):
print(f'六粒骰子中 {
i} 的个数为:{
countDict[i]}')
六粒骰子中 1 的个数为:1
六粒骰子中 2 的个数为:2
六粒骰子中 3 的个数为:0
六粒骰子中 4 的个数为:1
六粒骰子中 5 的个数为:0
六粒骰子中 6 的个数为:2
闽南地区可能有不同的博饼规则,但大同小异,我选择的规则如下:
根据结果判断规则表示的难易度,我进行了如图5个类型的划分,判断顺序为12345。
# 判断是否为“六博红/六博黑”
def sixred_or_black():
for i in range(1,7):
if countDict[i] == 6:
if i == 4:
return '六博红'
else:
return '六博黑'
# 判断是否为“状元插金花”
def chajinhua():
if countDict[4] == 4 and countDict[1] == 2:
return '状元插金花'
# 判断是否为“对堂”
def duitang():
if len(set(list(countDict.values()))) == 1:
return '对堂'
# 判断是否为“五子登科”
def wuzidengke():
if 5 in list(countDict.values()):
return '五子登科'
# 判断是否为“状元”
def zhuangyuan():
if countDict[4] == 4:
return '状元'
# 判断是否为“四进”
def sijin():
for i in range(1,7):
if countDict[i] == 4:
return '四进'
# 判断是否为“三红/二举/一秀”,否则为“无奖励”
def sanhong_erju_yixiu():
if countDict[4] == 3:
return '三红'
elif countDict[4] == 2:
return '二举'
elif countDict[4] == 1:
return '一秀'
else:
return '抱歉无奖励'
# while循环7次(上述7个函数依次判断,若符合条件则break,不符合则继续判断)
count = 7
while count:
if sixred_or_black() == None:
count -= 1
else:
print('结果为:',sixred_or_black())
break
if chajinhua() == None:
count -= 1
else:
print('结果为:',chajinhua())
break
if duitang() == None:
count -= 1
else:
print('结果为:',duitang())
break
if wuzidengke() == None:
count -= 1
else:
print('结果为:',wuzidengke())
break
if zhuangyuan() == None:
count -= 1
else:
print('结果为:',zhuangyuan())
break
if sijin() == None:
count -= 1
else:
print('结果为:',sijin())
break
if sanhong_erju_yixiu() == None:
count -= 1
else:
print('结果为:',sanhong_erju_yixiu())
break
结合上述,稍作修改,可得如下代码:
import sys # 导入sys模块
from PyQt5.QtWidgets import QMessageBox, QWidget, QApplication # 导入Qt模块
from Game import Ui_Form # 导入ui设计模块
# import picture # 导入背景图模块
from random import randint # 导入随机数函数
class Game(QWidget, Ui_Form):
# 初始化
def __init__(self):
super(Game, self).__init__()
self.setupUi(self)
# 结果展示函数
def show_message(self):
results = []
for roll_num in range(6):
result = randint(1,6)
results.append(result) # 将随机数存于列表
sides = [1,2,3,4,5,6]
countDict = {
} # 该字典用于统计和存储每个点数出现次数
for i in results:
if i in countDict:
countDict[i] += 1 # 对于重复出现的,每出现一次,次数增加1
else:
countDict[i] = 1
for j in sides: # 对于未出现的点数,记为0次
if j not in results:
countDict[j] = 0
# 函数判断结果
def sixred_or_black():
for i in range(1,7):
if countDict[i] == 6:
if i == 4:
return '六博红'
else:
return '六博黑'
def chajinhua():
if countDict[4] == 4 and countDict[1] == 2:
return '状元插金花'
def duitang():
if len(set(list(countDict.values()))) == 1:
return '对堂'
def wuzidengke():
if 5 in list(countDict.values()):
return '五子登科'
def zhuangyuan():
if countDict[4] == 4:
return '状元'
def sijin():
for i in range(1,7):
if countDict[i] == 4:
return '四进'
def sanhong_erju_yixiu():
if countDict[4] == 3:
return '三红'
elif countDict[4] == 2:
return '二举'
elif countDict[4] == 1:
return '一秀'
else:
return '抱歉无奖励'
count = 7
while count:
if sixred_or_black() == None:
count -= 1
else:
QMessageBox.about(self, '结果',f'点数分别为:{
results[0]} '
f'{
results[1]} '
f'{
results[2]} '
f'{
results[3]} '
f'{
results[4]} '
f'{
results[5]}\n'
f'你获得了:{
sixred_or_black()}')
break
if chajinhua() == None:
count -= 1
else:
QMessageBox.about(self, '结果',f'点数分别为:{
results[0]} '
f'{
results[1]} '
f'{
results[2]} '
f'{
results[3]} '
f'{
results[4]} '
f'{
results[5]}\n'
f'你获得了:{
chajinhua()}')
break
if duitang() == None:
count -= 1
else:
QMessageBox.about(self, '结果',f'点数分别为:{
results[0]} '
f'{
results[1]} '
f'{
results[2]} '
f'{
results[3]} '
f'{
results[4]} '
f'{
results[5]}\n'
f'你获得了:{
duitang()}')
break
if wuzidengke() == None:
count -= 1
else:
QMessageBox.about(self, '结果',f'点数分别为:{
results[0]} '
f'{
results[1]} '
f'{
results[2]} '
f'{
results[3]} '
f'{
results[4]} '
f'{
results[5]}\n'
f'你获得了:{
wuzidengke()}')
break
if zhuangyuan() == None:
count -= 1
else:
QMessageBox.about(self, '结果',f'点数分别为:{
results[0]} '
f'{
results[1]} '
f'{
results[2]} '
f'{
results[3]} '
f'{
results[4]} '
f'{
results[5]}\n'
f'你获得了:{
zhuangyuan()}')
break
if sijin() == None:
count -= 1
else:
QMessageBox.about(self, '结果',f'点数分别为:{
results[0]} '
f'{
results[1]} '
f'{
results[2]} '
f'{
results[3]} '
f'{
results[4]} '
f'{
results[5]}\n'
f'你获得了:{
sijin()}')
break
if sanhong_erju_yixiu() == None:
count -= 1
else:
QMessageBox.about(self, '结果',f'点数分别为:{
results[0]} '
f'{
results[1]} '
f'{
results[2]} '
f'{
results[3]} '
f'{
results[4]} '
f'{
results[5]}\n'
f'你获得了:{
sanhong_erju_yixiu()}')
break
# 退出函数
def closeEvent(self, QCloseEvent):
# 弹窗询问是否需要退出
reply = QMessageBox.question(self, '确认', '确认退出吗', QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
if reply == QMessageBox.Yes:
QCloseEvent.accpet()
else:
QCloseEvent.ignore()
if __name__ == '__main__':
app = QApplication(sys.argv)
ui = Game()
ui.show()
sys.exit(app.exec_())