【QT项目】简易五子棋游戏(人机对战)— 完整源码
文章目录
- 前言
- 一、游戏实现效果
- 二、需求分析
- 三、解决方案
- 四、核心步骤
- 1.插入棋盘图
- 2.双方落子
- 3.输赢判定
- 4.重新开始
- 五、完整源码
- 1.main.cpp
- 2.chessboard.h
- 3.chessboard.cpp
- 总结
前言
本篇,我们将使用QT实现一个人机对战的简易五子棋游戏,适合QT零基础和初学者进行学习。
一、游戏实现效果
- 这里的电脑为简单人机,没有采用特定的算法,因此没有防守功能,有兴趣的小伙伴可以自行拓展。
二、需求分析
- 项目开始前,需要我们对项目进行简单的需求分析,知道我们应该做些什么?
(1)在窗口背景插入棋盘图
(2)玩家鼠标点击棋盘某个区域落子
(3)电脑在棋盘上某个空白区域落子
(4)输赢判定,在棋盘的水平方向、垂直方向、对角线方向是否五子连珠
(5)清空棋盘,开始新一轮游戏
三、解决方案
- 完成需求分析后,需要针对每个需求思考相应的解决方案,确保项目的可行性。
(1)在窗口内创建一个QLabel类标签用来插入棋盘图
(2)使用鼠标点击事件函数,动态创建一个标签插入棋子图,并显示在鼠标的点击位置
(3)使用随机数生成函数,在随机生成的键盘某个区域位置,用同样的方法插入棋子图
(4)创建一个二维向量容器对应棋盘的每个坐标,并使用双重循环遍历棋盘判断是否五子连珠
(5)在窗口内嵌套一个透明窗口作为棋子容器,游戏结束时,释放该窗口并重新动态创建透明窗口
四、核心步骤
1.插入棋盘图
- 我们借助QLabel标签显示图片,并将标签设置与主窗口同等大小作为背景图
//插入棋盘背景this->bg = new QLabel(this); //创建标签到主窗口中this->bg->setGeometry(0,0,810,810); //设置标签大小和位置this->bg->setPixmap(QPixmap("./picture/chessboard.png")); //将棋盘图插入到标签中this->bg->setScaledContents(true); //图片自适应标签大小
2.双方落子
- 使用鼠标点击事件,在玩家在点击位置落子,紧接着电脑利用随机数生成坐标落子
void chessboard::mousePressEvent(QMouseEvent *event)
{//若鼠标点击位置没有棋子,则玩家落子if(chess.at(event->x()/54).at(event->y()/54) == 0){//返回值判断一方是否获胜bool result = this->piecePress(PLAYERS,event->x(),event->y());//玩家胜利时,跳过电脑落子重新开始游戏if(result == true){return;}//直到生成随机数区域没有棋子,则电脑落子while(1){//生成随机横坐标int computerx = qrand()%800;//生成随机纵坐标int computery = qrand()%800;//判断该位置是否有棋子if(chess.at(computerx/54).at(computery/54) == 0){//电脑落子this->piecePress(COMPUTER,computerx,computery);break;}}}
}
- 落子显示,我们通过动态创建标签的方式显示棋子图片,并根据下棋对象显示黑棋/白棋
bool chessboard::piecePress(bool object, int x, int y)
{//动态创建标签插入棋子图,并初始化位置信息this->piece = new QLabel(this->chessWin);this->piece->setGeometry(x-x%54,y-y%54,54,54);this->piece->setScaledContents(true);//若下棋对象为玩家if(object == PLAYERS){//插入黑棋图this->piece->setPixmap(QPixmap("./picture/black.png"));//棋盘相应位置进行标记chess[x/54][y/54] = 1;}//若下棋对象为电脑else if(object == COMPUTER){//插入白棋图this->piece->setPixmap(QPixmap("./picture/white.png"));//棋盘相应位置进行标记chess[x/54][y/54] = 2;}//棋子显示this->piece->show();//输赢判定,并返回判定结果return this->winner();
}
3.输赢判定
- 在玩家/电脑每次落子之后,将通过四个不同方向扫描整个棋盘进行一次输赢判定
bool chessboard::winner()
{//横向扫描for(int i=0;i<15;i++){for(int j=0;j<11;j++){if(chess[i][j]==1 && chess[i][j+1]==1 && chess[i][j+2]==1 && chess[i][j+3]==1 && chess[i][j+4]==1){QMessageBox::information(nullptr,"温馨提示","玩家获胜!");this->newGame();return true;}else if(chess[i][j]==2 && chess[i][j+1]==2 && chess[i][j+2]==2 && chess[i][j+3]==2 && chess[i][j+4]==2){QMessageBox::information(nullptr,"温馨提示","电脑获胜!");this->newGame();return true;}}}//纵向扫描for(int j=0;j<15;j++){for(int i=0;i<11;i++){if(chess[i][j]==1 && chess[i+1][j]==1 && chess[i+2][j]==1 && chess[i+3][j]==1 && chess[i+4][j]==1){QMessageBox::information(nullptr,"温馨提示","玩家获胜!");this->newGame();return true;}else if(chess[i][j]==2 && chess[i+1][j]==2 && chess[i+2][j]==2 && chess[i+3][j]==2 && chess[i+4][j]==2){QMessageBox::information(nullptr,"温馨提示","电脑获胜!");this->newGame();return true;}}}//对角扫描for(int i=0;i<11;i++){for(int j=0;j<11;j++){if(chess[i][j]==1 && chess[i+1][j+1]==1 && chess[i+2][j+2]==1 && chess[i+3][j+3]==1 && chess[i+4][j+4]==1){QMessageBox::information(nullptr,"温馨提示","玩家获胜!");this->newGame();return true;}else if(chess[i][j]==2 && chess[i+1][j+1]==2 && chess[i+2][j+2]==2 && chess[i+3][j+3]==2 && chess[i+4][j+4]==2){QMessageBox::information(nullptr,"温馨提示","电脑获胜!");this->newGame();return true;}}}//反对角扫描for(int j=0;j<11;j++){for(int i=14;i>3;i--){if(chess[i][j]==1 && chess[i-1][j+1]==1 && chess[i-2][j+2]==1 && chess[i-3][j+3]==1 && chess[i-4][j+4]==1){QMessageBox::information(nullptr,"温馨提示","玩家获胜!");this->newGame();return true;}else if(chess[i][j]==2 && chess[i-1][j+1]==2 && chess[i-2][j+2]==2 && chess[i-3][j+3]==2 && chess[i-4][j+4]==2){QMessageBox::information(nullptr,"温馨提示","电脑获胜!");this->newGame();return true;}}}return false;
}
4.重新开始
- 游戏结束后,初始化棋盘,并释放主窗口中所有通过动态创建的标签显示的棋子图
void chessboard::newGame()
{//初始化棋盘for(int i=0;i<15;i++){for(int j=0;j<15;j++){chess[i][j] = 0;}}//释放棋盘窗口,包括棋子delete this->chessWin;//创建新棋盘窗口,并初始化this->chessWin = new QWidget(this);this->chessWin->resize(810,810);this->chessWin->show();
}
五、完整源码
1.main.cpp
#include "widget.h"
#include "chessboard.h"
#include <QApplication>int main(int argc, char *argv[])
{QApplication a(argc, argv);chessboard *five = chessboard::getInstance(); //创建棋盘窗口five->show(); //棋盘窗口显示return a.exec();
}
2.chessboard.h
#ifndef CHESSBOARD_H
#define CHESSBOARD_H#include <QLabel>
#include <QVector>
#include <QWidget>
#include <QMouseEvent>#define PLAYERS 0
#define COMPUTER 1class chessboard : public QWidget
{Q_OBJECT
public://静态公有的获取类对象指针的方法static chessboard* getInstance();//鼠标点击事件void mousePressEvent(QMouseEvent *event);//落子函数bool piecePress(bool object,int x,int y);//输赢判定函数bool winner();//重新开始游戏void newGame();
private://构造函数私有化explicit chessboard(QWidget *parent = 0);//静态私有的类对象指针static chessboard* pchessboard;//棋盘图片QLabel *bg;//棋子图片QLabel *piece;//棋盘落子情况:0无棋子,1有棋子static QVector<QVector<int>> chess;//棋盘窗口QWidget *chessWin;
signals:public slots:
};#endif // CHESSBOARD_H
3.chessboard.cpp
#include <QTime>
#include <QtGlobal>
#include <QMessageBox>
#include "chessboard.h"QVector<QVector<int>> chessboard::chess;
chessboard* chessboard::pchessboard = nullptr; chessboard *chessboard::getInstance()
{if(chessboard::pchessboard == nullptr){chessboard::pchessboard = new chessboard();}return chessboard::pchessboard;
}void chessboard::mousePressEvent(QMouseEvent *event)
{//若鼠标点击位置没有棋子,则玩家落子if(chess.at(event->x()/54).at(event->y()/54) == 0){//返回值判断一方是否获胜bool result = this->piecePress(PLAYERS,event->x(),event->y());//玩家胜利时,跳过电脑落子重新开始游戏if(result == true){return;}//直到生成随机数区域没有棋子,则电脑落子while(1){//生成随机横坐标int computerx = qrand()%800;//生成随机纵坐标int computery = qrand()%800;//判断该位置是否有棋子if(chess.at(computerx/54).at(computery/54) == 0){//电脑落子this->piecePress(COMPUTER,computerx,computery);break;}}}
}bool chessboard::piecePress(bool object, int x, int y)
{//动态创建标签插入棋子图,并初始化位置信息this->piece = new QLabel(this->chessWin);this->piece->setGeometry(x-x%54,y-y%54,54,54);this->piece->setScaledContents(true);//若下棋对象为玩家if(object == PLAYERS){//插入黑棋图this->piece->setPixmap(QPixmap("./picture/black.png"));//棋盘相应位置进行标记chess[x/54][y/54] = 1;}//若下棋对象为电脑else if(object == COMPUTER){//插入白棋图this->piece->setPixmap(QPixmap("./picture/white.png"));//棋盘相应位置进行标记chess[x/54][y/54] = 2;}//棋子显示this->piece->show();//输赢判定,并返回判定结果return this->winner();
}bool chessboard::winner()
{//横向扫描for(int i=0;i<15;i++){for(int j=0;j<11;j++){if(chess[i][j]==1 && chess[i][j+1]==1 && chess[i][j+2]==1 && chess[i][j+3]==1 && chess[i][j+4]==1){QMessageBox::information(nullptr,"温馨提示","玩家获胜!");this->newGame();return true;}else if(chess[i][j]==2 && chess[i][j+1]==2 && chess[i][j+2]==2 && chess[i][j+3]==2 && chess[i][j+4]==2){QMessageBox::information(nullptr,"温馨提示","电脑获胜!");this->newGame();return true;}}}//纵向扫描for(int j=0;j<15;j++){for(int i=0;i<11;i++){if(chess[i][j]==1 && chess[i+1][j]==1 && chess[i+2][j]==1 && chess[i+3][j]==1 && chess[i+4][j]==1){QMessageBox::information(nullptr,"温馨提示","玩家获胜!");this->newGame();return true;}else if(chess[i][j]==2 && chess[i+1][j]==2 && chess[i+2][j]==2 && chess[i+3][j]==2 && chess[i+4][j]==2){QMessageBox::information(nullptr,"温馨提示","电脑获胜!");this->newGame();return true;}}}//对角扫描for(int i=0;i<11;i++){for(int j=0;j<11;j++){if(chess[i][j]==1 && chess[i+1][j+1]==1 && chess[i+2][j+2]==1 && chess[i+3][j+3]==1 && chess[i+4][j+4]==1){QMessageBox::information(nullptr,"温馨提示","玩家获胜!");this->newGame();return true;}else if(chess[i][j]==2 && chess[i+1][j+1]==2 && chess[i+2][j+2]==2 && chess[i+3][j+3]==2 && chess[i+4][j+4]==2){QMessageBox::information(nullptr,"温馨提示","电脑获胜!");this->newGame();return true;}}}//反对角扫描for(int j=0;j<11;j++){for(int i=14;i>3;i--){if(chess[i][j]==1 && chess[i-1][j+1]==1 && chess[i-2][j+2]==1 && chess[i-3][j+3]==1 && chess[i-4][j+4]==1){QMessageBox::information(nullptr,"温馨提示","玩家获胜!");this->newGame();return true;}else if(chess[i][j]==2 && chess[i-1][j+1]==2 && chess[i-2][j+2]==2 && chess[i-3][j+3]==2 && chess[i-4][j+4]==2){QMessageBox::information(nullptr,"温馨提示","电脑获胜!");this->newGame();return true;}}}return false;
}void chessboard::newGame()
{//初始化棋盘for(int i=0;i<15;i++){for(int j=0;j<15;j++){chess[i][j] = 0;}}//释放棋盘窗口,包括棋子delete this->chessWin;//创建新棋盘窗口,并初始化this->chessWin = new QWidget(this);this->chessWin->resize(810,810);this->chessWin->show();
}chessboard::chessboard(QWidget *parent) : QWidget(parent)
{//隐藏标题栏this->setFixedSize(810,810);//创建棋盘背景this->bg = new QLabel(this);this->bg->setGeometry(0,0,810,810);this->bg->setPixmap(QPixmap("./picture/chessboard.png"));this->bg->setScaledContents(true);//创建棋盘窗口this->chessWin = new QWidget(this);this->chessWin->resize(810,810);//初始化棋盘for(int i=0;i<15;i++){QVector<int> row;for(int j=0;j<15;j++){row.append(0);}chess.append(row);}//随机数初始化qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));
}
总结
以上就是【QT项目】简易五子棋游戏(人机对战)的所有内容,希望大家阅读后都能有所收获!原创不易,转载请标明出处,若文章出现有误之处,欢迎读者留言指正批评!
【QT项目】简易五子棋游戏(人机对战)— 完整源码相关推荐
- JavaScript实现backtracking Jump Game回溯跳跃游戏算法(附完整源码)
JavaScript实现backtracking Jump Game回溯跳跃游戏算法(附完整源码) backtrackingJumpGame.js完整源代码 backtrackingJumpGame. ...
- JAVA课程设计(小游戏贪吃蛇)完整源码附素材(二)
目录 JAVA课程设计(小游戏贪吃蛇)完整源码附素材(一) JAVA课程设计(小游戏贪吃蛇)完整源码附素材(二) JAVA课程设计(小游戏贪吃蛇)完整源码附素材(三) 前言 1. 任务描述 1.1 ...
- Android 蓝牙五子棋[可人机对战]——完整篇
前言 我之前做了个人机对战的五子棋, AI算法很垃圾, 然后各种逻辑很糟糕, 已经很久没有维护了, 今天看了篇文章, 是用了蓝牙和Wifi的五子棋对战, 我觉得很有意思, 毕竟自己没做过蓝牙连接这方面 ...
- C++jump game跳跃游戏的算法(附完整源码)
C++jump game跳跃游戏的算法 C++实现jump game跳跃游戏的算法完整源码(定义,实现,main函数测试) C++实现jump game跳跃游戏的算法完整源码(定义,实现,main函数 ...
- android精品源码,下拉刷新效果高德地图五子棋游戏定制日历全民TV源码
1.Android图片涂鸦 2.在AchartEngine的基础上进行功能扩展的图表,新增非常多的... 3.上拉刷新.下拉加载 4.实现多种下拉刷新效果.上拉加载更多以及配置自定义头... 5.高德 ...
- C++ 简易弹球游戏(分块解释、源码、注释)
模拟一定范围内用挡板使小球不下落的经典小游戏. 目录 宽高在此修改 设置小球可能出现的形状 其他全局参数 建立挡板类 建立小球类 实现与挡板碰撞 考虑小球间的相互碰撞 实现小球移动 打印界面 主程序 ...
- 深度学习项目:男女性别识别【附完整源码】
性别分类对于人机交互应用和计算机辅助生理或心理分析等商业领域的许多应用至关重要,因为它包含有关男女特征差异的广泛信息. 本次案例收集了接近二十万的男女数据集图片. 文章目录 性别分类简介 使用 Pyt ...
- JavaScript:实现Sudoku数独游戏算法(附完整源码)
JavaScript:实现Sudoku数独游戏算法 class Sudoku {constructor (board) {this.board = board}findEmptyCell () {// ...
- python猜数字小游戏(内附完整源码)
代码如下: import random t=random.randint(0,99999) print("※=========☺========※=▇破产抽奖轮盘▆=※=======☹=== ...
- 深度学习项目:泰坦尼克号生存预测【附完整源码】
文章目录 一.建模基本流程 二.结构化数据建模流程 2.1 泰塔尼克号数据 2.2 数据处理 2.3 建立模型 2.4 训练模型 2.5 评估模型 2.6 模型预测 27 保存模型 一.建模基本流程 ...
最新文章
- VC++大数据量绘图时无闪烁刷屏技术实现
- Adobe Flash Player 10.0.32.18
- sqlite创建表联合主键的sql写法、执行sql文件、不支持右连接、获取年份、case when 的使用
- 面向过程和面向对象的区别
- 物联网串口服务器的功能和作用
- eclipse使用maven tomcat插件部署无法关联源代码
- 五分钟用Docker快速搭建Go开发环境
- 《Pro ASP.NET MVC 3 Framework》学习笔记之二十四【Controllers和Actions】
- 新年春节项目海报设计,PSD分层模板,帮你顺利交稿!
- bzoj 1046: [HAOI2007]上升序列【dp+二分】
- 数据迁移工具(数据库之间进行数据库迁移所使用的工具及迁移流程。)
- VC++每个版本对应的vcredist
- 3 	2012年 	毕节市 	工业废水排放量 	5466 	万吨	中国城市统计年鉴2013 	335-341
- 拼多多破1000亿美金,黄峥自述:我的人生经历和创业理念
- 苹果手机7P ios14 nfc怎么复制门禁卡
- 江恩 计算机,江恩计算器
- 〖Python 数据库开发实战 - MongoDB篇②〗- Mac环境下的MongoDB数据库安装
- Linux vim 文本替换 %s/原文/替换文本/g
- Java实现 LeetCode 54 螺旋矩阵
- 12米数字高程DEM现已上线!附DEM专题图制作教程
热门文章
- [RK3399][Android7.1] 问题记录 --- GPU 重启问题分析
- cpu.h-栈的宏定义-满减栈
- 2018-2019 起风了,唯有努力生存
- oracle dbf 超大,system01.dbf文件过大——SYSTEM表空间AUD$使用空间过大问题处理
- 转阿彪 PHP常见的安全问题
- 微信-点链接进入公众号关注页
- 微信小程序开发之组件official-account(配置公众号关注组件)
- 计算机基础在线网络课程,欢迎访问大学计算机基础网络课程
- 【呆瓜学maven】Maven介绍(创建工程项目以及下载所需要的jar包)
- 卡尔曼滤波的细致讲解从一维到多维