数据结构课设——QT实现扫雷游戏

一、题目内容

实现一个N*M的扫雷游戏
扫雷游戏规则:
把所有非地雷的格子揭开即胜利;踩到地雷格子就算失败。开局随机左击一个方格,方格即被打开并显示出方格中的数字;方格中数字则表示其周围的8个方格隐藏了几颗雷。右击是标记雷。双击:当双击位置周围已标记雷数等于该位置数字时操作有效,相当于对该数字周围未打开的方块均进行一次左键单击操作。地雷未标记完全时使用双击无效。若数字周围有标错的地雷,则游戏结束,标错的地雷上会显示一个“×”。当打开的方格为空时,自动打开周围八个方格。

二、需求分析

在这里插入图片描述

三、界面设计

1.UI资源

在这里插入图片描述

**备注:**扫雷图标从网站上下载

2.主界面

在这里插入图片描述

3.自定义难度设置

在这里插入图片描述

四、功能实现

1.雷区实现

雷区本质:一个N*M的二维数组
数组元素为一个个的小格子,格子有很多不同状态
写一个格子类来带表格子,不同的状态用不同的参数来表示
在QT中将格子看做是一个个图元,通过将图元添加到场景中,再利用UI设置从而将格子显示出来,鼠标点击的时候就调用函数来改变被点击格子的状态。每次操作之后调用UpdateMate()更新函数检查格子状态的改变并进行重绘。
figuremate.h

class FigureMate : public QObject,public QGraphicsPixmapItem  //继承
{
    Q_OBJECT//宏定义,可以使用信号和槽机制
public:
    FigureMate();
    void setRowAndCol(int x,int y){row=x;col=y;} //设置行和列
    void setOpened(bool s){opened=s;updateMate();}//模拟点击,打开
    void setMine(bool m){mine=m;}
    void setNumOfMines(int n){numOfMines=n;}//设置地雷个数
    void setFlag(bool m){flag=m;updateMate();}//标记
    void setOpenMine(bool s){openMine=s;}//设置打开雷,即踩雷
    bool isOpened(){return opened;}//判断是否打开过
    bool isMine(){return mine;}//判断是不是雷
    bool isFlag(){return flag;}//判断是否已被标记
    int getNumOfMines(){return numOfMines;}//得到雷数
    void simulateLeftClick();//模拟左键点击
    void updateMate();//更新显示
    
protected:
     void mousePressEvent(QGraphicsSceneMouseEvent *event)override;
     void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;

signals:
     void openOnMine(int r,int c);//挖到了雷
     void openOnNone(int r,int c);//挖到没有雷的地方
     void doubleClickSignal(int r,int c);//左右键双击有效
     void checkSignal();//每次点击后,发送信号给myscene检查游戏是否结束
     void flagChangedSignal();//标记改变信号,用来numScene改变剩余地雷数

private:

     int row;//行
     int col;//列
     bool opened=false;//是否已经打开,默认设置为未打开
     bool mine=false;//有地雷吗?默认设置为没有
     bool flag=false;//是否被旗帜标记了,默认设置为没有被标记
     bool openMine=false;//是否打开了雷
     int numOfMines=0;//周围地雷个数
};

2.获取所点击位置周围地雷数

本质:遍历周围八个格子,计数有地雷的格子数。
思路:若我们将被点击的格子放在二维坐标系的原点,则周围八个格子相对于中心格子的坐标不变,始终是(-1,0)、(1,0)…
在这里插入图片描述
则周围八个格子的真实坐标=中心格子的真实坐标+周围八个格子相对与中心格子的坐标

int nx,ny,numOfMines;//周围的八个点  坐标
    int dx[8]={-1,-1,-1,0,0,1,1,1};
    int dy[8]={-1,0,1,-1,1,-1,0,1};
    //设置周围砖块数
    for(int i=0;i<width;++i){
        for(int j=0;j<height;++j){
            numOfMines = 0;

            for(int k=0;k<8;++k){//遍历它周围的八个格子
                nx=i+dx[k];
                ny=j+dy[k];
            if(0<=nx&&nx<width&&0<=ny&&ny<height){//判断是在第一象限,在范围内,防止四周的格子判断失误
                if(this->mates[nx][ny]->isMine()){
                    //这八个格子中如果有雷
                    numOfMines++;
                    }
            }
            }
            this->mates[i][j]->setNumOfMines(numOfMines);//设置雷数

        }
    }

3.自动排雷

效果描述:当打开的格子为空时,自动打开周围的八个格子
效果展示:
在这里插入图片描述
实现:递归实现。
当打开的格子不为空时,递归停止。

//无雷时,自动打开实现
void SceneClass::findNoMines(int row,int col){

    mates[row][col]->setOpened(true);//模拟点击

    if(mates[row][col]->getNumOfMines()!=0)
        return;//有数字的方块就不展开了

    int nx,ny;
    int dx[8]={-1,-1,-1,0,0,1,1,1};
    int dy[8]={-1,0,1,-1,1,-1,0,1};
    for(int i=0;i<8;++i){
        nx=row+dx[i];
        ny=col+dy[i];
        if(0<=nx&&nx<width&&0<=ny&&ny<height&&!mates[nx][ny]->isOpened()){
            findNoMines(nx,ny);
        }
    }
}

4.胜负判断

实现方法:每次点击后调用函数判断游戏是否结束。
效果展示:
在这里插入图片描述

五、一些思考与拓展

winXP自带的扫雷游戏的功能实际上是比较简单的,可加的拓展功能:实现用户的登录注册、记录用户的最高成绩、联机排行榜、撤回一步等。

六、参考博文

https://blog.csdn.net/livingsu/article/details/104774193

七、源码

源码

  • 8
    点赞
  • 52
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

光头强12138

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

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

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

打赏作者

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

抵扣说明:

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

余额充值