C++扫雷小游戏

基本思路

  1. 创建二维数组。
  2. 利用数组二维数组下标随机,在地图随机设置十个雷,用-1表示。
  3. 遍历二维数组,在以雷为中心的九宫格内所有数值+1.
  4. 对格子进行加密,采用数值+20的方式,便于贴图。
  5. 左键点击空白格,进行解密,数值-20。右键点击空白格,数值+20,通过数值范围控制💣、🚩等贴图的实现。打开空白格,用到递归。
  6. 统计🚩标记正确💣的个数是否为设置的全部💣个数,判定胜利。

教学视频

已实现的功能

扫雷游戏基础玩法实现

尚未实现的功能

  • 用户交互自定义设置💣数量,自适应💣数量的游戏格窗大小;
  • 游戏计分等。

待开新坑


源码

main.cpp


#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <easyx.h>
#include <mmsystem.h>
#pragma comment(lib, "winmm.lib")

#define ROW 10
#define COL 10
#define IMGW 40
#define MineNum 10

void initMap(int map[ROW][COL]);                    //初始化地图
void drawMap(int map[ROW][COL], IMAGE img[]);       //地图贴图
void mouseEvent(int map[ROW][COL]);                 //鼠标点击操作(左键打开,右键标记)
void openNull(int map[ROW][COL], int row, int col); //递归打开空白格
void judge_1(int map[ROW][COL], int row, int col);  //若点到雷,则遍历数组,显示所有雷
void judge_2(int map[ROW][COL], int row, int col);  //判定标记的格子是否为雷,并返回胜利条件
bool isOver = false;                                //结束标记
bool victory = false;                               //胜利标记

int main()
{

    initgraph(COL * IMGW, ROW * IMGW);

    mciSendString(_T("open ./images/start.mp3 alias bgm"), NULL, 0, NULL);
    mciSendString(_T("play bgm"), NULL, 0, NULL);

    srand((unsigned)time(NULL)); //随机数种子

    int map[ROW][COL] = {0}; //定义游戏地图

    initMap(map); //初始化地图

    IMAGE img[12]; //定义图片数组

    for (int i = 0; i < 12; i++) //加载图片
    {
        char fileName[50] = {0};
        sprintf_s(fileName, "./images/%d.jpg", i);
        loadimage(img + i, _T(fileName), IMGW, IMGW);
    }

    while (true)
    {
        mouseEvent(map);
        drawMap(map, img);
        if (isOver)
        {
            int ret = MessageBox(GetHWnd(), _T("铁Five"), _T("shit"), MB_OKCANCEL);
            if (ret == IDOK)
            {
                initMap(map);
                isOver = false;
            }
            else if (ret == IDCANCEL)
            {
                exit(0);
            }
        }
        else if (victory)
        {
            int ret = MessageBox(GetHWnd(), _T("恭喜你,铁five!"), _T("Congratulations!"), MB_OKCANCEL);
            if (ret == IDOK)
            {
                initMap(map);
                victory = false;
            }
            else if (ret == IDCANCEL)
            {
                exit(0);
            }
        }
    }

    return 0;
}

void initMap(int map[ROW][COL])
{
    memset(map, 0, ROW * COL * sizeof(int));

    for (int i = 0; i < MineNum;) //地图里埋10个雷,用-1表示
    {
        int r = rand() % ROW; //控制随机数在[0,9)
        int c = rand() % COL;
        if (map[r][c] == 0)
        {
            map[r][c] = -1;
            i++; //成功设置不重复的雷,计数才增加
        }
    }

    for (int i = 0; i < ROW; i++) //雷所在的九宫格所有数值+1,雷除外
    {
        for (int k = 0; k < COL; k++)
        {
            if (map[i][k] == -1)
            {
                for (int r = i - 1; r <= i + 1; r++)
                {
                    for (int c = k - 1; c <= k + 1; c++)
                    {
                        if ((r >= 0 && r < ROW && c >= 0 && c < COL) && map[r][c] != -1) //限制数组越界
                        {
                            map[r][c]++;
                        }
                    }
                }
            }
        }
    }

    //格子加密
    for (int i = 0; i < ROW; i++)
    {
        for (int k = 0; k < COL; k++)
        {
            map[i][k] += 20;
        }
    }
}
void drawMap(int map[ROW][COL], IMAGE img[])
{
    for (int i = 0; i < ROW; i++)
    {
        for (int k = 0; k < COL; k++)
        {
            if (map[i][k] >= 0 && map[i][k] <= 8) //空白格子和数字
            {
                putimage(k * IMGW, i * IMGW, img + map[i][k]);
            }
            else if (map[i][k] == -1)
            {
                putimage(k * IMGW, i * IMGW, img + 9);
            }
            else if (map[i][k] >= 19 && map[i][k] <= 28)
            {
                putimage(k * IMGW, i * IMGW, img + 10);
            }
            else if (map[i][k] > 28)
            {
                putimage(k * IMGW, i * IMGW, img + 11);
            }
        }
    }
}

void mouseEvent(int map[ROW][COL])
{
    ExMessage msg; //定义消息结构体(鼠标消息,按键消息,字符消息)
    if (peekmessage(&msg, EM_MOUSE))
    {
        int r = msg.y / IMGW;
        int c = msg.x / IMGW;
        if (msg.message == WM_LBUTTONDOWN)
        {
            if (map[r][c] >= 19 && map[r][c] <= 28)
            {
                PlaySound(_T("./images/click.wav"), NULL, SND_ASYNC | SND_FILENAME);
                map[r][c] -= 20;
                openNull(map, r, c);
                judge_1(map, r, c);
            }
        }
        else if (msg.message == WM_RBUTTONDOWN)
        {
            PlaySound(_T("./images/rightclick.wav"), NULL, SND_ASYNC | SND_FILENAME);
            if (map[r][c] >= 19 && map[r][c] <= 28)
            {
                map[r][c] += 20;
            }
            else if (map[r][c] >= 39 && map[r][c] <= 48)
            {
                map[r][c] -= 20;
            }
            judge_2(map, r, c);
            // showMap(map);
        }
    }
}

void openNull(int map[ROW][COL], int row, int col)
{
    if (map[row][col] == 0)
    {
        for (int i = row - 1; i <= row + 1; i++)
        {
            for (int k = col - 1; k <= col + 1; k++)
            {
                if ((i >= 0 && i < ROW && k >= 0 && k < COL) && map[i][k] >= 19 && map[i][k] <= 28)
                {
                    map[i][k] -= 20;
                    openNull(map, i, k);
                }
            }
        }
    }
}

void judge_1(int map[ROW][COL], int row, int col)
{
    if (map[row][col] == -1)
    {
        for (int i = 0; i < ROW; i++)
        {
            for (int k = 0; k < COL; k++)
            {
                if (map[i][k] == 19)
                {
                    map[i][k] -= 20;
                }
            }
        }
        isOver = true;
    }
}

void judge_2(int map[ROW][COL], int row, int col)
{
    int cnt = 0;
    for (int i = 0; i < ROW; i++)
    {
        for (int k = 0; k < COL; k++)
        {
            if (map[i][k] == 39)
            {
                cnt++;
            }
        }
    }
    if (cnt >= MineNum)
    {
        victory = true;
    }
}
comments powered by Disqus