软件工程Lab4

第一次制作中秋博饼小游戏的心得与吐槽

  • 一、我想说的
  • 二、实现的功能
  • 三、编译工具
  • 四、步骤
    • 下载并打开Qt Designer
    • 设计自己的UI
      • UI简介
      • 转换为.py文件
  • 五、核心代码分析
    • 随机数生成
    • 点数统计
    • 博饼规则&判断奖励
  • 六、完整代码
  • 七、缺憾

一、我想说的

这软工老师真的犬や豚には及ばない!comme la merde du chien et cochon!

二、实现的功能

点击开始游戏(单人模式),进入博饼,自动生产6个骰子的点数,并判断玩家本次博饼的结果(奖励):
软件工程Lab4_第1张图片

三、编译工具

Qt Designer (基本UI可视化设计)
Pycharm/Jupyter Notebook (功能程序设计)

四、步骤

下载并打开Qt Designer

  1. 一般Qt在Anaconda下载时就自带了。
  2. D盘 > Anaconda > Lib > site-packages > qt5_applications > Qt > bin >designer.exe (不同用户可能位置略有差异)

设计自己的UI

UI简介

这里我就简单介绍下我这次项目的各个控件的功能,具体使用方法请参考:参考1 参考2 参考3
软件工程Lab4_第2张图片

  1. Label控件更名为Background,用于插入背景图片,右键置于底层:
    软件工程Lab4_第3张图片
    该图片被更名为1.jpg并存放于名为image的文件夹内。同时,我用XML格式写一个.qrc文件,将上述图片的相对路径添加进去。具体如何使用请参考:Qt designer 插入背景图片方法
  2. Push Button控件更名为StartGame,这样直接点击是无法有任何反应的,若要实现点击后与用户的交互功能(如显示游戏结果等)则需要增加“信号/槽slot”:
    软件工程Lab4_第4张图片
    拖动需要增加功能的控件会出现如下界面:
    软件工程Lab4_第5张图片
    软件工程Lab4_第6张图片
  3. 另外我还自定义了windowIcon的图标为骰子,toolTip设置了控件提示(提示工具在鼠标移动到指定元素后触发)。按照自己的需求设计,这里不过多赘述。

转换为.py文件

一切就绪后,我将其命名为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

博饼规则&判断奖励

闽南地区可能有不同的博饼规则,但大同小异,我选择的规则如下:
软件工程Lab4_第7张图片
根据结果判断规则表示的难易度,我进行了如图5个类型的划分,判断顺序为12345。
软件工程Lab4_第8张图片
软件工程Lab4_第9张图片

# 判断是否为“六博红/六博黑”
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_())

七、缺憾

  1. 不是使用微信开发者工具:成品不是微信小程序
  2. 仅实现单人模式,未实现多人联机功能
  3. 判断结果的方法仍需要改进,暂时无法打包成函数多次调用以达到减少代码目的
  4. 游戏界面优化的问题

你可能感兴趣的