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、电脑下棋的位置不够智能,不知道防守。

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

 

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

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

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

  • 24
    点赞
  • 50
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 10
    评论
以下基于Qt五子棋对棋盘的操作的代码示例: 在头文件中需要定义一个二维数组来表示棋盘,例如: ```cpp class Chessboard : public QWidget { Q_OBJECT public: explicit Chessboard(QWidget *parent = 0); private: int chessboard[15][15]; // 棋盘 }; ``` 在构造函数中初始化棋盘: ```cpp Chessboard::Chessboard(QWidget *parent) : QWidget(parent) { // 初始化棋盘 for(int i = 0; i < 15; i++) { for(int j = 0; j < 15; j++) { chessboard[i][j] = 0; } } } ``` 在绘制棋盘时,需要根据棋盘数组中的值来决定绘制黑子、白子或空白,例如: ```cpp void Chessboard::paintEvent(QPaintEvent *event) { Q_UNUSED(event); QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing, true); painter.setPen(Qt::black); painter.setBrush(Qt::yellow); int gridSize = 40; int startX = 20; int startY = 20; int endX = startX + gridSize * 14; int endY = startY + gridSize * 14; for(int i = 0; i < 15; i++) { painter.drawLine(startX + i * gridSize, startY, startX + i * gridSize, endY); painter.drawLine(startX, startY + i * gridSize, endX, startY + i * gridSize); } for(int i = 0; i < 15; i++) { for(int j = 0; j < 15; j++) { if(chessboard[i][j] == 1) { painter.setPen(Qt::NoPen); painter.setBrush(Qt::black); painter.drawEllipse(startX + i * gridSize - gridSize / 2, startY + j * gridSize - gridSize / 2, gridSize, gridSize); } else if(chessboard[i][j] == 2) { painter.setPen(Qt::NoPen); painter.setBrush(Qt::white); painter.drawEllipse(startX + i * gridSize - gridSize / 2, startY + j * gridSize - gridSize / 2, gridSize, gridSize); } } } } ``` 在落子时,需要根据落子位置更新棋盘数组,并重绘棋盘: ```cpp void Chessboard::mousePressEvent(QMouseEvent *event) { int gridSize = 40; int startX = 20; int startY = 20; int endX = startX + gridSize * 14; int endY = startY + gridSize * 14; int x = event->pos().x(); int y = event->pos().y(); int i = (x - startX + gridSize / 2) / gridSize; int j = (y - startY + gridSize / 2) / gridSize; if(i >= 0 && i < 15 && j >= 0 && j < 15 && chessboard[i][j] == 0) { chessboard[i][j] = 1; // 1 表示黑子 update(); // 重绘棋盘 // TODO: 计算电脑落子位置并更新棋盘 } } ``` 以上是基于Qt五子棋对棋盘的操作的代码示例,具体实现还需要根据实际需求进行调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

似末

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值