【小游戏】C++实现扫雷

一、扫雷游戏模式

在确定大小的矩形雷区中随机布置一定数量的地雷,玩家需要尽快找出雷区中的所有不是地雷的方块,而不许踩到地雷。
游戏的基本操作包括左键单击和右键单击。其中左键用于打开安全的格子,推进游戏进度;右键用于标记地雷,以辅助判断。
左键单击:在判断出不是雷的方块上按下左键,可以打开该方块。如果方块上出现数字,则该数字表示其周围3×3区域中的地雷数(一般为8个格子,对于边块为5个格子,对于角块为3个格子。所以扫雷中最大的数字为8);如果方块上为空(相当于0),则可以递归地打开与空相邻的方块;如果不幸触雷,则游戏结束。
右键单击:在判断为地雷的方块上按下右键,可以标记地雷(显示为小红旗)。重复一次或两次操作可取消标记。

二、代码实现

1.绘制地图场景

根据每一块地区的数据进行图形输出。

void drawmap(int map[][12],IMAGE *img)
{
    int i, j;
    for (i = 1; i <= 10; i++)
    {
        for (j = 0; j <= 10; j++)
        {
            int x = 50 * (i - 1);//得到位置
            int y = 50 * (j - 1);
            if (map[i][j]>25)
            {
                putimage(x, y, &img[9]);//标记flag
            }
            else
            {
                switch (map[i][j])
                {
                case 9:
                    putimage(x, y, &img[11]);//输出图片雷
                    break;
                case 10:
                    putimage(x, y, &img[0]);//0
                    break;
                case 11:
                    putimage(x, y, &img[1]);//1
                    break;
                case 12:
                    putimage(x, y, &img[2]);//2
                    break;
                case 13:
                    putimage(x, y, &img[3]);//3
                    break;
                case 14:
                    putimage(x, y, &img[4]);//4
                    break;
                case 15:
                    putimage(x, y, &img[5]);//5
                    break;
                case 16:
                    putimage(x, y, &img[6]);//6
                    break;
                case 17:
                    putimage(x, y, &img[7]);//7
                    break;
                case 18:
                    putimage(x, y, &img[8]);//8
                    break;
                default:
                    putimage(x, y, &img[10]);//地图
                    break;
                }
            }
        }
    }
}

2.鼠标点击

鼠标左键点击翻开格子,右键点击标记flag,再次点击可以进行取消。 sum记录翻开格子的数量,点击后对每个位置的数据进行加减操作。

int mousedown(int map[][12])
{
    MOUSEMSG m;    //定义鼠标消息变量
    while (1)
    {
        //获取鼠标消息
        m = GetMouseMsg();
        int mi = m.x / 50 + 1;
        int mj = m.y / 50 + 1;

        //判断鼠标消息
        switch (m.uMsg)
        {
        case WM_LBUTTONDOWN:
            if (map[mi][mj] > 9)    //已翻开的情况
            {
                continue;
            }
            if (map[mi][mj] == 0)   //如果点击为0,则翻开一片。
            {
                //使用递归函数
                swap(map, mi, mj);
            }
            else
            {
                map[mi][mj] += 10;
                sum += 1;
            }
            return  map[mi][mj];
            break;
        case WM_RBUTTONDOWN:
            if (map[mi][mj] > 9&& map[mi][mj] < 25)    //已翻开的情况
            {
                continue;
            }
            if (map[mi][mj] > 25)       //再次点击取消flag
            {
                map[mi][mj] -= 30;
            }
            else
            {
                map[mi][mj] += 30;
            }
            return  map[mi][mj];
            break;
        }
    }
}

3.递归

当我们点到为0的地区时,将会打开周围的部分地区,外围为非0数或到达边界,内部为0.
如图:
在这里插入图片描述

void swap(int map[][12],int mi,int mj)
{
    map[mi][mj] = 10;
    sum += 1;
    for (int i = mi - 1; i <= mi + 1; i++)
    {
        for (int j = mj - 1; j <= mj + 1; j++)
        {
            //数组下标不能越界
            if (i >= 1 && i <= 10 && j >= 1 && j <= 10)
            {
                //翻开的只能是数字
                if (map[i][j] < 9)
                {
                    //如果为0,则进行递归。
                    if (map[i][j] == 0)
                    {
                        swap(map, i, j);
                    }
                    else
                    {
                        map[i][j] += 10;
                        sum += 1;
                    }
                }
            }
        }
    }
}

4.初始化游戏

void startgame()
{
    initgraph(500, 500);    //初始化地图500x500
    int map[12][12] = { 0 };
    int i,j,m,n;
    //随机函数种子
    srand((unsigned int)time(NULL));
    //随机生成10个雷
    for (n = 0; n < 10;)
    {
        i = rand() % 10 + 1;    //[1,10]
        j = rand() % 10 + 1;
        if (map[i][j] == 0)     //排除本来就有雷的情况
        {
            map[i][j] = -1;     //-1表示有雷
            n++;
        }
    }
    //产生数字
    for (i = 1; i <= 10; i++)
    {
        for (j = 1; j <= 10; j++)
        {
            //排除是雷的情况
            if (map[i][j] != -1)
            {
                for (m = i - 1; m <= i + 1; m++)    //判断周围是否有雷
                {
                    for (n = j - 1; n <= j + 1; n++)
                    {
                        if (map[m][n] == -1)
                        {
                            map[i][j]++;
                        }
                    }
                }
            }
        }
    }
    IMAGE img[12];              //定义图片变量
    loadimage(&img[0], "E:\\C++ project\\minesweeping\\0.jpg", 50, 50);
    loadimage(&img[1], "E:\\C++ project\\minesweeping\\1.gif", 50, 50);//加载图片
    loadimage(&img[2], "E:\\C++ project\\minesweeping\\2.gif", 50, 50);
    loadimage(&img[3], "E:\\C++ project\\minesweeping\\3.gif", 50, 50);
    loadimage(&img[4], "E:\\C++ project\\minesweeping\\4.gif", 50, 50);
    loadimage(&img[5], "E:\\C++ project\\minesweeping\\5.gif", 50, 50);
    loadimage(&img[6], "E:\\C++ project\\minesweeping\\6.gif", 50, 50);
    loadimage(&img[7], "E:\\C++ project\\minesweeping\\7.gif", 50, 50);
    loadimage(&img[8], "E:\\C++ project\\minesweeping\\8.gif", 50, 50);
    loadimage(&img[9], "E:\\C++ project\\minesweeping\\flag.gif", 50, 50);
    loadimage(&img[10], "E:\\C++ project\\minesweeping\\地图.gif", 50, 50);
    loadimage(&img[11], "E:\\C++ project\\minesweeping\\雷.gif", 50, 50);
    while (1)
    {
        drawmap(map, img);
        //点到地雷
        if (mousedown(map)==9)
        {
            sum = 0;    //重置判断变量
            drawmap(map, img);
            MessageBox(hwnd,"你踩到雷了!","Game Over",MB_OK);
            return;
        }
        //成功完成游戏
        if (sum == 90)
        {
            sum = 0;    //重置判断变量
            drawmap(map, img);
            MessageBox(hwnd, "你成功完成了游戏!", "Game Over", MB_OK);
            return;
        }
    }
}

5.main

#include<iostream>
#include<time.h>
#include<graphics.h>        //图形库头文件 easyx
#include <conio.h>          //调用_getch函数
using namespace std;
HWND hwnd;
int sum = 0;//用于表示目前已经点开的格子数
//声明函数
void drawmap(int map[][12], IMAGE* img);
int mousedown(int map[][12]);
void swap(int map[][12], int mi, int mj);
//初始化游戏

//绘制地图

//鼠标点击

//递归函数

int main()
{
    while (1)
    {
        startgame();
        if (MessageBox(hwnd, "再来一次", "结束游戏", MB_YESNO)==IDNO)
            break;
    }
    //_getch();                //防止闪屏
    closegraph();
    return 0;
}


总结及运行

运行结果如图:
在这里插入图片描述
在这里插入图片描述

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
下面是一个用C++实现扫雷游戏,具体实现思路是使用二维组来表示扫雷游戏的格子,其中0表示空格,1表示有地雷的格子,2表示已经翻开的格子,3表示标记为地雷的格子。在游戏过程中,使用递归算法来实现翻开空格的效果,同时需要判断游戏是否结束。 ```cpp #include <iostream> #include <vector> #include <ctime> #include <cstdlib> using namespace std; // 定义常量 const int BOARD_SIZE = 10; // 扫雷游戏的大小 const int MINE_NUM = 15; // 地雷量 // 定义二维组表示扫雷游戏的格子 int board[BOARD_SIZE][BOARD_SIZE]; // 在指定位置放置地雷 void placeMine(int x, int y) { board[x][y] = 1; } // 随机放置地雷 void placeMines() { srand(time(nullptr)); int count = 0; while (count < MINE_NUM) { int x = rand() % BOARD_SIZE; int y = rand() % BOARD_SIZE; if (board[x][y] != 1) { placeMine(x, y); count++; } } } // 计算指定位置周围地雷量 int countMines(int x, int y) { int count = 0; for (int i = -1; i <= 1; ++i) { for (int j = -1; j <= 1; ++j) { int nx = x + i; int ny = y + j; if (nx >= 0 && nx < BOARD_SIZE && ny >= 0 && ny < BOARD_SIZE && board[nx][ny] == 1) { count++; } } } return count; } // 打印游戏面板 void printBoard(bool showMine) { for (int i = 0; i < BOARD_SIZE; ++i) { for (int j = 0; j < BOARD_SIZE; ++j) { if (board[i][j] == 2) { cout << countMines(i, j) << " "; } else if (board[i][j] == 3) { cout << "F "; } else if (showMine && board[i][j] == 1) { cout << "* "; } else { cout << "- "; } } cout << endl; } } // 翻开指定位置的格子 bool click(int x, int y) { if (board[x][y] == 1) { return false; } else if (board[x][y] == 2) { return true; } else { board[x][y] = 2; if (countMines(x, y) == 0) { for (int i = -1; i <= 1; ++i) { for (int j = -1; j <= 1; ++j) { int nx = x + i; int ny = y + j; if (nx >= 0 && nx < BOARD_SIZE && ny >= 0 && ny < BOARD_SIZE) { click(nx, ny); } } } } return true; } } // 标记指定位置的格子 void mark(int x, int y) { if (board[x][y] == 3) { board[x][y] = 0; } else { board[x][y] = 3; } } // 判断游戏是否结束 bool isGameOver() { for (int i = 0; i < BOARD_SIZE; ++i) { for (int j = 0; j < BOARD_SIZE; ++j) { if (board[i][j] == 2) { continue; } else if (board[i][j] == 1) { continue; } else { return false; } } } return true; } int main() { // 初始化游戏面板 for (int i = 0; i < BOARD_SIZE; ++i) { for (int j = 0; j < BOARD_SIZE; ++j) { board[i][j] = 0; } } placeMines(); // 开始游戏 bool gameOver = false; while (!gameOver) { printBoard(false); cout << "请输入坐标和操作(x y c/m):"; int x, y; char op; cin >> x >> y >> op; if (op == 'm') { mark(x, y); } else if (op == 'c') { if (!click(x, y)) { gameOver = true; printBoard(true); cout << "游戏结束,你输了!" << endl; } else if (isGameOver()) { gameOver = true; printBoard(true); cout << "恭喜你,你赢了!" << endl; } } } return 0; } ``` 该程序可以实现一个简单的扫雷游戏,支持放置地雷、随机放置地雷计算周围地雷量、打印游戏面板、翻开格子、标记格子、判断游戏是否结束等操作。需要注意的是,由于该程序使用了递归算法来实现翻开空格的效果,可能会出现栈溢出的情况,因此需要设置递归深度的限制。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值