C语言实现扫雷游戏(详解)

举报
YIN_尹 发表于 2023/08/03 17:21:48 2023/08/03
【摘要】 一.扫雷游戏简介扫雷相信大家也都应该玩过,在这里还是简单介绍一下:《扫雷》是一款大众类的益智小游戏,游戏目标是在最短的时间内根据点击格子出现的数字找出所有非雷格子,同时避免踩雷,踩到一个雷即全盘皆输。每个格子上显示的数字即表示该格子周围雷的个数那么我们接下来带领大家实现一个大小为9*9的扫雷游戏:二.C语言代码实现1.整体框架简述最终实现游戏的完整代码,我们放在三个文件中,方便对我们的代码进...

一.扫雷游戏简介

扫雷相信大家也都应该玩过,在这里还是简单介绍一下:

《扫雷》是一款大众类的益智小游戏,游戏目标是在最短的时间内根据点击格子出现的数字找出所有非雷格子,同时避免踩雷,踩到一个雷即全盘皆输。

52cb441d51dd46dabc37f7cd22a4ca62.png

每个格子上显示的数字即表示该格子周围雷的个数

那么我们接下来带领大家实现一个大小为9*9的扫雷游戏:

二.C语言代码实现

1.整体框架简述

最终实现游戏的完整代码,我们放在三个文件中,方便对我们的代码进行管理。

57002f92d44943cf878aee38789a5f76.png

这三个文件分别是:

(1)test.c

用于对游戏逻辑的测试

(2)game.h

游戏实现相关的函数声明,符号声明,头文件的包含

(3)game.c

游戏实现相关函数的实现


全部的代码我们放在最后供大家参考


2.游戏整体逻辑的实现及测试

我们先在test.c文件对扫雷游戏的整体流程进行一个实现,测试一下逻辑是否正确,实现游戏功能的函数我们先不具体实现:

#include "game.h"
//打印菜单函数
void menu()
{
    printf("**********************************\n");
    printf("******       1. play       *******\n");
    printf("******       0. exit       *******\n");
    printf("**********************************\n");
}

//游戏实现函数
play_game()
{
    printf("扫雷\n");
}

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

7901b8540ee548b2abb65c0f58b92221.png

测试一下:

71641b1d44eb49eeadee4dbf61273a15.png

3.游戏具体过程实现

(1)设计布置雷的棋盘和打印信息的棋盘

1128c43c530c44a19c67e664c9652d05.png

既然要实现一个9X9的扫雷,我们就需要一个9X9大小的棋盘,那我们是不是可以考虑使用一个9X9的二维数组呢

但是,如果我们就把大小设置程9*9的二维数组,会发现其实存在一些问题:

要实现扫雷的话我们就要统计一下每个格子周围雷的个数

321698c88f3b42bea32c86704af7dcbf.png

所以,我们不妨把这个数组搞大点,用一个11X11的二维数组外边的两圈我们不放雷就行了,这样就不会越界访问了;

现在有一个数组来放雷了,但是在游戏过程中我们是不是还需要打印雷的数量信息便于玩家排雷,所以我们再搞一个11X11的二维数组来表示雷的数量信息

2ad5782c24d941cb8ce9abdefd67a7f7.png

那接下来我们就定义这样两个数组并对他们按要求进行初始化;

首先,我们为了以后如果想修改棋盘大小比较方便,我们在头文件game.h 中用关键字define定义两个标识符常量

7f6e6d2f4cf04a3f868b44c718f67788.png

97883ba8637540a894c3360884954b65.png

88d355a5c2e442e48d0b991a6b561fca.png

记得在test.c和game.c中别忘了引用头文件“game.h”。

现在初始化好了,那我们定义一个打印棋盘的函数:

944ef453312f4132a9be58435cc53a00.png

调用并运行一下:

98a1cdbc85b649f688803074ccd367fe.png

6bbf7894186c4a0fadf859f4209278cf.png

(2)在棋盘上布置雷

现在棋盘已经设计好了,我们就可以在棋盘上布置雷了,我们规定一下,每一局我们布置10个雷:

设计一个布置雷的函数:

我们的思路是随机生成两个1~9的随机数作为雷的坐标,然后在该位置放雷,这里又用到了rand函数来生成随机数

f506f49510eb48ceafe6427da953a0c6.png

当然记得调用srand设置随机数生成器srand((unsigned int)time(NULL)),在main函数中调用一次即可;

使用srand函数时需要包含#include 这个头文件,time函数需要包含#include 头文件。


运行一下看看效果:

f715980e4fdc494ea42189a7f5561188.png

(3)排查雷

雷布置好了,那我们现在就可以排查雷了。

排查的话,我们是不是要在mine数组里面排查,因为雷是布置在这个数组里的,然后我们把排查到的信息存放到show数组中,这个数组是用来显示排查出的雷的信息的

然后我们来定义排查雷的函数,思路是这样的:

1.让玩家输入一个坐标,判断是否合法,不合法提示玩家重新输入

2.如果合法,判断该坐标是否是否已经被排查过,若被排查过,提示玩家重新输入

3.若没被排查过,再判断该坐标放的是否是雷(即是否==1),是雷的话,提示玩家被炸死,结束游戏。

4.若不是雷,计算出该坐标周围的雷的个数,结果放到show数组对应元素中,展示出来。

5.在判断雷的个数这里,因为我们布置雷的时候是无雷是字符’0‘,有雷是字符’1‘,我们采用的方法是对它周围的一圈元素进行遍历求和,再减去8乘以字符’0‘,结果就是雷的个数(因为字符1跟字符0的ASCII码值差值也是1)

6.如果排查了 71次还没被炸死,则玩家获胜(因为我们放了10个雷,9乘9-10=71)

7b0281397e054839a7dc3d4960d4062d.png

统计雷个数的函数:

3abcdc5976cb4bc486bb2ba55c5e7383.png好了,到这里,我们就实现完了!!!

玩一把试试:

1fc34caa16ac4e05a4d09269cd93f7d8.png

可以正常玩了!!!

4.代码展示

(1)test.c

用于对游戏逻辑的测试

#include "game.h"
//打印菜单函数
void menu()
{
    printf("**********************************\n");
    printf("******       1. play       *******\n");
    printf("******       0. exit       *******\n");
    printf("**********************************\n");
}

//游戏实现函数
play_game()
{
    //创建两个字符数组
    char mine[ROWS][COLS] = { 0 };  //用于布置雷
    char show[ROWS][COLS] = { 0 };  //用于显示排查的雷的信息

    //初始化棋盘
    InitBoard(mine, ROWS, COLS, '0');  //全部初始化为'0'
    InitBoard(show, ROWS, COLS, '*');  //全部初始化为'*'

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

    //布置雷
    set_mine(mine, ROW, COL);
    //print_board(show, ROW, COL);

    //排查雷
    print_board(show, ROW, COL);
    find_mine(mine, show, ROW, COL);
}

int main()
{
    int elect = 0;
    srand((unsigned int)time(NULL));
    do
    {
        menu();
        printf("请选择:");
        scanf("%d", &elect);
        switch (elect)
        {
        case 1:
            play_game();
            break;
        case 0:
            printf("退出游戏!!!\n");
            break;
        default:
            printf("选择错误,请重新选择!!!\n");
            break;
        }
    } while (elect);
    return 0;
}

(2)game.h

游戏实现相关的函数声明,符号声明,头文件的包含

#pragma once

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



#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
#define EASY_COUNT 10


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

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

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

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

(3)game.c

游戏实现相关函数的实现

#include "game.h"

//初始化数组的函数实现
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set) 
{
    int i = 0;
    int j = 0;
    for (i = 0; i < rows; i++) 
    {
        for (j = 0; j < cols; j++) 
        {
            board[i][j] = set;
        }
    }
}

//打印棋盘
void print_board(char board[ROWS][COLS], int row, int col) 
{
    int i = 0;
    int j = 0;
    //打印列号
    for (i = 0; i <= col; i++) 
    {
        printf("%d ", i);
    }
    printf("\n");
    for (i = 1; i <= row; i++) 
    {
        printf("%d ", i); //打印行号
        for (j = 1; j <= col; j++) 
        {

            printf("%c ", board[i][j]);
        }
        printf("\n");  //打印完一行需要换行
    }
}


//布置雷
void set_mine(char mine[ROWS][COLS], int row, int col)
{
    int count = 10;//10个雷
    while (count) 
    {
        int x = rand() % row + 1;//生成1~9的随机数
        int y = rand() % col + 1;

        if (mine[x][y] == '0') 
        {       
            mine[x][y] = '1';
            count--;
        }
    }
}


//计算雷的个数
int get_mine_count(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 find_mine(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 (show[x][y] == '*')
            {
                if (mine[x][y] == '1')
                {
                    printf("很遗憾,你被炸死了\n");
                    print_board(mine, ROW, COL);
                    break;
                }
                else
                {
                    int count = get_mine_count(mine, x, y);
                    show[x][y] = count + '0';
                    print_board(show, ROW, COL);
                    win++;
                }
            }
            else
            {
                printf("该坐标已经被排查过了\n");
            }
        }
        else
        {
            printf("坐标非法,请重新输入\n");
        }
    }
    if (win == row * col - EASY_COUNT)
    {
        printf("恭喜你,排雷成功\n");
        print_board(mine, ROW, COL);
    }
}

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。