数据结构课设——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
    评论
好的,以下是一个简单的排雷游戏的C语言代码: #include <stdio.h> #include <stdlib.h> #include <time.h> #define ROWS 10 #define COLS 10 #define MINES 10 void init_board(char board[][COLS], int rows, int cols, char ch); void print_board(char board[][COLS], int rows, int cols); void set_mines(char board[][COLS], int rows, int cols, int num_mines); void get_neighbors(char board[][COLS], int rows, int cols, int row, int col, int *n, int *s, int *e, int *w, int *ne, int *nw, int *se, int *sw); void reveal(char board[][COLS], char mask[][COLS], int rows, int cols, int row, int col); int count_mines(char board[][COLS], int rows, int cols, int row, int col); int main(void) { char board[ROWS][COLS]; char mask[ROWS][COLS]; int row, col, num_mines, num_revealed; srand((unsigned)time(NULL)); init_board(board, ROWS, COLS, '-'); init_board(mask, ROWS, COLS, '*'); num_mines = MINES; set_mines(board, ROWS, COLS, num_mines); num_revealed = 0; while (num_revealed < ROWS * COLS - num_mines) { print_board(mask, ROWS, COLS); printf("Enter row and column (e.g. 3 4): "); scanf("%d %d", &row, &col); if (board[row][col] == '*') { printf("BOOM! Game over.\n"); break; } reveal(board, mask, ROWS, COLS, row, col); num_revealed++; } if (num_revealed == ROWS * COLS - num_mines) { printf("Congratulations! You win!\n"); } return 0; } void init_board(char board[][COLS], int rows, int cols, char ch) { int i, j; for (i = 0; i < rows; i++) { for (j = 0; j < cols; j++) { board[i][j] = ch; } } } void print_board(char board[][COLS], int rows, int cols) { int i, j; printf(" "); for (j = 0; j < cols; j++) { printf("%d ", j); } printf("\n"); for (i = 0; i < rows; i++) { printf("%d ", i); for (j = 0; j < cols; j++) { printf("%c ", board[i][j]); } printf("\n"); } } void set_mines(char board[][COLS], int rows, int cols, int num_mines) { int i, j, k; for (k = 0; k < num_mines; k++) { do { i = rand() % rows; j = rand() % cols; } while (board[i][j] == '*'); board[i][j] = '*'; } } void get_neighbors(char board[][COLS], int rows, int cols, int row, int col, int *n, int *s, int *e, int *w, int *ne, int *nw, int *se, int *sw) { *n = (row > 0) ? board[row - 1][col] : 0; *s = (row < rows - 1) ? board[row + 1][col] : 0; *e = (col < cols - 1) ? board[row][col + 1] : 0; *w = (col > 0) ? board[row][col - 1] : 0; *ne = (row > 0 && col < cols - 1) ? board[row - 1][col + 1] : 0; *nw = (row > 0 && col > 0) ? board[row - 1][col - 1] : 0; *se = (row < rows - 1 && col < cols - 1) ? board[row + 1][col + 1] : 0; *sw = (row < rows - 1 && col > 0) ? board[row + 1][col - 1] : 0; } void reveal(char board[][COLS], char mask[][COLS], int rows, int cols, int row, int col) { int n, s, e, w, ne, nw, se, sw, num_mines; if (mask[row][col] == '-') { mask[row][col] = board[row][col]; if (board[row][col] == ' ') { get_neighbors(board, rows, cols, row, col, &n, &s, &e, &w, &ne, &nw, &se, &sw); if (n == '-') reveal(board, mask, rows, cols, row - 1, col); if (s == '-') reveal(board, mask, rows, cols, row + 1, col); if (e == '-') reveal(board, mask, rows, cols, row, col + 1); if (w == '-') reveal(board, mask, rows, cols, row, col - 1); if (ne == '-') reveal(board, mask, rows, cols, row - 1, col + 1); if (nw == '-') reveal(board, mask, rows, cols, row - 1, col - 1); if (se == '-') reveal(board, mask, rows, cols, row + 1, col + 1); if (sw == '-') reveal(board, mask, rows, cols, row + 1, col - 1); } } } int count_mines(char board[][COLS], int rows, int cols, int row, int col) { int n, s, e, w, ne, nw, se, sw, count; get_neighbors(board, rows, cols, row, col, &n, &s, &e, &w, &ne, &nw, &se, &sw); count = 0; if (n == '*') count++; if (s == '*') count++; if (e == '*') count++; if (w == '*') count++; if (ne == '*') count++; if (nw == '*') count++; if (se == '*') count++; if (sw == '*') count++; return count; }

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

光头强12138

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

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

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

打赏作者

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

抵扣说明:

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

余额充值