Python3使用Qt5来实现简易的五子棋小游戏


Posted in Python onMay 02, 2022

要写出一个五子棋游戏,我们最先要解决的,就是如何下子,如何判断已经五子连珠,而不是如何绘制画面,因此我们先确定棋盘

五子棋采用15*15的棋盘,因此,我们可以使用二维列表来创建一个棋盘,不妨认为0表示未放置棋子,1表示放置白子,2表示放置黑子。

显而易见可以创建列表,注意不能使用*来复制列表

self.chess_board = [[0 for i in range(15)] for i in range(15)]

下棋的步骤十分好做,只需要找到对应的索引进行赋值即可,下一步应该解决如何判断五子连珠的问题。

每当我们落子结束后,应该判断是否已经完成五子连珠。对于刚放置的一颗棋子而言,可能的情况大致分为四种:

1.水平
2.斜向右下
3.竖直
4.斜向右上

要判断是否已经连珠成功,我们以刚放置的棋子为起点,先向前遍历4个棋子,并计算相同棋子的个数,一旦遇到不同的棋子,就停止,然后从起点向后遍历4个棋子,直到全部遍历完成或者棋子总数已经达到5个,就可以返回。我们只需要注意如何获得棋子的前后棋子以及棋盘的边界问题,棋子不可能超出棋盘,因此被遍历的棋子也不能超出棋盘。

以水平为例,可以得到代码

def judge_1(self,x:int,y:int) -> bool:
        count = 1
        if self.chess_board[x][y] != 0:
            for i in range(1,5):
                if y - i >= 0:
                    if self.chess_board[x][y] == self.chess_board[x][y-i]:
                        print(x,y-i)
                        count += 1
                    else:
                        break
                else:
                    break
            for i in range(1,5):
                if y + i <=14:
                    if self.chess_board[x][y] == self.chess_board[x][y+i]:
                        print(x,y+i)
                        count += 1
                    else:
                        break
                else:
                    break
        if count == 5:
            return True
        return False

以相似的步骤完成其余三种判断,就已经完成了五子棋游戏的核心要素了,剩下的就需要交给PyQt5来完成游戏的绘制来完善游戏了。

我们创建一个类来继承QWidget类,创建一个窗口,之后我们需要创建几个属性来完成储存我们的数据信息

#棋子的坐标
self.x = -1
self.y = -1
#区分玩家
#开始标签
self.flag = False
#储存已经下好的白子
self.white_chess = []
#储存已经下好的黑子
self.black_chess = []

我们已经可以开始绘制棋盘,在Qt5中,如果我们需要进行绘制,我们应该重写paintEvent方法,这个方法会由程序自动调用执行。创建一个QPainter对象,将需要绘制的内容用begin与end方法包裹起来,就可以完成绘制。

我们用drawLine方法来绘制线条,用drawEllipse方法来绘制棋子,使用setPen来更改线条样式,setBrush来更改棋子样式。

得到代码(本段代码有参考他人代码,这是我第一次接触Qt的绘制)

--------------------GUI中的x轴竖直向下,y轴水平向右,因此绘制棋子时的x与y需要颠倒---------------

#绘制棋盘与棋子
    def paintEvent(self, e) -> None:
        qp = QPainter()
        qp.begin(self)
        qp.fillRect(self.rect(), QColor("light blue"))
        qp.drawRect(self.rect())
        qp.setBackground(QColor("yellow"))
        qp.setPen(QPen(QColor(0, 0, 0), 2, Qt.SolidLine))
        for i in range(15):
            qp.drawLine(QPoint(30, 30 + 30 * i), QPoint(450, 30 + 30 * i))
        for i in range(15):
            qp.drawLine(QPoint(30 + 30 * i, 30), QPoint(30 + 30 * i, 450))
        qp.setBrush(QColor(0, 0, 0))
        key_points = [(3, 3), (11, 3), (3, 11), (11, 11), (7, 7)]
        if len(self.black_chess) != 0:
            for t in self.black_chess:
                #画黑子
                qp.drawEllipse(QPoint(30 + 30 * t[1], 30 + 30 * t[0]), 6, 6)
        for t in key_points:
            #棋盘的5个定点
            qp.drawEllipse(QPoint(30 + 30 * t[0], 30 + 30 * t[1]), 3, 3)
        qp.setBrush(QColor(255,255,255))
        if len(self.white_chess) != 0:
            for t in self.white_chess:
                #画白子
                qp.drawEllipse(QPoint(30 + 30 * t[1], 30 + 30 * t[0]), 6, 6)
        qp.end()

另一个需要在GUI中解决的问题就是,如何获取要下的棋子的坐标?我们可以通过重写鼠标事件来解决,重写单机事件mousePressEvent,并修改棋子的x坐标与y坐标即可,另外,用户不可能每次都恰巧点到我们规定的坐标点上,因此需要给出一个大致范围判断,这里我的方式是先获取坐标,然后根据坐标找到距离最近的点

def mousePressEvent(self, e) -> None:
        if e.buttons() == QtCore.Qt.LeftButton:
            if e.x() > 15 and e.x() < 465 and e.y() > 15 and e.y() < 465:
                x = e.x()/30 - e.x()//30
                y = e.y()/30 - e.y()//30
                self.y = (e.x()-30)//30 if x < 0.5 else (e.x()-30)//30 + 1
                self.x = (e.y()-30)//30 if y < 0.5 else (e.y()-30)//30 + 1
                if self.flag:
                    print(self.x,self.y)
                    if self.player % 2 == 1:
                        if goBang.put_white_chess(self.x,self.y):
                            self.player += 1 
                            print('黑子行动')
                        else:
                            print('白子行动')
                        if goBang.judge(self.x,self.y):
                            msg_box = QMessageBox(QMessageBox.Information, '提示', '白子获胜!')
                            msg_box.exec_()
                    else:
                        if goBang.put_black_chess(self.x,self.y):
                            self.player += 1
                            print('白子行动')
                        else:
                            print('黑子行动')
                        if goBang.judge(self.x,self.y):
                            msg_box = QMessageBox(QMessageBox.Information, '提示', '黑子获胜!')
                            msg_box.exec_()

每当游戏完成,我们应该可以清空棋盘,也就是将所有储存数据的变量都重新初始化再重绘棋盘

#清除棋盘,重开游戏
    def clear(self) -> None:
        self.x = -1
        self.y = -1
        self.player = 0
        self.flag = False
        self.white_chess = []
        self.black_chess = []
        self.chess_board = [[0 for i in range(15)] for i in range(15)]
        self.update()

这样就大致结束了!!

下面是全部代码:

from PyQt5 import *
from PyQt5 import QtCore
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
import sys
 
class GoBang(QWidget):
    #初始化棋盘
    def __init__(self):
        super().__init__()
        self.setWindowTitle('五子棋Hi~ o(* ̄▽ ̄*)ブ')
        self.x = -1
        self.y = -1
        #区分玩家
        self.player = 0
        #开始标签
        self.flag = False
        #储存已经下好的白子
        self.white_chess = []
        #储存已经下好的黑子
        self.black_chess = []
        self.setFixedSize(800,600)
        self.chess_board = [[0 for i in range(15)] for i in range(15)]
        btn1 = QPushButton('开始',self)
        btn1.setGeometry(500,100,50,30)
        btn1.clicked.connect(self.setFlag)
        btn2 = QPushButton('重开',self)
        btn2.setGeometry(550,100,50,30)
        btn2.clicked.connect(self.clear)
        self.show()
    
    #绘制棋盘与棋子
    def paintEvent(self, e) -> None:
        qp = QPainter()
        qp.begin(self)
        qp.fillRect(self.rect(), QColor("light blue"))
        qp.drawRect(self.rect())
        qp.setBackground(QColor("yellow"))
        qp.setPen(QPen(QColor(0, 0, 0), 2, Qt.SolidLine))
        for i in range(15):
            qp.drawLine(QPoint(30, 30 + 30 * i), QPoint(450, 30 + 30 * i))
        for i in range(15):
            qp.drawLine(QPoint(30 + 30 * i, 30), QPoint(30 + 30 * i, 450))
        qp.setBrush(QColor(0, 0, 0))
        key_points = [(3, 3), (11, 3), (3, 11), (11, 11), (7, 7)]
        if len(self.black_chess) != 0:
            for t in self.black_chess:
                #画黑子
                qp.drawEllipse(QPoint(30 + 30 * t[1], 30 + 30 * t[0]), 6, 6)
        for t in key_points:
            #棋盘的5个定点
            qp.drawEllipse(QPoint(30 + 30 * t[0], 30 + 30 * t[1]), 3, 3)
        qp.setBrush(QColor(255,255,255))
        if len(self.white_chess) != 0:
            for t in self.white_chess:
                #画白子
                qp.drawEllipse(QPoint(30 + 30 * t[1], 30 + 30 * t[0]), 6, 6)
        qp.end()
 
    #更改标签,开始游戏
    def setFlag(self) -> None:
        self.flag = True
 
    def mousePressEvent(self, e) -> None:
        if e.buttons() == QtCore.Qt.LeftButton:
            if e.x() > 15 and e.x() < 465 and e.y() > 15 and e.y() < 465:
                x = e.x()/30 - e.x()//30
                y = e.y()/30 - e.y()//30
                self.y = (e.x()-30)//30 if x < 0.5 else (e.x()-30)//30 + 1
                self.x = (e.y()-30)//30 if y < 0.5 else (e.y()-30)//30 + 1
                if self.flag:
                    print(self.x,self.y)
                    if self.player % 2 == 1:
                        if goBang.put_white_chess(self.x,self.y):
                            self.player += 1 
                            print('黑子行动')
                        else:
                            print('白子行动')
                        if goBang.judge(self.x,self.y):
                            msg_box = QMessageBox(QMessageBox.Information, '提示', '白子获胜!')
                            msg_box.exec_()
                    else:
                        if goBang.put_black_chess(self.x,self.y):
                            self.player += 1
                            print('白子行动')
                        else:
                            print('黑子行动')
                        if goBang.judge(self.x,self.y):
                            msg_box = QMessageBox(QMessageBox.Information, '提示', '黑子获胜!')
                            msg_box.exec_()
 
            
    #下白子
    def put_white_chess(self,x:int,y:int) -> bool:
        if self.chess_board[x][y] != 0:
            msg_box = QMessageBox(QMessageBox.Information, '提示', '这个位置已经有棋子了!')
            msg_box.exec_()
            return False
        else:
            self.chess_board[x][y] = 1
            self.white_chess.append((x,y))
            self.update()
            return True
 
    #下黑子
    def put_black_chess(self,x:int,y:int) -> bool:
        if self.chess_board[x][y] != 0:
            msg_box = QMessageBox(QMessageBox.Information, '提示', '这个位置已经有棋子了!')
            msg_box.exec_()
            return False
        else:
            self.chess_board[x][y] = 2
            self.black_chess.append((x,y))
            self.update()
            return True
 
    #清除棋盘,重开游戏
    def clear(self) -> None:
        self.x = -1
        self.y = -1
        self.player = 0
        self.flag = False
        self.white_chess = []
        self.black_chess = []
        self.chess_board = [[0 for i in range(15)] for i in range(15)]
        self.update()
 
    #判断是否已经五子连珠
    def judge(self,x:int,y:int) -> bool:
        if self.judge_1(x,y) or self.judge_2(x,y) or self.judge_3(x,y) or self.judge_4(x,y):
            return True
        return False
 
    #判断横线
    def judge_1(self,x:int,y:int) -> bool:
        count = 1
        if self.chess_board[x][y] != 0:
            for i in range(1,5):
                if y - i >= 0:
                    if self.chess_board[x][y] == self.chess_board[x][y-i]:
                        print(x,y-i)
                        count += 1
                    else:
                        break
                else:
                    break
            for i in range(1,5):
                if y + i <=14:
                    if self.chess_board[x][y] == self.chess_board[x][y+i]:
                        print(x,y+i)
                        count += 1
                    else:
                        break
                else:
                    break
        if count == 5:
            return True
        return False
 
    #判断右下线
    def judge_2(self,x:int,y:int) -> bool:
        count = 1
        if self.chess_board[x][y] != 0:
            for i in range(1,5):
                if x-i >= 0 and y - i >= 0:
                    if self.chess_board[x][y] == self.chess_board[x-i][y-i]:
                        print(x-i,y-i)
                        count += 1
                    else:
                        break
                else:
                    break
            for i in range(1,5):
                if x + i <= 14 and y + i <= 14:
                    if self.chess_board[x][y] == self.chess_board[x+i][y+i]:
                        print(x+i,y+i)
                        count += 1
                    else:
                        break
                else:
                    break
        if count == 5:
            return True
        return False
 
    #判断竖线
    def judge_3(self,x:int,y:int) -> bool:
        count = 1
        if self.chess_board[x][y] != 0:
            for i in range(1,5):
                if x - i >= 0:
                    if self.chess_board[x][y] == self.chess_board[x-i][y]:
                        print(x-i,y)
                        count += 1
                    else:
                        break
                else:
                    break
            for i in range(1,5):
                if x + i <= 14:
                    if self.chess_board[x][y] == self.chess_board[x+i][y]:
                        print(x+i,y)
                        count += 1
                    else:
                        break
                else:
                    break
        if count == 5:
            return True
        return False
 
    #判断右上线
    def judge_4(self,x:int,y:int) -> bool:
        count = 1
        if self.chess_board[x][y] != 0:
            for i in range(1,5):
                if x - i >= 0 and y + i <= 14:
                    if self.chess_board[x][y] == self.chess_board[x-i][y+i]:
                        print(x-i,y+i)
                        count += 1
                    else:
                        break
                else:
                    break
            for i in range(1,5):
                if x + i <= 14 and y - i >= 0:
                    if self.chess_board[x][y] == self.chess_board[x+i][y-i]:
                        print(x+i,y-i)
                        count += 1
                    else:
                        break
                else:
                    break
        if count == 5:
            return True
        return False
 
#程序入口
if __name__ == '__main__':  
    app = QApplication(sys.argv)  
    goBang = GoBang()
    sys.exit(app.exec_())

以上就是本文的全部内容,希望对大家的学习有所帮助。


Tags in this post...

Python 相关文章推荐
python的random模块及加权随机算法的python实现方法
Jan 04 Python
pandas 两列时间相减换算为秒的方法
Apr 20 Python
python判断一个集合是否为另一个集合的子集方法
May 04 Python
Python3中的列表生成式、生成器与迭代器实例详解
Jun 11 Python
Python中pip更新和三方插件安装说明
Jul 08 Python
python保存二维数组到txt文件中的方法
Nov 15 Python
python之当你发现QTimer不能用时的解决方法
Jun 21 Python
python 数据生成excel导出(xlwt,wlsxwrite)代码实例
Aug 23 Python
python删除指定列或多列单个或多个内容实例
Jun 28 Python
python 密码学示例——凯撒密码的实现
Sep 21 Python
Python3使用tesserocr识别字母数字验证码的实现
Jan 29 Python
python爬取youtube视频的示例代码
Mar 03 Python
python开发制作好看的时钟效果
关于的python五子棋的算法
python开发人人对战的五子棋小游戏
python pygame 开发五子棋双人对弈
May 02 #Python
Python开发简易五子棋小游戏
May 02 #Python
Python开发五子棋小游戏
python获取带有返回值的多线程
May 02 #Python
You might like
php知道与问问的采集插件代码
2010/10/12 PHP
解析php扩展php_curl.dll不加载的解决方法
2013/06/26 PHP
php5.5新数组函数array_column使用
2013/07/08 PHP
JavaScript 变量命名规则
2009/09/23 Javascript
JS获取客户端IP地址、MAC和主机名的7个方法汇总
2014/07/21 Javascript
js实现带关闭按钮始终显示在网页最底部工具条的方法
2015/03/02 Javascript
全面解析Bootstrap中tooltip、popover的使用方法
2016/06/13 Javascript
js实现碰撞检测特效代码分享
2016/10/16 Javascript
Vue2单一事件管理组件通信
2017/05/09 Javascript
JS switch判断 三目运算 while 及 属性操作代码
2017/09/03 Javascript
three.js加载obj模型的实例代码
2017/11/10 Javascript
详解在React里使用&quot;Vuex&quot;
2018/04/02 Javascript
vue中的provide/inject的学习使用
2018/05/09 Javascript
小程序最新获取用户昵称和头像的方法总结
2019/09/23 Javascript
[19:14]DOTA2 HEROS教学视频教你分分钟做大人-维萨吉
2014/06/24 DOTA
使用Python实现windows下的抓包与解析
2018/01/15 Python
解决python线程卡死的问题
2019/02/18 Python
详解Python用户登录接口的方法
2019/04/17 Python
100行Python代码实现每天不同时间段定时给女友发消息
2019/09/27 Python
MATCHESFASHION.COM法国官网:英国奢侈品零售商
2018/01/04 全球购物
美国牙科折扣计划:DentalPlans.com
2019/08/26 全球购物
马来西亚在线健康商店:Medipal Malaysia
2020/04/13 全球购物
英文求职信结束语大全
2013/10/26 职场文书
机电一体化自荐信
2013/12/10 职场文书
骨干教师培训感言
2014/01/16 职场文书
中学生校园广播稿
2014/01/16 职场文书
全神贯注教学反思
2014/02/03 职场文书
党支部公开承诺书
2014/03/28 职场文书
注册资产评估专业求职信
2014/07/16 职场文书
商务英语专业大学生职业生涯规划书
2014/09/14 职场文书
税务干部个人整改措施思想汇报
2014/10/10 职场文书
小班上学期幼儿评语
2014/12/30 职场文书
2015秋季幼儿园开学寄语
2015/03/25 职场文书
2015年前台个人工作总结
2015/04/03 职场文书
红十字会救护培训简讯
2015/07/20 职场文书
java设计模式--七大原则详解
2021/07/21 Java/Android