目录
一、前言
二、游戏效果展示
三、需求分析
四、代码实现
1、新建一个类five_in_a_row继承于QWidget
2、头文件(five_in_a_row.h)
3、构造函数(初始化棋盘)
4、放置棋子槽函数
5、定输赢函数
6、清空棋盘函数
7、cpp用到的头文件
8、主函数测试
五、总结
一、前言 本文为使用Qt实现一个简易的五子棋游戏,通过使用QTableWiget绘制棋盘,使用二维数组相关知识实现五子棋人机对战的功能。
二、游戏效果展示 电脑比较笨,不懂得防守(哈哈哈),不,应该是我太厉害了!哈哈!!!
三、需求分析
- 使用QTableWiget画一个棋盘
- 双击棋盘中的某块区域,在该区域“下”一颗棋子
- 人下完棋子之后,电脑也需要在某块区域下棋(使用随机数)
- 判断输赢(是否五子连珠)
- 分出胜负后需要清空棋盘
四、代码实现 1、新建一个类five_in_a_row继承于QWidget
- (1) 右键工程文件夹——>添加新文件
文章图片
- (2) 选择C++——>C++ Class,点击下一步
文章图片
- (3) 类名为 five_in_a_row,基类选择 QWidget,点击下一步,点击完成。
文章图片
2、头文件(five_in_a_row.h)
#ifndef FIVE_IN_A_ROW_H
#define FIVE_IN_A_ROW_H#include
#include
#include class five_in_a_row : public QWidget
{
Q_OBJECT
public:
explicit five_in_a_row(QWidget *parent = 0);
void whetherWin(int type);
//定输赢
void clearChessBoard();
//清空表格,初始化数组private:
QTableWidget *tableWidget;
//表格,用于绘制棋盘
QMessageBox *message;
//消息框
int num[20][20];
//二维数组,存放棋子位置
int win;
//输赢的标志位signals:public slots:
void setChess(int x, int y);
//下棋
};
#endif // FIVE_IN_A_ROW_H
3、构造函数(初始化棋盘)
- 初始化二维数组
- 新建20 x 20表格
- 设置表格宽高
- 绑定信号槽
five_in_a_row::five_in_a_row(QWidget *parent) : QWidget(parent)
{
this->setFixedSize(700, 700);
this->setWindowTitle("五子棋");
this->setWindowIcon(QIcon(":/image/小棋盘.png"));
message = new QMessageBox(QMessageBox::NoIcon, "Tip", "",
QMessageBox::Ok | QMessageBox::No, this);
message->setWindowIcon(QIcon(":/image/提示.png"));
message->setStyleSheet("QMessageBox QLabel{min-width: 400px;
"
"min-height: 100px;
font:16pt;
font-family:'楷体';
}");
for(int i = 0;
i < 20;
i++)//初始化二维数组
{
for(int j = 0;
j < 20;
j++)
{
num[i][j] = 0;
}
}tableWidget = new QTableWidget(20, 20,this);
//20x20 的表格
tableWidget->setGeometry(0, 0, this->width(), this->height());
//设置表格 x、y、w、hfor(int i=0;
i<20;
i++)
{
tableWidget->setColumnWidth(i, this->width()/21);
//设置列宽
tableWidget->setRowHeight(i, this->height()/21);
//设置行高
}tableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
//设置表格不可编辑//双击下棋
connect(tableWidget, SIGNAL(cellDoubleClicked(int,int)), this, SLOT(setChess(int, int)));
}
4、放置棋子槽函数 通过双击信号得到的行(x)和列(y),在表格 x行y列 的地方加载一个打钩QLabel,也就是“下”一颗棋子,并且将二维数组 num[x][y] =1,标记此处是我们下的棋子。
人下完棋子之后,判断有没有五子连珠,没有的话电脑开始下棋,电脑通过随机数产生一个在x,y附近的位置(temp_x 、temp_y)。并在表格 temp_x 行,temp_y 列 的地方加载一个打叉QLabel,并且将二维数组 num[temp_x ][temp_y] =-1,标记此处是电脑下的棋子。并判断电脑是否五子连珠。
void five_in_a_row::setChess(int x, int y)
{
//num[x][y] == 0表示该位置没有棋子
if(num[x][y] == 0)
{
num[x][y] = 1;
//人下的棋子,用1代替
QLabel *lab = new QLabel;
lab->setPixmap(QPixmap(":/image/打钩红.png").scaled(this->width()/21, this->height()/21));
tableWidget->setCellWidget(x, y, lab);
//放置一颗棋子(打钩)
whetherWin(1);
//判断人是否赢了
if(this->win == 1)
{
message->setText("你赢啦!是否再来一局?");
if(message->exec() == QMessageBox::Ok) //再来一局
{
this->clearChessBoard();
}
else //退出游戏
{
this->close();
}
return;
}//电脑通过随机数下棋
message->setText("电脑下棋中……");
message->exec();
while(1)
{
qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));
//随机数种子,让随机数更随机
//产生一个人下的棋子附近的随机位置
int temp_x = (qrand()%5-2)+x;
int temp_y = (qrand()%5-2)+y;
if(num[temp_x-1][temp_y-1]==0 && temp_x<20 && temp_y<20 && temp_x > 0 && temp_y >0)//该位置没有棋子
{
num[temp_x-1][temp_y-1] = -1;
//电脑下的棋子,用-1代替
QLabel *temp_lab = new QLabel;
temp_lab->setPixmap(QPixmap(":/image/打叉.png").scaled(this->width()/21, this->height()/21));
tableWidget->setCellWidget(temp_x-1, temp_y-1, temp_lab);
//放置一颗棋子(打叉)
break;
}
else
{
continue;
}
}
whetherWin(-1);
//判断电脑是否赢了
if(this->win == -1)
{
message->setText("电脑赢啦!是否再来一局?");
if(message->exec() == QMessageBox::Ok) //再来一局
{
this->clearChessBoard();
}
else //退出游戏
{
this->close();
}
}
}
}
5、定输赢函数 通过循环遍历二维数组的方法,判断行方向、列方向、斜方向是否五子连珠。
//判断行方向、列方向、斜方向是否五子连珠
void five_in_a_row::whetherWin(int type)//type=1表示人,type=-1表示电脑
{
int i, j;
for(i=0;
i<20;
i++)//判断行方向是否五子连珠
{
for(j=0;
j<20;
j++)
{
if(num[i][j]==type && num[i][j+1]==type && num[i][j+2]==type && num[i][j+3]==type && num[i][j+4]==type)
{
win = type;
return;
}
else
{
win = 0;
}
}
}
for(j=0;
j<20;
j++)//判断列方向是否五子连珠
{
for(i=0;
i<20;
i++)
{
if(num[i][j]==type && num[i+1][j]==type && num[i+2][j]==type && num[i+3][j]==type && num[i+4][j]==type)
{
win = type;
return;
}
else
{
win = 0;
}
}
}
for(j=0;
j<20;
j++)//判断斜(\)方向是否五子连珠
{
for(i=0;
i<20;
i++)
{
if(num[i][j]==type && num[i+1][j+1]==type && num[i+2][j+2]==type && num[i+3][j+3]==type && num[i+4][j+4]==type)
{
win = type;
return;
}
else
{
win = 0;
}
}
}
for(j=0;
j<20;
j++)//判断斜(/)方向是否五子连珠
{
for(i=0;
i<20;
i++)
{
if(num[i][j]==type && num[i-1][j+1]==type && num[i-2][j+2]==type && num[i-3][j+3]==type && num[i-4][j+4]==type)
{
win = type;
return;
}
else
{
win = 0;
}
}
}
}
6、清空棋盘函数 首先将二维数组内的值全部置为0,然后将表格内容清空,将输赢的标志位 置0。
//清空棋盘
void five_in_a_row::clearChessBoard()
{
for(int i = 0;
i < 20;
i++)//初始化数组
{
for(int j = 0;
j < 20;
j++)
{
num[i][j] = 0;
}
}
tableWidget->clear();
//清空表格
this->win = 0;
//输赢的标志位 置0
}
7、cpp用到的头文件
#include "five_in_a_row.h"8、主函数测试
#include
#include
#include "five_in_a_row.h"
#include int main(int argc, char *argv[])
{
QApplication app(argc,argv);
five_in_a_row w;
//创建棋盘类对象w.show();
//显示棋盘return app.exec();
}
五、总结 通过以上代码,我们的这个五子棋小游戏就做完了,其实有很多不足的地方。比如:
1、判断输赢的时候,存在二维数组越界问题。
2、当人下的棋子附近没有地方下棋的时候,电脑不知道下哪里,程序就会崩溃掉。
3、在边界下棋时,电脑下棋会很久才下一颗棋(供电脑下棋的位置太少)。
4、电脑下棋的位置不够智能,不知道防守。
感兴趣的小伙伴可以优化优化,也可以改成人与人对战,可以和好朋友一起玩,哈哈哈。
文章图片
文章图片
文章图片
文章图片
以上是五子棋用到的图片,需要的小伙伴可以下载一下。
原创不易,转载请标明出处。
【Qt学习|Qt学习之使用QTableWiget实现简易五子棋游戏(人机对战)】有什么问题可以评论区留言,期待您的一键三连,嘻嘻。
推荐阅读
- FFmpeg音视频|Qt结合FFmpeg转码码流数据(h264)生成不同视频格式(mp4、mov、flv、avi等)
- Qt-大屏电子看板|Qt编写可视化大屏电子看板系统32-模块10大屏地图
- Java|maven tomcat10 servlet api 不兼容 包名javax变成jakarta 实例化Servlet类 异常
- Qt-大屏电子看板|Qt编写可视化大屏电子看板系统31-模块9视频监控
- 腾讯|知乎回应“腾讯搜狗退出知乎股东”(是上市后的标准操作)
- C++|基于QT实现简单的TCP通信
- QT|Qt实现隐藏按钮功能
- QT|QT实现TCP通信
- [Qt学习笔记]Qt实现多摄像头的识别、显示、截图、分辨率帧率设置等功能