目录
一、前言
二、游戏效果展示
三、需求分析
四、代码实现
1、新建一个类five_in_a_row继承于QWidget
2、头文件(five_in_a_row.h)
3、构造函数(初始化棋盘)
4、放置棋子槽函数
5、定输赢函数
6、清空棋盘函数
7、cpp用到的头文件
8、主函数测试
五、总结
本文为使用Qt实现一个简易的五子棋游戏,通过使用QTableWiget绘制棋盘,使用二维数组相关知识实现五子棋人机对战的功能。
电脑比较笨,不懂得防守(哈哈哈),不,应该是我太厉害了!哈哈!!!
分析完需求之后,话不多说,直接开始上代码
#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
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、h
for(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)));
}
通过双击信号得到的行(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();
}
}
}
}
通过循环遍历二维数组的方法,判断行方向、列方向、斜方向是否五子连珠。
//判断行方向、列方向、斜方向是否五子连珠
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;
}
}
}
}
首先将二维数组内的值全部置为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
}
#include "five_in_a_row.h"
#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、电脑下棋的位置不够智能,不知道防守。
感兴趣的小伙伴可以优化优化,也可以改成人与人对战,可以和好朋友一起玩,哈哈哈。
以上是五子棋用到的图片,需要的小伙伴可以下载一下。
原创不易,转载请标明出处。
有什么问题可以评论区留言,期待您的一键三连,嘻嘻。