【C语言步行梯】C语言实现扫雷游戏(含详细分析)

在这里插入图片描述

🎯每日努力一点点,技术进步看得见
🏠专栏介绍:【C语言步行梯】专栏用于介绍C语言相关内容,每篇文章将通过图片+代码片段+网络相关题目的方式编写,欢迎订阅~~

文章目录

  • 需求分析
  • 具体实现
    • 主函数体
    • 菜单实现
    • 游戏实现
      • 计算雷数量
      • 盘面设计
        • 初始化盘面
        • 显示盘面
      • 布置雷
      • 排雷函数
      • 游戏函数主体
    • 完整代码
    • 分文件编写


需求分析

以前Windows都会自带一款有趣的游戏,叫做扫雷。今天我们就一起使用C语言来实现一下这个经典的游戏。
在这里插入图片描述
下图演示的是一个9×9的盘面,其中含有10个雷。我们可以看到部分方格中含有数字,以图中红色数字2为例,它所在的9宫格已被涂成黄色。在它所在9宫格范围内有2个雷,故该位置有雷。
在这里插入图片描述
在开始的时候棋盘上已经埋藏好了雷,但玩家不知道雷的具体位置。在玩家点击不是雷的位置后,该位置将显示9宫格范围内的雷的数量。在玩家找出所有不是雷的位置后,玩家获胜。如果不慎点击到雷所在位置,则游戏结束。

举个例子吧!如下图,没有数字的位置是我们还未点击,且不知道是否有雷的区域。有数字的方格是已经点击,并且没有雷的位置。由于有数字的已经点击了,且保证其中没有雷。而1所在9宫格内必定有1个雷,故绿色箭头所指区域一定是雷。我们不能点击这个区域,否则游戏结束。

在这里插入图片描述

具体实现

主函数体

在主函数体内,我们需要调用一个menu函数,用它提醒用户:输入1开始游戏,输入0退出游戏。接收用户输入后,通过switch语句,执行game()函数或者退出游戏。menu和game函数将在下文中讲解。

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");}}while(input);return 0;
}

菜单实现

首先,我们需要一个菜单,提示用户:输入1可以开始游戏,输入0会退出游戏。我通过封装一个menu函数实现↓↓↓

void menu()
{printf("**************************************************************\n");printf("******************* 1.play        0.exit *********************\n");printf("**************************************************************\n");
}

游戏实现

计算雷数量

由上面的需求可以知道,玩家在输入某个坐标后,如果该位置没有雷,则需要在该坐标位置显示其所在9宫格内雷的数量。

如下图所示,若用户输入(3,3)坐标时,我们需要统计该坐标所在9宫格内雷的数量。即将数组中的(mine[1][1]+mine[1][2]+mine[1][3]+mine[2][1]+mine[2][3]+mine[3][1]+mine[3][2]+mine[3][3])-'0'*8的数值计算出来即可。

★ps:这里的mine数组存储的字符,所以在8个坐标相加后,需要减’0’*8。如果用户输入的坐标是雷,则游戏结束,不需要统计雷的数量,所以这里不需要统计用户输入的坐标内是否有雷。
在这里插入图片描述
但如果玩家输入的坐标是(1,1)时,此时数组将会越界。为了保证数组不越界,我们将原本为9×9的盘面,使用11×11的数组来存储。(下图中,红色字符0,表示的是多开辟的空间)。
在这里插入图片描述
经过上面的分析后,我们可以写出如下计算雷的函数↓↓↓

int getMindCount(char board[ROWS][COLS], int x, int y)
{return (board[x - 1][y - 1] + board[x - 1][y] + board[x - 1][y + 1] + board[x][y - 1] + board[x][y + 1] + board[x + 1][y - 1] + board[x + 1][y] + board[x + 1][y + 1]) - '0' * 8;
}

盘面设计

我们需要一个mine数组记录我们买下的雷的位置(如下图左侧所示)。为了不让用户看到雷的位置,我们需要另个数组,用于显示用户已经点击的位置,并将其展示给用户。
在这里插入图片描述
关于show数组,这里需要额外说明一下。假如用户输入坐标(1,1),此时需要判断mine[1][1]处是否有雷,如果有雷,则游戏结束;如果没有雷,且用户还有将所有没有雷的区域点击完,则游戏继续。在该区域没有雷的情况下,需要调用getMineCount(mine,1,1),计算该位置的雷数量,并将show[1][1]改为雷的数量。

初始化盘面

show数组显示给用户看前,均初始化为’*‘(星号)。而mine数组用于存储雷,在布置雷之前,应全部初始化为’0’(字符0表示没有雷,字符1表示有雷)。因此,我们需要实现一个初始化盘面的函数↓↓↓

//初始化盘面
void initBoard(char board[ROWS][COLS], int rows, int cols, char set)
{for (int i = 0; i < rows; i++){for (int j = 0; j < cols; j++){board[i][j] = set;}}
}
显示盘面

在玩家输入坐标前,我们需要展示当前盘面状态(哪些已经点击过了,哪些还没有点击过),以方便用户输入坐标。下面我们实现一个展示盘面的函数↓↓↓

void displayBoard(char board[ROWS][COLS], int rows, int cols)
{for (int i = 1; i < rows - 1; i++){if (i == 1){for (int j = 0; j < cols - 1; j++){if (j == 1)printf(" ");printf("%2d", j);}printf("\n");}printf("%2d ", i);for (int j = 1; j < cols - 1; j++){printf( " %c", board[i][j]);}printf("\n");}
}

其展示效果如下:
在这里插入图片描述

布置雷

在游戏前,我们需要给mine数组设置雷。需要使用到随机数函数rand()。其实现代码如下↓↓↓

void setMine(char board[ROWS][COLS], int rows, int cols)
{int mine = MINE;while (mine){int x = rand() % rows + 1;int y = rand() % cols + 1;if (board[x][y] == '0'){board[x][y] = '1';mine--;}}
}

排雷函数

我们需要一个函数,用于与玩家进行交互,接受玩家输入的坐标,检查该坐标是否有雷。如果该坐标没有雷,则检查所有非雷坐标是否均被点击,如果均被点击,则玩家获胜;如果未全部点击,则游戏继续。如果该坐标有雷,则玩家游戏失败。
在这里插入图片描述

void findMine(char mine[ROWS][COLS], char show[ROWS][COLS], int rows, int cols)
{int min = (rows - 2) * (cols - 2) - MINE;int x = 0;int y = 0;do{displayBoard(show, ROWS, COLS);printf("请输入排雷坐标>");scanf("%d %d", &x, &y);if (x >= 0 && x <= rows && y >= 0 && y <= cols){if (mine[x][y] == '1'){printf("挑战失败,您被炸死了!\n");break;}else{int count = getMindCount(mine, x, y);show[x][y] = '0' + count;min--;}}else{printf("输入的坐标有误,请重新输入\n");}} while (min);if (min == 0)printf("恭喜你!排雷成功!\n");
}

游戏函数主体

在实现了上述各个函数后,我们只要稍加组织,就可以实现游戏了。

void game()
{char mine[ROWS][COLS];//存储雷char show[ROWS][COLS];//显示给用户看的//初始化盘面initBoard(mine, ROWS, COLS, '0');initBoard(show, ROWS, COLS, '*');//布置雷setMine(mine, ROW, COL);//开始排除雷findMine(mine, show, ROWS, COLS);
}

完整代码

上面代码中主函数中没有加入随机数种子,在下面代码中加入了srand((unsigned int)time(NULL)),同时对于上面出现ROW、COL的宏定义等也在下方代码整体给出。

#include <stdio.h>
#include <stdlib.h>
#include <time.h>#define ROW 9
#define COL 9
#define MINE 10#define ROWS (ROW+2)
#define COLS (COL+2)void menu()
{printf("**************************************************************\n");printf("******************* 1.play        0.exit *********************\n");printf("**************************************************************\n");
}//初始化盘面
void initBoard(char board[ROWS][COLS], int rows, int cols, char set)
{for (int i = 0; i < rows; i++){for (int j = 0; j < cols; j++){board[i][j] = set;}}
}//显示盘面
void displayBoard(char board[ROWS][COLS], int rows, int cols)
{for (int i = 1; i < rows - 1; i++){if (i == 1){for (int j = 0; j < cols - 1; j++){if (j == 1)printf(" ");printf("%2d", j);}printf("\n");}printf("%2d ", i);for (int j = 1; j < cols - 1; j++){printf( " %c", board[i][j]);}printf("\n");}
}//埋雷
void setMine(char board[ROWS][COLS], int rows, int cols)
{int mine = MINE;while (mine){int x = rand() % rows + 1;int y = rand() % cols + 1;if (board[x][y] == '0'){board[x][y] = '1';mine--;}}
}//计算雷的数量
int getMindCount(char board[ROWS][COLS], int x, int y)
{return (board[x - 1][y - 1] + board[x - 1][y] + board[x - 1][y + 1] + board[x][y - 1] + board[x][y + 1] + board[x + 1][y - 1] + board[x + 1][y] + board[x + 1][y + 1]) - '0' * 8;
}//找雷
void findMine(char mine[ROWS][COLS], char show[ROWS][COLS], int rows, int cols)
{int min = (rows - 2) * (cols - 2) - MINE;int x = 0;int y = 0;do{displayBoard(show, ROWS, COLS);printf("请输入排雷坐标>");scanf("%d %d", &x, &y);if (x >= 0 && x <= rows && y >= 0 && y <= cols){if (mine[x][y] == '1'){printf("挑战失败,您被炸死了!\n");break;}else{int count = getMindCount(mine, x, y);show[x][y] = '0' + count;min--;}}else{printf("输入的坐标有误,请重新输入\n");}} while (min);if (min == 0)printf("恭喜你!排雷成功!\n");
}//游戏
void game()
{char mine[ROWS][COLS];//存储雷char show[ROWS][COLS];//显示给用户看的//初始化盘面initBoard(mine, ROWS, COLS, '0');initBoard(show, ROWS, COLS, '*');//布置雷setMine(mine, ROW, COL);//开始排除雷findMine(mine, show, ROWS, COLS);
}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");}} while (input);return 0;
}

分文件编写

可以创建game.h保存头文件,及各函数的函数声明;game.c保存各个函数的具体实现;main.c中保存主函数。

game.h ↓↓↓

#pragma once#define _CRT_SECURE_NO_WARNINGS 1#include <stdio.h>
#include <stdlib.h>
#include <time.h>#define ROW 9
#define COL 9
#define MINE 10#define ROWS (ROW+2)
#define COLS (COL+2)//菜单
void menu();//初始化盘面
void initBoard(char board[ROWS][COLS], int rows, int cols, char set);//显示盘面
void displayBoard(char board[ROWS][COLS], int rows, int cols);//埋雷
void setMine(char board[ROWS][COLS], int rows, int cols);//计算雷的数量
int getMindCount(char board[ROWS][COLS], int x, int y);//找雷
void findMine(char mine[ROWS][COLS], char show[ROWS][COLS], int rows, int cols);//游戏
void game();

game.c ↓↓↓

#include "game.h"void menu()
{printf("**************************************************************\n");printf("******************* 1.play        0.exit *********************\n");printf("**************************************************************\n");
}//初始化盘面
void initBoard(char board[ROWS][COLS], int rows, int cols, char set)
{for (int i = 0; i < rows; i++){for (int j = 0; j < cols; j++){board[i][j] = set;}}
}//显示盘面
void displayBoard(char board[ROWS][COLS], int rows, int cols)
{for (int i = 1; i < rows - 1; i++){if (i == 1){for (int j = 0; j < cols - 1; j++){if (j == 1)printf(" ");printf("%2d", j);}printf("\n");}printf("%2d ", i);for (int j = 1; j < cols - 1; j++){printf( " %c", board[i][j]);}printf("\n");}
}//埋雷
void setMine(char board[ROWS][COLS], int rows, int cols)
{int mine = MINE;while (mine){int x = rand() % rows + 1;int y = rand() % cols + 1;if (board[x][y] == '0'){board[x][y] = '1';mine--;}}
}//计算雷的数量
int getMindCount(char board[ROWS][COLS], int x, int y)
{return (board[x - 1][y - 1] + board[x - 1][y] + board[x - 1][y + 1] + board[x][y - 1] + board[x][y + 1] + board[x + 1][y - 1] + board[x + 1][y] + board[x + 1][y + 1]) - '0' * 8;
}//找雷
void findMine(char mine[ROWS][COLS], char show[ROWS][COLS], int rows, int cols)
{int min = (rows - 2) * (cols - 2) - MINE;int x = 0;int y = 0;do{displayBoard(show, ROWS, COLS);printf("请输入排雷坐标>");scanf("%d %d", &x, &y);if (x >= 0 && x <= rows && y >= 0 && y <= cols){if (mine[x][y] == '1'){printf("挑战失败,您被炸死了!\n");break;}else{int count = getMindCount(mine, x, y);show[x][y] = '0' + count;min--;}}else{printf("输入的坐标有误,请重新输入\n");}} while (min);if (min == 0)printf("恭喜你!排雷成功!\n");
}//游戏
void game()
{char mine[ROWS][COLS];//存储雷char show[ROWS][COLS];//显示给用户看的//初始化盘面initBoard(mine, ROWS, COLS, '0');initBoard(show, ROWS, COLS, '*');//布置雷setMine(mine, ROW, COL);//开始排除雷findMine(mine, show, ROWS, COLS);
}

main.c ↓↓↓

#include "game.h"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;
}

🚩这篇文章结束了~~
如果文章中出现了错误,欢迎私信或留言。(๑•̀ㅂ•́)و✧
有任何疑问请评论或私信哦~~o( ̄▽ ̄)ブ

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/757800.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Docker 从0安装 nacos集群

前提条件 Docker支持一下的CentOs版本 Centos7(64-bit)&#xff0c;系统内核版本为 3.10 以上Centos6.5(64-bit) 或者更高版本&#xff0c;系统内核版本为 2.6.32-431 或者更高版本 安装步骤 使用 yum 安装&#xff08;CentOS 7下&#xff09; 通过 uname -r 命令查看你当…

MFC界面美化第四篇----自绘list列表(重绘列表)

1.前言 最近发现读者对我的mfc美化的专栏比较感兴趣&#xff0c;因此在这里进行续写&#xff0c;这里我会计划写几个连续的篇章&#xff0c;包括对MFC按钮的美化&#xff0c;菜单栏的美化&#xff0c;标题栏的美化&#xff0c;list列表的美化&#xff0c;直到最后形成一个完整…

Codeforces Round 935 (Div. 3)(A,B,C,D,E,F)

比赛链接 阳间场&#xff0c;阴间题&#xff0c;最考阅读理解的一场。题目本身的难度不大。 A. Setting up Camp 题意&#xff1a; 组委会计划在奥运会结束后带领参赛者进行一次徒步旅行。目前&#xff0c;需要携带的帐篷数量正在计算中。据了解&#xff0c;每个帐篷最多可容…

前端vue3-手动设置滚动条位置/自动定位

从B页面进行xx操作后需要跳转到A页面&#xff0c;并定位到AA职位&#xff0c;上图为A页面。 A页面的左侧是div&#xff0c;内层包裹List组件 给div定义refleftRef,在代码中写如下&#xff1a; function scrollTop() {if (leftRef.value) {console.log(99, leftRef.value);next…

0基础 三个月掌握C语言(13)

数据在内存中的存储 整数在内存中的存储 在讲解操作符时 我们就已经学习了该部分的内容 这里我们回顾一下 整数的二进制表示方法有三种&#xff1a;原码 反码 补码 有符号的整数&#xff08;unsigned&#xff09; 三种表达方式均有符号位和数值位两部分 最高位的一位被当…

文件包含漏洞之包含SESSION(CTF题目)

这次使用的环境是ubuntunginxphpmysql 首先四个文件源码在以下链接中&#xff1a; 一道CTF题&#xff1a;PHP文件包含 | Chybeta 我们注册一个用户名111密码111&#xff0c;然后登录查看cookie和linux的session&#xff0c;因为我们的de服务器 是手动搭建的&#xff0c;所以…

Java IO模型

NIO Java IO 模型1. 什么是IO计算机结构角度应用程序角度 2. 常见的内存模型3. Java中常见的IO模型3.1 BIO&#xff08;Blocking I/O&#xff09;3.2 NIO&#xff08;Non-blocking/New I/O&#xff09;同步非阻塞 IO 模型I/O 多路复用模型 3.3 AIO&#xff08;Asynchronous I/O…

Spring6.1新特性,四种方式调用REST接口(RestClient、WebClient、RestTemplate、HTTP Interface)

个人博客&#xff1a;无奈何杨&#xff08;wnhyang&#xff09; 个人语雀&#xff1a;wnhyang 共享语雀&#xff1a;在线知识共享 Github&#xff1a;wnhyang - Overview 官网 REST Clients :: Spring Framework The Spring Framework provides the following choices for…

电子元器件批发采购中的供应链透明度与可追溯性

电子元器件批发采购中的供应链透明度与可追溯性是非常重要的&#xff0c;特别是考虑到供应链的复杂性和全球化。以下是一些关于如何增强供应链透明度和可追溯性的建议&#xff1a; 供应商审核与选择&#xff1a;对潜在的供应商进行全面的审核和评估&#xff0c;了解其供应链结构…

【Leetcode】1793. 好子数组的最大分数

文章目录 题目思路代码复杂度分析时间复杂度空间复杂度 结果总结 题目 题目链接&#x1f517; 给你一个整数数组 n u m s nums nums &#xff08;下标从 0 0 0 开始&#xff09;和一个整数 k k k 。 一个子数组 ( i , j ) (i, j) (i,j) 的 分数 定义为 m i n ( n u m s …

ROS2从入门到精通0-3:VSCode 搭建 ROS2 工程环境

目录 0 专栏介绍1 Ubuntu下安装VSCode1.1 基本安装1.2 将VSCode添加到侧边栏 2 VSCode集成相关插件3 VSCode运行ROS2环境步骤3.1 安装编译依赖项3.2 创建工作空间和源码空间3.3 启动VSCode与配置 4 测试工程环境4.1 C版本4.2 Python版本 0 专栏介绍 本专栏旨在通过对ROS2的系统…

一、初识 web3

瑾以此系列文章&#xff0c;献给那些出于好奇并且想要学习这方面知识的开发者们 在多数时间里&#xff0c;我们对 web3 的理解是非常模糊的 就好比提及什么是 web1 以及 web2&#xff0c;相关概念的解释是&#xff1a; 1. 从 Web3 的开始 Web3&#xff0c;也被称为Web3.0&…

idea error java:compilation failed:internal java compiler error

idea中编译运行maven项目报错如下 idea error java:compilation failed:internal java compiler error 尝试如下操作 注意&#xff1a;jdk8 需要设置4个地方 1.首先打开File->Project Structure中的Project&#xff0c;将SDK和language level都设置一致&#xff0c;如下…

基于Java的考研专业课程管理系统(Vue.js+SpringBoot)

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 考研高校模块2.3 高校教师管理模块2.4 考研专业模块2.5 考研政策模块 三、系统设计3.1 用例设计3.2 数据库设计3.2.1 考研高校表3.2.2 高校教师表3.2.3 考研专业表3.2.4 考研政策表 四、系统展示五、核…

文件操作:文本文件(写/读)

文件操作可以将数据永久化&#xff0c;C中对文件操作需要包含头文件 < fstream > 文件类型分为两种&#xff1a; 1. 文本文件&#xff1a;文件以文本的ASCII码形式存储在计算机中 2. 二进制文件&#xff1a;文件以文本的二进制形式存储在计算机中&#xff0c;…

matplotlib绘制统计特征图和分布特征图

文章目录 一、统计特征图绘制1.需求2.代码方法一方法二总结 二、分布特征图绘制1.需求2.代码 一、统计特征图绘制 1.需求 我现在有两个数据集Pdata和Cdata分别在DataFrame对象中&#xff0c;我现在想对这两个数据集进行统计特征分析&#xff0c;并用直方图展示出来。 2.代码…

CSS学习(3)-浮动和定位

一、浮动 1. 元素浮动后的特点 脱离文档流。不管浮动前是什么元素&#xff0c;浮动后&#xff1a;默认宽与高都是被内容撑开&#xff08;尽可能小&#xff09;&#xff0c;而且可以设置宽 高。不会独占一行&#xff0c;可以与其他元素共用一行。不会 margin 合并&#xff0c;…

护眼大路灯好不好用?中国路灯排行榜

护眼大路灯好不好用&#xff1f;关于这个问题一直有争议&#xff0c;一部分人觉得大路灯不好用&#xff0c;而且会增加支出&#xff0c;绝大多数人则认为大路灯特别好用&#xff0c;之所以会有不同的看法&#xff0c;小编觉得&#xff0c;还是大家使用的大路灯不同&#xff0c;…

[C语言]——函数递归

目录 一.什么是递归 1.递归的思想&#xff1a; 二.递归的限制条件 三.递归举例 1.举例1&#xff1a;求n的阶乘 1.1分析和代码实现 1.2画图推演 2.举例2&#xff1a;顺序打印⼀个整数的每⼀位 2.1分析和代码实现 2.2画图推演 四.递归与迭代 1.举例3&#xff1a;求第…

分页多线程处理大批量数据

1.业务场景 因为需要从一个返利明细表中获取大量的数据&#xff0c;生成返利报告&#xff0c;耗时相对较久&#xff0c;作为后台任务执行。但是后台任务如果不用多线程处理&#xff0c;也会要很长时间才能处理完。 另外考虑到数据量大&#xff0c;不能一次查询所有数据在内存…