Qt学习之使用QTableWiget实现简易五子棋游戏(人机对战)

目录

一、前言

二、游戏效果展示

三、需求分析

四、代码实现

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 <QWidget>
#include <QTableWidget>
#include <QMessageBox>

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、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)));

}

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"

#include <QLabel>

#include <QTime>

8、主函数测试

#include "five_in_a_row.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication app(argc,argv);

    five_in_a_row w;//创建棋盘类对象

    w.show();//显示棋盘

    return app.exec();
}

五、总结

        通过以上代码,我们的这个五子棋小游戏就做完了,其实有很多不足的地方。比如:

1、判断输赢的时候,存在二维数组越界问题。

2、当人下的棋子附近没有地方下棋的时候,电脑不知道下哪里,程序就会崩溃掉。

3、在边界下棋时,电脑下棋会很久才下一颗棋(供电脑下棋的位置太少)。

4、电脑下棋的位置不够智能,不知道防守。

感兴趣的小伙伴可以优化优化,也可以改成人与人对战,可以和好朋友一起玩,哈哈哈。

 

以上是五子棋用到的图片,需要的小伙伴可以下载一下。

原创不易,转载请标明出处。

有什么问题可以评论区留言,期待您的一键三连,嘻嘻。

猜你喜欢

转载自blog.csdn.net/wmcy123/article/details/123650729