C语言扫雷游戏简单实现

news/2024/11/29 10:51:21/

一、实现思路
1、布置雷
定义二维字符数组mine,用以存放雷,以‘1’表示雷,‘0’表示无雷;
定义二维字符数组show,用以保存扫雷需要的信息;
2、排雷
以输入坐标的形式排雷,可能出现四种结果:

坐标非法;
踩到雷,游戏结束;
踩到处周边有雷,显示周边雷的数量;
踩到处周边无雷,将周边无雷的区域展开;
3、检查雷是否被排完
排完则游戏成功,否则游戏继续。

二、函数代码实现
1、“雷”数组的初始化以及打印“雷区”
初始化:
将数组中的元素全部初始化为set;
//初始化数组
void Initarr(char arr[ROWS][COLS], int row, int col, char set)
{
    for (int i = 0; i < row; i++)
    {
        for (int j = 0; j < col; j++)
        {
            arr[i][j] = set;
        }
    }
}
打印雷区:
利用分割线分开每一次排雷,打印行标与列标以便选择位置。
//打印“雷区”,由于第一行、最后一行、第一列与最后一列作为辅助作用,
//因此不予打印,只打印中间9行。
void Display(char arr[ROWS][COLS], int row, int col)
{
    printf("------- 扫雷 ------\n");
    printf("0 1 2 3 4 5 6 7 8 9\n");//打印列标
    for (int i = 1; i < row + 1; i++)
    {
        printf("%d ", i);//打印行标
        for (int j = 1; j < col + 1; j++)
        {
            printf("%c ", arr[i][j]);
        }
        printf("\n");
    }
    printf("------- 扫雷 ------\n");
}

2、布置雷与扫雷
布置雷
以count表示游戏难度,即布置雷的数量,通过传参保证函数脱离全局变量后依旧可用;
//随机布置雷
void Setmine(char mine[ROWS][COLS], int row, int col, int count)
{
    int x = 0;
    int y = 0;
    while (count)
    {
        //mine为11×11大小,首行末行与首列末列均不布置雷
        x = rand() % row + 1;
        y = rand() % col + 1;
        if (mine[x][y] == '0')
        {
            mine[x][y] = '1';
            count--;
        }
    }
}
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
扫雷,根据出现的情况进行分类
在判断输赢时采用了循环检查雷是否排查完成,效率较低;
//扫雷可能出现的情况:
// 1、坐标非法->重新输入
// 2、坐标合法->A、踩雷->游戏结束
//              B、未踩雷->a、周边有雷->显示雷的数量
//                         b、周边无雷->大面积展开
//              C、该位置已经被扫过->坐标非法
void Sweep(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col, int count)
{
    int x = 0, y = 0;
    while (1)
    {
        printf("请输入坐标:\n");
        scanf("%d %d", &x, &y);
        if (x < 1 || x > row || y < 1 || y > col)
        {
            printf("坐标非法,请重新输入:\n");
        }
        else if (mine[x][y] == '1')
        {
            printf("此处有雷,游戏结束\n");
            Display(mine, row, col);
            break;
        }
        else if (show[x][y] != '*')
        {
            printf("该位置已被扫过,请重新输入:\n");
        }
        else
        {
            //周边无雷
            if (get_mine(mine, x, y) == 0)
            {
                unfold(mine, show, x, y);
                Display(show, row, col);
            }
            //周边有雷
            else
            {
                show[x][y] = get_mine(mine, x, y) + '0';
                Display(show, row, col);
            }
        }
        //判断是否完成
        int win = 0;
        for (int i = 1; i < row + 1; i++)
        {
            for (int j = 1; j < col + 1; j++)
            {
                if (show[i][j] == '*')
                    win++;
            }
        }
        if (win == EASY)
        {
            printf("扫雷成功!\n");
            Display(mine, row, col);
            break;
        }
    }
        
}
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
递归展开无雷处
采用递归,依次判断周边的八个位置,达到展开效果;
void unfold(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y)
{
    if (x == 0 || x == ROW + 1 || y == 0 || y == COL + 1)
        return;
    if (show[x][y] == '*')
    {
        int ret = get_mine(mine, x, y);
        if (ret == 0)
        {
            show[x][y] = ' ';
            unfold(mine, show, x -1, y -1);
            unfold(mine, show, x - 1, y);
            unfold(mine, show, x - 1, y + 1);
            unfold(mine, show, x, y - 1);
            unfold(mine, show, x, y + 1);
            unfold(mine, show, x + 1, y - 1);
            unfold(mine, show, x + 1, y);
            unfold(mine, show, x + 1, y + 1);
        }
        else
        {
            show[x][y] = ret + '0';
        }
    }
}

获取周边雷的数量
检查周边8个位置的雷个数,利用两层嵌套循环检查;
//获取周边的雷的个数
int get_mine(char mine[ROWS][COLS], int x, int y)
{
    int count = 0;
    for (int i = -1; i < 2; i++)
    {
        for(int j = -1; j < 2; j++)
            if (mine[x + i][y + j] == '1')
            {
                count++;
            }
    }
    return count;
}

三、小tips
定义二维数组存放雷时,将数组定义大两个,9×9的棋盘采用11×11的数组,如此,即便是判断边缘格子时也可以采用一样的函数,不用担心越界;
定义游戏难度时,可将相关内容都放在头文件中,以#define定义的方式,方便以后修改;
定义函数时,可将只会在本.c文件中用到的函数前加上static,防止其他文件调用,同时也让在其他.c文件中定义函数时更为方便;
书写代码时,须首先严谨思考,考虑到各种结果,先思考再敲代码,会更有效率。
四、代码汇总
头文件game.h

#pragma once#include<stdio.h>
#include<stdlib.h>
#include<time.h>#define ROW 9
#define COL 9#define ROWS 11
#define COLS 11//游戏难度
#define EASY 10//初始化数组,初始arr数组中的值为set
void Initarr(char arr[ROWS][COLS], int row, int col, char set);//打印“雷区”
void Display(char arr[ROWS][COLS], int row, int col);//随机布置雷
void Setmine(char mine[ROWS][COLS], int row, int col, int count);//扫雷
void Sweep(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col, int count);函数文件game.c#define _CRT_SECURE_NO_WARNINGS 1#include"game.h"
//具体函数的实现//选择菜单
void menu()
{printf("******************\n");printf("***** 1、开始 ****\n");printf("***** 0、退出 ****\n");printf("******************\n");
}//初始化数组
void Initarr(char arr[ROWS][COLS], int row, int col, char set)
{for (int i = 0; i < row; i++){for (int j = 0; j < col; j++){arr[i][j] = set;}}
}//打印“雷区”,由于第一行、最后一行、第一列与最后一列作为辅助作用,因此不予打印,只打印中间9行
void Display(char arr[ROWS][COLS], int row, int col)
{printf("------- 扫雷 ------\n");printf("0 1 2 3 4 5 6 7 8 9\n");//打印列标for (int i = 1; i < row + 1; i++){printf("%d ", i);//打印行标for (int j = 1; j < col + 1; j++){printf("%c ", arr[i][j]);}printf("\n");}printf("------- 扫雷 ------\n");
}//随机布置雷
void Setmine(char mine[ROWS][COLS], int row, int col, int count)
{int x = 0;int y = 0;while (count){//mine为11×11大小,首行末行与首列末列均不布置雷x = rand() % row + 1;y = rand() % col + 1;if (mine[x][y] == '0'){mine[x][y] = '1';count--;}}
}//获取周边的雷的个数
static int get_mine(char mine[ROWS][COLS], int x, int y)
{int count = 0;for (int i = -1; i < 2; i++){for(int j = -1; j < 2; j++)if (mine[x + i][y + j] == '1'){count++;}}return count;
}//展开函数
static void unfold(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y)
{if (x == 0 || x == ROW + 1 || y == 0 || y == COL + 1)return;if (show[x][y] == '*'){int ret = get_mine(mine, x, y);if (ret == 0){show[x][y] = ' ';unfold(mine, show, x -1, y -1);unfold(mine, show, x - 1, y);unfold(mine, show, x - 1, y + 1);unfold(mine, show, x, y - 1);unfold(mine, show, x, y + 1);unfold(mine, show, x + 1, y - 1);unfold(mine, show, x + 1, y);unfold(mine, show, x + 1, y + 1);}else{show[x][y] = ret + '0';}}
}
//扫雷可能出现的情况:
// 1、坐标非法->重新输入
// 2、坐标合法->A、踩雷->游戏结束
//              B、未踩雷->a、周边有雷->显示雷的数量
//                         b、周边无雷->大面积展开
//              C、该位置已经被扫过->坐标非法
void Sweep(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col, int count)
{int x = 0, y = 0;while (1){printf("请输入坐标:\n");scanf("%d %d", &x, &y);if (x < 1 || x > row || y < 1 || y > col){printf("坐标非法,请重新输入:\n");}else if (mine[x][y] == '1'){printf("此处有雷,游戏结束\n");Display(mine, row, col);break;}else if (show[x][y] != '*'){printf("该位置已被扫过,请重新输入:\n");}else{//周边无雷if (get_mine(mine, x, y) == 0){unfold(mine, show, x, y);Display(show, row, col);}//周边有雷else{show[x][y] = get_mine(mine, x, y) + '0';Display(show, row, col);}}//判断是否完成int win = 0;for (int i = 1; i < row + 1; i++){for (int j = 1; j < col + 1; j++){if (show[i][j] == '*')win++;}}if (win == EASY){printf("扫雷成功!\n");Display(mine, row, col);break;}}    
}void game()
{// mine数组用以存放雷char mine[ROWS][COLS] = { 0 };// show数组用以存放扫出的信息char show[ROWS][COLS] = { 0 };//初始化mine数组为字符0,show数组为字符'*'Initarr(mine, ROWS, COLS, '0');//Display(mine, ROW, COL);//检测初始化效果Initarr(show, ROWS, COLS, '*');//Display(show, ROW, COL);//检测初始化效果Setmine(mine, ROW, COL, EASY);//Display(mine, ROW, COL);//查看雷的布置位置Display(show, ROW, COL);Sweep(mine, show, ROW, COL, EASY);
}


测试文件test.h
#define _CRT_SECURE_NO_WARNINGS 1

#include"game.h"

int main()
{
    int x = 0;
    srand((unsigned int)time(NULL));
    do
    {
        menu();
        scanf("%d", &x);
        switch (x)
        {
        case 1:
            printf("游戏开始\n");
            game();
            break;
        case 0:
            printf("游戏退出\n");
            break;
        default:
            printf("输入错误,请重新输入\n");
            break;
        }
    } while (x);
}

最后,如果还想了解更多知识,请关注我,感谢啦。


http://www.ppmy.cn/news/695729.html

相关文章

【记录】实践场景

Apache Doris 在京东搜索实时 OLAP 探索与实践 https://doris.apache.org/zh-CN/blog/JD_OLAP/ 通过对比开源的几款实时OLAP引擎&#xff0c;我们发现doris和clickhouse能够满足我们的需求&#xff0c;但是clickhouse的并发度太低是个潜在的风险&#xff0c;而且clickhouse的数…

新一代版本依赖管理Vesion Catalog的使用及发布

前言 前段时间使用新版本的Android Studio创建了个项目想测试点东西&#xff0c;项目创建后发现整个Gradle的依赖管理发生了巨大的变化。 先说一下我使用的Android Studio的版本如下。 创建项目后主要变化如下&#xff1a; 原本的.gradle变成了.gradle.kts&#xff0c;也就是…

网页直播英文版上线,跨国企业客户用着很酷哇

阿酷TONY原创文章 / 网页直播产品评测 / 长沙 网页直播是什么&#xff1f; 基于网页浏览器直接发起直播&#xff0c;比如打开谷歌浏览器&#xff0c;360浏览器直接登录发起直播即可&#xff0c;无须安装客户端软件&#xff0c;很方便很酷~~~ 第1部分&#xff1a;网页直播英文…

微云网页版服务器繁忙,腾讯微云传输速度慢的几种原因及解决方法

大家经常使用腾讯微云吧&#xff0c;不过大家知道腾讯微云传输速度慢怎么办吗?下面小编就给大家分享腾讯微云传输速度慢的几种原因及解决方法&#xff0c;希望会对你有所帮助。 腾讯微云传输速度慢的几种原因及解决方法&#xff1a; 1、网络宽带本身速度慢 解决办法&#xff1…

免费视频存储平台(微云、百度网盘、谷歌硬盘、酷播云)的截图对比

这个文章整理自2018年11月29日&#xff0c;主要是考虑的视频方面的存储平台&#xff0c;以下介绍了&#xff0c;腾讯的微云、百度网盘、谷歌云端硬盘、酷播云免费视频存储平台。 腾讯QQ的微云&#xff1a; 官网地址&#xff1a;https://www.weiyun.com 提供10G免费空间&…

整理网页资料加入App的流程

整理网页资料加入App的流程 编者&#xff1a;李国帅 qq&#xff1a;9611153 微信lgs9611153 时间&#xff1a;2019/11/11 起因: 以前收集了一些电子图书&#xff0c;后来学了android编程&#xff0c;就像把它们放到app里&#xff0c;自己有时间的话就会翻翻&#xff0c;比…

2021-06-15

作用: 这个只是一个简单的思路 作用是 就算脚本在客户手里 我们依然可以通过微云笔记来随时控制那边的脚本是否执行 比如客户拿了脚本跑路了 而且我们也没有做平时做的一些限制 我们可以使用微云来关闭脚本 客户运行脚本就会提示关闭无法运行下去 微云端&#xff1a; 脚本端&a…

IDM突破下载限制

IDM突破下载限制 好久没写了&#xff0c;水篇文刷一下存在感 各位都是大佬级别的人物&#xff0c;IDM是什么可能比我还清楚&#xff0c;我就不详细介绍了。如果有人不清楚&#xff0c;请看下文Wikipedia的解释。 Internet Download Manager&#xff08;简称IDM&#xff09;是一…