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的Flask框架中使用模版的入门教程
Apr 20 Python
Python 两个列表的差集、并集和交集实现代码
Sep 21 Python
使用python实现接口的方法
Jul 07 Python
Python实现简单的获取图片爬虫功能示例
Jul 12 Python
python机器学习之随机森林(七)
Mar 26 Python
Python小白必备的8个最常用的内置函数(推荐)
Apr 03 Python
详解Python静态网页爬取获取高清壁纸
Apr 23 Python
python文档字符串(函数使用说明)使用详解
Jul 30 Python
详解Python并发编程之创建多线程的几种方法
Aug 23 Python
jupyter notebook 的工作空间设置操作
Apr 20 Python
基于nexus3配置Python仓库过程详解
Jun 15 Python
浅谈django不使用restframework自定义接口与使用的区别
Jul 15 Python
python开发制作好看的时钟效果
关于的python五子棋的算法
python开发人人对战的五子棋小游戏
python pygame 开发五子棋双人对弈
May 02 #Python
Python开发简易五子棋小游戏
May 02 #Python
Python开发五子棋小游戏
python获取带有返回值的多线程
May 02 #Python
You might like
PHP获取网页所有连接的方法(附demo源码下载)
2016/03/30 PHP
PHP设计模式之原型设计模式原理与用法分析
2018/04/25 PHP
PHP Beanstalkd消息队列的安装与使用方法实例详解
2020/02/21 PHP
js 内存释放问题
2010/04/25 Javascript
JQuery FlexiGrid的asp.net完美解决方案 dotNetFlexGrid-.Net原生的异步表格控件
2010/09/12 Javascript
javascript笔记 String类replace函数的一些事
2011/09/22 Javascript
浏览器解析js生成的html出现样式问题的解决方法
2012/04/16 Javascript
通过js获取div的background-image属性
2013/10/15 Javascript
js/jquery判断浏览器的方法小结
2014/09/02 Javascript
JQuery插件jcarousellite的参数中文说明
2015/05/11 Javascript
javascript框架设计之浏览器的嗅探和特征侦测
2015/06/23 Javascript
基于jQuery实现选取月份插件附源码下载
2015/12/28 Javascript
第十篇BootStrap轮播插件使用详解
2016/06/21 Javascript
AngularJs 禁止模板缓存的方法
2017/11/28 Javascript
vue-star评星组件开发实例
2018/03/01 Javascript
Vue Router的懒加载路径的解决方法
2018/06/21 Javascript
详解vue如何使用rules对表单字段进行校验
2018/10/17 Javascript
从组件封装看Vue的作用域插槽的实现
2019/02/12 Javascript
JavaScript中的this/call/apply/bind的使用及区别
2020/03/06 Javascript
JQuery Ajax如何实现注册检测用户名
2020/09/25 jQuery
python实现simhash算法实例
2014/04/25 Python
python实现用于测试网站访问速率的方法
2015/05/26 Python
对numpy数据写入文件的方法讲解
2018/07/09 Python
python实现自动网页截图并裁剪图片
2018/07/30 Python
对Python强大的可变参数传递机制详解
2019/06/13 Python
Python实现中值滤波去噪方式
2019/12/18 Python
pytorch之添加BN的实现
2020/01/06 Python
Macbook安装Python最新版本、GUI开发环境、图像处理、视频处理环境详解
2020/02/17 Python
关于Python 中的时间处理包datetime和arrow的方法详解
2020/03/19 Python
Django用户登录与注册系统的实现示例
2020/06/03 Python
Scrapy实现模拟登录的示例代码
2021/02/21 Python
宿舍卫生检讨书
2014/01/16 职场文书
测试工程师程序员求职信范文
2014/02/20 职场文书
董事长助理工作职责
2014/06/08 职场文书
2014法院四风问题对照检查材料思想汇报
2014/10/04 职场文书
实习协议书
2015/01/27 职场文书