我的编程空间,编程开发者的网络收藏夹
学习永远不晚

C语言二维数组运用实现扫雷游戏

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

C语言二维数组运用实现扫雷游戏

作为80后、90后的老年人,想必对扫雷游戏都不陌生。
扫雷,是微软在win8版本之前系统自带的一款游戏——现在已经被下架了,童年的回忆,很难受。
游戏操作很简单,首先初始化一个m×n的方块矩阵,然后玩家不断地翻开方块,直到所有没有雷的方块都被翻开,游戏胜利。
在玩家进行操作的时候,游戏会适当的给予玩家一些提示:分布在雷周围的方块会显示出数字提示周围八个小方块里有几个雷,这样,玩家就可以根据提示来排除那些藏了雷的小方块。
现在,我们根据游戏规则来整理一下程序的思路:

1、创建两个二维数组,分别保存雷的分布地图和显示给玩家的地图;
2、分别初始化这两个数组;
3、打印初始地图
4、读取玩家输入的坐标并对其进行合法性判定;
5、若玩家的输入合法, 对地图进行更新, 否则, 提示玩家重新输入;
6、判定游戏是否结束, 若结束转到6, 否则重复3~6
7、输出游戏结果.

现在根据思路来写一下程序大致的框架了.
首先, 要两个二维数组, 那么问题来了, 数组要多大才合适呢? 显然, 数组的大小要和游戏的规模大小相同——也就是方块矩阵的大小和雷的数量,而这个矩阵多大、雷有多少,我们不知道,为了方便修改,我们使用宏定义来定义:

#define MAX_ROW 10    //矩阵行数
#define MAX_COL 10    //矩阵列数
#define MAX_MINE 10    //雷的数量

然后创建两个二维数组:

char mine_map[MAX_ROW][MAX_COL];
char game_map[MAX_ROW][MAX_COL];

mine_map是保存雷的分布数据的地图,game_map则是显示给用户的地图。
然后分别对这两个地图进行初始化,game_map的初始化比较简单:

void init_map(char a[MAX_ROW][MAX_COL])
{
    for (int i = 0; i < MAX_ROW; i++)
        for (int j = 0; j < MAX_COL; j++)
            a[i][j] = '#';
}

而mine_map的初始化则比较复杂了。首先,需要随机生成MAX_MINE个雷,这里我们使用rand()函数来生成,并在初始化之前生成一个随机种子。接着,在生成完MAX_MINE个雷之后,对mine_map扫描一次,在雷的周围的小方块里生成提示数字:

//计算一个小方块的周围有几个雷的函数
void cal_mine(char a[MAX_ROW][MAX_COL], int row, int col)
{
    for (int r = row - 1; r < row + 2; r++)
        for (int c = col - 1; c < col + 2; c++)
        {
            if (r >= 0 && r < MAX_ROW
                && c >= 0 && c < MAX_COL
                && a[r][c] != '*')
                a[r][c] = a[r][c] + 1;
        }
}
//生成游戏地图
void create_map(char map[MAX_ROW][MAX_COL])
{
    int count = 0;
    int row;
    int col;
    for (int i = 0; i < MAX_ROW; i++)
        for (int j = 0; j < MAX_COL; j++)
            map[i][j] = '0';
    while (count < MAX_MINE)
    {
        row = rand() % MAX_ROW;
        col = rand() % MAX_COL;
        if (map[row][col] != '*')
            map[row][col] = '*';
        else
            continue;
        count += 1;
    }
    for (int i = 0; i < MAX_ROW; i++)
        for (int j = 0; j < MAX_COL; j++)
        {
            if (map[i][j] == '*')
                cal_mine(map, i, j);
        }
}

之后就是更新地图和打印地图的函数了,为了方便调试上面这两个初始化函数,我们先写打印地图函数:

void display_map(char gmap[MAX_ROW][MAX_COL])
{
    system("cls");
    for (int r = MAX_ROW - 1; r >= 0; r--)
    {
        printf(" %2d|", r + 1);
        for (int c = 0; c < MAX_COL; c++)
            printf(" %c", gmap[r][c]);
        printf("\n");
    }
    printf("   |");
    for (int i = 0; i < MAX_COL; i++)
        printf("__");
    printf("\n     ");
    for (int i = 0; i < MAX_COL; i++)
        printf("%-2d", i + 1);
    printf("\n");
}

这个函数的可读性并不好,因为这个地图长啥样完全是根据我的喜好来定的,虽然用控制台写的程序都丑,但是它丑得有多别致由我决定······这个函数不同的人能玩出不同的花,以上仅供参考。
最后就是更新地图函数了,先写一个函数框架吧:

int renew_map(char game[MAX_ROW][MAX_COL], 
            char mine[MAX_ROW][MAX_COL],
             int row, int col)
{
    int count;
    game[row][col] = mine[row][col];
    if (mine[row][col] == '*')
        return 0;
    else if (mine[row][col] != '0')
        return 1;
    count = continues_map(game, mine, row, col);
    return count;
}

如果读到了雷,返回0;如果读到了非零区域,则将其翻开;若读到了周围没有雷的区域,则将其周围的方块自动翻开,直到不为0为止,这里我使用了一个叫continues_map的函数。
那么问题来了,要如何实现自动翻开的功能呢?
要回答这个问题,首先就要清楚连续翻的规则:在扫雷游戏中,提示数为0的方块表示周围没有雷,因此这个方块周围的八个方块都是可以翻开的,而且如果这八个方块之中有提示数为0的方块,则继续将该方块的周围八个方块翻开,直到碰到提示数不为0的方块为止,并将其翻开······这样来看,能否用循环语句来实现呢?我们想想算法思路:

1、判断该方块是否是“0”方块. 如果是,则扫描该方块的周围8个小方块;如果不是,则将该提示数录入game_map中;
2、对这8个方块分别执行步骤1.

考虑一下极端情况,若这8个方块也都是“0”方块,那么是否能用循环继续对这八个方块分别扫描?就算可以,继续考虑极端情况,能否继续用循环对周围16个方块进行扫描?随着问题规模的增加,循环逐渐乏力,也就是说使用循环处理该问题并不好——就算用循环实现了,代码也将会非常复杂,可读性非常之差,不利于后期的维护和修改。
那应该使用什么方法来实现?我们接着看算法思路,首先进行判断,如果条件满足,则将原问题分解为8个子问题,再对这8个子问题进行之前的操作,直到将所有满足判断条件的子问题处理完为止——这样来看,这不就是递归调用的特性嘛。
于是,只要将该函数写成递归形式不就行了嘛:

int continues_map(char game[MAX_ROW][MAX_COL], char mine[MAX_ROW][MAX_COL], int row, int col)
{
    int count = 1;
    int left = col - 1, right = col + 1, up = row + 1, down = row - 1;
    if (left >= 0 && game[row][left] == '#' && mine[row][left] == '0')
    {
        game[row][left] = '0';
        count = count + continues_map(game, mine, row, left);
    }
    else if (left >= 0 && game[row][left] == '#')
    {
        game[row][left] = mine[row][left];
        count++;
    }
    if (right < MAX_COL && game[row][right] == '#' && mine[row][right] == '0')
    {
        game[row][right] = '0';
        count = count + continues_map(game, mine, row, right);
    }
    else if (right < MAX_COL && game[row][right] == '#')
    {
        game[row][right] = mine[row][right];
        count++;
    }
    if (up < MAX_ROW && game[up][col] == '#' && mine[up][col] == '0')
    {
        game[up][col] = '0';
        count = count + continues_map(game, mine, up, col);
    }
    else if (up < MAX_ROW && game[up][col] == '#')
    {
        game[up][col] = mine[up][col];
        count++;
    }
    if (down >= 0 && game[down][col] == '#' && mine[down][col] == '0')
    {
        game[down][col] = '0';
        count = count + continues_map(game, mine, down, col);
    }
    else if (down >= 0 && game[down][col] == '#')
    {
        game[down][col]= mine[down][col];
        count++;
    }
    if (left >= 0 && game[up][left] == '#' && mine[up][left] == '0')
    {
        game[up][left] = '0';
        count = count + continues_map(game, mine, up, left);
    }
    else if (left >= 0 && game[up][left] == '#')
    {
        game[up][left] = mine[up][left];
        count++;
    }
    if (right < MAX_COL && game[up][right] == '#' && mine[up][right] == '0')
    {
        game[up][right] = '0';
        count = count + continues_map(game, mine, up, right);
    }
    else if (right < MAX_COL && game[up][right] == '#')
    {
        game[up][right] = mine[up][right];
        count++;
    }
    if (left >= 0 && game[down][left] == '#' && mine[down][left] == '0')
    {
        game[down][left] = '0';
        count = count + continues_map(game, mine, down, left);
    }
    else if (left >= 0 && game[down][left] == '#')
    {
        game[down][left] = mine[down][left];
        count++;
    }
    if (right < MAX_COL && game[down][right] == '#' && mine[down][right] == '0')
    {
        game[down][right] = '0';
        count = count + continues_map(game, mine, down, right);
    }
    else if (right < MAX_COL && game[down][right] == '#')
    {
        game[down][right] = mine[down][right];
        count++;
    }
    return count;
}

一共八种情况和终止条件,写成递归都挺复杂的,更不用说循环了······
写到这里,一个用以实现扫雷游戏功能的程序大致就写得差不多了,再加上一个主函数就可以玩了。主函数的功能主要就是对以上的函数进行调用来实现游戏功能,并对玩家输入的合法性进行判断,代码如下:

int main()
{
    srand((unsigned)time(0));
    char mine_map[MAX_ROW][MAX_COL];
    char game_map[MAX_ROW][MAX_COL];
    int input_row = 0;
    int input_col = 0;
    int count = 0;
    int increase = 0;
    display_map(game_map);
    while (count < MAX_ROW*MAX_COL - MAX_MINE)
    {        
        //读取坐标并效验
        printf("输入您将要翻开的格子的坐标(row, col): \n");
        scanf("%d %d", &input_row, &input_col);
        if (input_row<1 || input_row>MAX_ROW
            || input_col<1 || input_col>MAX_COL
            || game_map[input_row - 1][input_col - 1] != '#')
        {
            printf("输入有误,请重新输入...\n");
            continue;
        }
        input_row -= 1;
        input_col -= 1;
        increase = renew_map(game_map, mine_map, input_row, input_col);
        display_map(game_map);
        if (increase == 0)
            break;
        count = count + increase;
    }
    if (count == 0)
        printf("你是来自非洲的黑人朋友?\n");
    else if (count == MAX_ROW * MAX_COL - MAX_MINE)
        printf("YOU WIN!\n");
    else
        printf("游戏结束!\n");
    system("pause");
    return 0;
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程网。

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

C语言二维数组运用实现扫雷游戏

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

C语言二维数组怎么应用实现扫雷游戏

本篇内容介绍了“C语言二维数组怎么应用实现扫雷游戏”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!游戏简介:电脑随机设置10个雷,用户输入坐标
2023-07-02

C语言数组怎么实现扫雷游戏

本篇内容主要讲解“C语言数组怎么实现扫雷游戏”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“C语言数组怎么实现扫雷游戏”吧!1、扫雷是什么?百度百科:《扫雷》是一款大众类的益智小游戏,于1992年
2023-06-30

怎么使用C语言数组实现扫雷游戏

本篇内容主要讲解“怎么使用C语言数组实现扫雷游戏”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“怎么使用C语言数组实现扫雷游戏”吧!游戏界面展示:一开始菜单界面:选择 0 退出程序:选择 1 开始
2023-07-02

使用C语言实现扫雷游戏

这篇文章主要为大家详细介绍了使用C语言实现扫雷游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
2022-11-13

C语言怎样实现扫雷游戏

这篇文章主要介绍了C语言怎样实现扫雷游戏,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。概述扫雷是一款大众类的益智小游戏。游戏目标是根据点击格子出现的数字找出所有非雷格子,同时
2023-06-15

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录