C语言——扫雷游戏

本文详细介绍了如何使用C语言实现一个基础的扫雷游戏,包括游戏规则、二维数组的设计、雷和非雷的表示方法、避免越界访问的技巧以及游戏的菜单逻辑和核心功能实现。
摘要由CSDN通过智能技术生成

一,游戏介绍   

        扫雷是一款很大众的益智类游戏,游戏规则也很简单,在短时间内把所有的雷排查出来即为胜利,如果在排雷期间踩到雷则游戏失败。本次制作的是一个初级的(10颗雷),玩家需要翻开所有不是雷的格子才能取得胜利,如果翻开的是有雷的格子则游戏失败。如果翻开的格子没有雷,则这个格子会显示周围8个格子中雷的个数。

二,游戏思路

       首先,我们需要思考应该怎样构建这个游戏的基本框架呢?

       看到这个图时,可以明显感觉和方格图有点类似,那我们就可以尝试用一个二维数组来构建这个游戏的主体,那需要一个多大的二维数组呢,我们继续分析。
        接下来我们先思考,如何把雷和非雷区分开呢,这时候大家首先能想到的应该是雷用‘*’号,非雷用‘#’号,等等这种想法都没有任何问题,但这里给大家提一个思路就是,雷用字符‘1’表示,非雷用字符‘0’表示,这样建议肯定有一定的好处,而且会对后面我们排查雷的时候,这样容易计算格子周围一圈雷的个数。如果这个格子周围没有雷就可以显示‘0’,如果有一个雷则显示‘1’,以此类推可以更方便的为排雷提供信息。
        假设当我们布置完十个雷之后,开始游戏,然后随机点一个格子,如果这个格子是雷,则游戏结束,如果这个格子不是雷,那么就会显示这个格子周围一圈的雷的个数,如果周围是一个雷的话,则显示‘1’,那么问题来了,这里的‘1’,到底是该格子周围雷的个数呢,还是雷呢?所以为了解决这个问题,我们需要建立两个二维数组,一个用来我们布置雷‘1’和非雷‘0’(mine),这个是用户看不见的,另一个用于展示给玩家看的棋盘(show),存放的是排查雷的信息,这样两边就不会冲突了。展示给玩家看的数组为了保持神秘感,我们最开始放的全是✳,这时我们创建的数组就是字符数组。
        紧接着,我们思考一下,我们翻格子的时候,如果这个格子不是雷,那么就会排查这个格子周围八个格子存在雷的个数,假设我们翻开最外围的格子的时候,但是该格子外围时没有格子的怎么办?这是侯就会出现越界访问的情况,为了避免这个情况出现,我们只需要把9*9的格子扩张成11*11的格子就可以了,如图所示,这样遍历的时候就不会出现越界访问的情况了。

三,游戏的实现

为了使游戏代码逻辑清晰可以文件形式创作,创建game.c文件(用于测试函数),创建game.h文件(用于游戏函数的声明和头文件的引用),创建test.c文件(用于游戏的框架和实现)。

1,菜单的打印

      菜单的打印采用do-while循环,其中运用switch语句可以更好的控制游戏的开始与结束。

2,初始化数据

       首先我们定义两个数组,一个是用来存放布置雷的信息,另一个是存放排查雷的信息。为了方便我们以后对代码的修改以及对游戏的优化,我们这里在头文件中把行和列分别定义出来,如果以后想玩更大的棋盘,我们只需在头文件中进行修改即可。

        然后就可以对两个数组进行初始化了,并且要把参数传进去。

3,打印棋盘

       当我们初始完之后,我们想要看看棋盘到底是什么样的,那么我们就需要打印棋盘,打印棋盘的时候,展示给我们的其实是9*9的棋盘,我们最开始设成11*11的棋盘只是为了防止越界访问。
打印的时候行和列都是1-9,这样方便后续通过坐标来排雷。

4,布置雷

      接下来我们需要布置雷,大家思考一下,我们布置雷实际上还是把雷放在中间的9*9的数组中去,也就是说我们这里布置雷只需要操作mine数组。怎么实现呢,这里我们假设布置十个雷,那么我们就需要生成十个随机坐标,来放置雷。但是为了以后方便更改数据,所以这里我们可以把雷的数量在头文件中。在放置雷的时候,需要随机,这就需要我们对count进行改造,运用时间戳来产生随机值。

5,排雷

       我们有两个数组mine,show。show数组我们可以看见,但是我们排雷是对mine数组进行的,并且要把排查结果反应到show中让我们看到。

计算周围雷的个数时要注意,我们mine数组中存的时字符‘0’,‘1’,我们直接找出周围8个格子的坐标,并且相加再减去8个‘0’,最后所得的ASCII值即为8个格子中的雷的数目。

四,总结

       扫雷游戏简单但是代码较复杂,还需要多加理解,才能够真正的掌握理解,也许这就是C语言的魅力,可以通过一行行的字母来完成一个简单的小游戏。并且这个扫雷游戏需要将71个不是雷的坐标全部翻开才算游戏胜利。游戏设计比较简单还可以添加更多功能,希望小伙伴们将其完善的更完美。

五,源码

game.h

#define  _CRT_SECURE_NO_WARNINGS 1

#include<stdio.h>
#include<stdlib.h>
#include<time.h>

#define EASY_COUNT 10

#define ROW 9
#define COL 9

#define ROWS ROW+2
#define COLS COL+2

//棋盘的初始化
void InitBoard(char board[ROWS][COLS], int rows, int cols,char set);

//打印棋盘
void DisplayBoard(char board[ROWS][COLS], int row, int col);

//布置雷
void SetMine(char board[ROWS][COLS], int row, int col);

//排查雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);

game.c

#define  _CRT_SECURE_NO_WARNINGS 1

#include"game.h"

void InitBoard(char board[ROWS][COLS], int rows, int cols, char set)
{
    int i = 0;
    for (i = 0; i < rows; i++)
    {
        int j = 0;
        for (j = 0; j < cols; j++)
        {
            board[i][j] = set;
        }
    }
}

void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
    int i = 0;
    printf("--------扫雷游戏--------\n");
    for (i = 0; i <= col; i++)
    {
        printf("%d ", i);
    }
    printf("\n");
    for (i = 1; i <= row; i++)
    {
        printf("%d ", i);
        int j = 0;
        for (j = 1; j <= col; j++)
        {
            printf("%c ", board[i][j]);
        }
        printf("\n");
    }
}

void SetMine(char board[ROWS][COLS], int row, int col)
{
    //布置10个雷
    //生成随即坐标,布置雷
    int count = EASY_COUNT;
    while (count)
    {
        int x = rand() % row + 1;
        int y = rand() % col + 1;

        if (board[x][y] == '0')
        {
            board[x][y] = '1';
            count--;
        }
    }
}
//统计周围雷的个数
int GetMineCount(char mine[ROWS][COLS], int x, int y)
{
    return ((mine[x - 1][y] + mine[x - 1][y - 1] + mine[x][y - 1] + mine[x + 1][y - 1] 
        + mine[x + 1][y] + mine[x + 1][y + 1] + mine[x][y + 1] + mine[x - 1][y + 1] - 8 * '0'));
}

void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
    int x = 0;
    int y = 0;
    int win = 0;
    while (win < row * col - EASY_COUNT)
    {
        printf("请输入要排查的坐标:>");
        scanf("%d %d", &x, &y);
        if (x >= 1 && x <= row && y >= 1 && y <= col)
        {
            if (mine[x][y] == '1')
            {
                printf("很遗憾,你被炸死了\n");
                DisplayBoard(mine, ROW, COL);
                break;
            }
            else
            {
                //该位置不是雷,就要统计出这个坐标周围有几个雷
                int count = GetMineCount(mine, x, y);
                show[x][y] = count + '0';
                DisplayBoard(show, ROW, COL);
                win++;
            }
        }
        else
        {
            printf("坐标输入非法,请重新输入\n");
        }
    }
    if (win == row * col - EASY_COUNT)
    {
        printf("恭喜你,排雷成功\n");
        DisplayBoard(mine, ROW, COL);
    }
}
 

test.c

#define  _CRT_SECURE_NO_WARNINGS 1

#include"game.h"
//设置主页面
void menu()
{
    printf("*****************************\n");
    printf("*****************************\n");
    printf("**********1. play ***********\n");
    printf("**********0. exit ***********\n");
    printf("*****************************\n");
    printf("*****************************\n");
}

//完成游戏的整个过程
void game()
{
    char mine[ROWS][COLS];//布置好的雷的信息
    char show[ROWS][COLS];//存放排查出的雷的信息用于显示
    //初始化棋盘
    InitBoard(mine, ROWS, COLS, '0');
    InitBoard(show, ROWS, COLS, '*');

    //打印棋盘
    //DisplayBoard(mine, ROW, COL);
    DisplayBoard(show, ROW, COL);

    //布置雷
    SetMine(mine, ROW, COL);
    //DisplayBoard(mine, ROW, COL);
    
    //排查雷
    FindMine(mine, show, ROW, COL);
}

int main()
{
    int input = 0;
    do
    {
        menu();
        printf("请选择:>");
        scanf("%d", &input);
        switch (input)
        {
        case 1:
            game();
            break;
        case 0:
            printf("退出游戏\n");
            break;
        default:
            printf("选择错误,请重新选择\n");
            break;
        }
    } while (input);
    return 0;
}
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

我比你更怕啊

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

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

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

打赏作者

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

抵扣说明:

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

余额充值