C语言:扫雷游戏实现
一、扫雷游戏的分析和设计
扫雷游戏想必大家都玩过吧,初级的玩法是在一个9*9的棋盘上找到没有雷的格子,而今天我们就要做的就是9*9扫雷游戏的实现。
1、游戏功能和规则
- 使用控制台实现经典的扫雷游戏
- 游戏可以通过菜单实现继续玩或者退出游戏
- 扫雷的棋盘是9*9的格⼦
- 默认随机布置10个雷(可随意)
- 可以排查雷
如果位置不是雷,就显示周围有几个雷
如果位置是雷,就炸死游戏结束
把除10个雷之外的所有非雷都找出来,排雷成功,游戏结束
2、游戏实现思路
- 首先,创建一个主函数用于判断是否进行游戏,并设计一个菜单。
- 创建用于存放雷的棋盘,并进行棋盘的初始化。
- 设计棋盘的打印。
- 放入雷,并实现有雷棋盘的打印。
- 输入坐标进行排查,并返回排查结果。
- 进行循环直到排查成功或被炸死。
在布置雷的过程中我们将雷设置为'1',不是雷设置为'0';
二、代码实现
在实现代码前,我们可以用多文件的方式,对我们的函数进行声明和定义,这样可以简化和简洁直观的设计和表达代码。
- game.h:我们可以在game.h文件中包含我们所有需要用到的头文件,常量的定义和函数的声明,其他文件只需要声明game.h 即可。
- game.c:写入游戏所需要的功能函数。
- test.c:代码的整合
1、主函数的实现
在主函数中我们先创建一个input值,用于输入我们的选择,根据 do while 循环判断我们是否进行游戏,并且每次循环都打印菜单,在接着使用switch语句根据玩家输入进行判断,如果输入为1就开始游戏执行game(),如果为0,游戏结束并跳出循环,如果输入错误就继续进行循环直到主动退出。
int main()
{int input = 0;srand((unsigned int)time(NULL));do {menu();printf("请输入选项:");scanf("%d", &input);switch (input){case 1:printf("开始游戏\n");game();break;case 0:printf("游戏结束\n");break;default:printf("选择错误,请重新选择:\n");break;}} while (input);return 0;
}
2、菜单的实现
不需要返回所以用void
void menu()
{printf("****************\n");printf("**** 1.play ****\n");printf("**** 0.exit ****\n");printf("****************\n");
}
3、游戏函数的实现
1、棋盘的设计
在排雷的过程中如果我们选择的位置不是雷就会看它周围的8个坐标中是否有雷,如果有雷就会显示雷的个数。
但如果我们选择的是边界位置,就会超出棋盘的范围,导致越界。
所以我们要将棋盘扩大一圈,这样就不存在越界问题了。
假设我们现在已经布置好了雷(雷用1表示,不是雷用0表示),当我们输入一个坐标的时候,如果这个坐标周围有一个雷,那么我们需要将这个雷的数量信息记录并存储下来,同时打印给玩家,但是我们存放雷的数组里面已经有数据了,如果再存放在里面就会可能产生混淆从而导致棋盘混乱打印困难,所以我们可以设置两个棋盘,一个是雷的棋盘mine,一个是用于放置雷的信息的棋盘show,我们后面会把雷布置到到mine数组里面,再mine数组排查雷之后,将雷的信息存放到show数组里面,然后打印show数组的信息给用户参考排查,这样就不会存在数据混淆了。
同时我们也要在game.h文件里进行常量的定义。
2、棋盘的初始化
在设计好棋盘后,我们就应该对棋盘进行初始化,首先,我们将mine棋盘全初始化为'0',show棋盘全初始化为'*'.
//棋盘的初始化
void InitBoard(char board[ROWS][COLS], int row, int col, char set)
{for (int i = 1; i < row; i++){for (int j = 1; j < col; j++){board[i][j] = set;}}
}
因为要初始化两个数组,所以我们需要创建一个char set,用于接收'0' 和 '*' 。
3、打印棋盘
因为是扫雷游戏,所以我们只需要打印一个隐藏信息的棋盘即可
我们只需要将show数组,行和列传给函数,并且为了显示行和列数,我们可以先利用for循环打印0-col的一行数,再进入棋盘的打印 ,在行的循环中打印一列数
//棋盘的打印
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{int i = 0;int j = 0;printf("-----------扫雷-------------\n");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");}printf("-----------扫雷-------------\n");
}
4、雷的布置
我们需要在mine数组里布置雷,那我们该如何布置呢?
1.这就需要用到我们的rand()函数了。
rand()函数是随机数生成函数,需要使用stdlib,h文件,但生成的数不是完全的随机数,而是伪随机数,我们需要改变他的种子,才能真正的生成随机数;
2.这就需要用到我们的srand()函数了
它一般用于初始化随机数生成器,通常是为rand函数设置种子,以便生成不同的随机数序列。所以我们在每次调用rand函数之前应先调用srand函数,以传入不同的种子。而srand函数通过参数seed来设置它的随机生成数,也就是说我们需要种子的种子不是一个固定值,只有这样,rand函数生成的数才是真正的随机数。
3、这就用到了time()函数了
因为时间一直在变化,所以我们可以用时间来当作srand函数的种子,它需要包含time.h的头文件。
所以我们在主函数里设计了srand函数
但随机数的范围是没法确定的,所以我们需要固定一个范围
用x表示行用y表示列,如果棋盘长度为9,rand()%9就是0-8,+1就是0-9,同理列也是这样
之后我们设置雷的数量, 设为count=EASY_COUNT,在game.h上也定义常量EASY_COUNT 10;
在利用while循环条件设置为count,布置一个雷count--;在循环中,利用if语句将随机生成的下标位置如果不等与'1',就设置为'1'
//布置雷
void SetMine(char board[ROWS][COLS], int row, int col)
{int count = EASY_COUNT;while (count){//生成随机下标//x:1-9//y:1-9int x = rand() % row + 1;int y = rand() % col + 1;if (board[x][y] != '1');{board[x][y] = '1';count--;}}
}
5、雷的排查
排查雷需要利用循环,那么判断循环结束的条件是什么呢?
把除10个雷之外的所有非雷都找出来,排雷成功,游戏结束
如果位置是雷,就炸死游戏结束
所以条件就是找到不是雷的所有坐标既
设置win为不是雷的坐标数
row*col:全部坐标数
EASY_COUNT:雷数
win<row*col-EASY_COUNT
我们需要规定输入坐标的范围,如果判断的坐标值为'1',游戏结束,并打印所有雷;如果不是,win++,并返回周围雷数,由于返回的值应该是字符 ,所以要让返回值+'0';并打印所有雷。
如果排查雷数等于win=row*col-EASY_COUNT 就是排查成功,并打印所有雷。
//排查雷
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{win++;printf("还要排查%d个位置\n", row * col - EASY_COUNT - win);int c = GetMineCount(mine, x, y);show[x][y] = c + '0';DisplayBoard(show, ROW, COL);}}else{printf("输入坐标有误,请重新输入\n");}}if (win == row * col - EASY_COUNT){printf("恭喜你,排雷成功\n");DisplayBoard(mine, ROW, COL);}}
6、返回周围雷数
//返回周围雷数
int GetMineCount(char mine[ROWS][COLS], int x, int y)
{return mine[x - 1][y - 1] + mine[x - 1][y] + mine[x - 1][y + 1] + mine[x][y - 1] + mine[x][y + 1] + mine[x + 1][y - 1] + mine[x + 1][y] + mine[x + 1][y + 1]-8*'0';
}
因为雷的字符为1,非雷为0;所以将周围坐标相加就是雷数,再减去8*'0',就是雷的个数.
三、完整代码
game.h
#pragma once
#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+2void InitBoard(char board[ROWS][COLS],int row, int col, int 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);
test.c
#include"game.h"void menu()
{printf("****************\n");printf("**** 1.play ****\n");printf("**** 0.exit ****\n");printf("****************\n");
}void game()
{//建立数组char mine[ROWS][COLS] = { 0 };//用来存放布置好的雷的信息char show[ROWS][COLS] = { 0 };//用来存放排查出的雷的信息//初始化InitBoard(mine, ROWS, COLS, '0');InitBoard(show, ROWS, COLS, '*');//打印棋盘//DisplayBoard(mine, ROW, COL);DisplayBoard(show, ROW, COL);//布置雷SetMine(mine, ROW, COL);//排查雷FindMine(mine,show, ROW, COL);}int main()
{int input = 0;srand((unsigned int)time(NULL));do {menu();printf("请输入选项:");scanf("%d", &input);switch (input){case 1:printf("开始游戏\n");game();break;case 0:printf("游戏结束\n");break;default:printf("选择错误,请重新选择:\n");break;}} while (input);return 0;
}
game.c
#include"game.h"//棋盘的初始化
void InitBoard(char board[ROWS][COLS], int row, int col, char set)
{for (int i = 1; i < row; i++){for (int j = 1; j < col; j++){board[i][j] = set;}}
}//棋盘的打印
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{int i = 0;int j = 0;printf("-----------扫雷-------------\n");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");}printf("-----------扫雷-------------\n");
}//布置雷
void SetMine(char board[ROWS][COLS], int row, int col)
{int count = EASY_COUNT;while (count){//生成随机下标//x:1-9//y:1-9int x = rand() % row + 1;int y = rand() % col + 1;if (board[x][y] != '1');{board[x][y] = '1';count--;}}
}//返回周围雷数
int GetMineCount(char mine[ROWS][COLS], int x, int y)
{return mine[x - 1][y - 1] + mine[x - 1][y] + mine[x - 1][y + 1] + mine[x][y - 1] + mine[x][y + 1] + mine[x + 1][y - 1] + mine[x + 1][y] + 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{win++;printf("还要排查%d个位置\n", row * col - EASY_COUNT - win);int c = GetMineCount(mine, x, y);show[x][y] = c + '0';DisplayBoard(show, ROW, COL);}}else{printf("输入坐标有误,请重新输入\n");}}if (win == row * col - EASY_COUNT){printf("恭喜你,排雷成功\n");DisplayBoard(mine, ROW, COL);}}
相关文章:

C语言:扫雷游戏实现
一、扫雷游戏的分析和设计 扫雷游戏想必大家都玩过吧,初级的玩法是在一个9*9的棋盘上找到没有雷的格子,而今天我们就要做的就是9*9扫雷游戏的实现。 1、游戏功能和规则 使用控制台实现经典的扫雷游戏游戏可以通过菜单实现继续玩或者退出游戏扫雷的棋盘…...

算法入门:Java实现排序、查找算法
链接:算法入门:Java实现排序、查找算法 (qq.com) 冒泡/选择/插入/希尔排序代码 (qq.com) 快排/归并/堆排/基数排序代码 (qq.com)...

【初阶数据结构篇】顺序表的实现(赋源码)
文章目录 本篇代码位置顺序表和链表1.线性表2.顺序表2.1 概念与结构2.2分类2.2.1 静态顺序表2.2.2 动态顺序表 2.3 动态顺序表的实现2.3.1动态顺序表的初始化和销毁及打印2.3.2动态顺序表的插入动态顺序表的尾插动态顺序表的头插动态顺序表的在指定位置插入数据 2.3.3动态顺序表…...

移动式气象站:便携科技的天气守望者
在科技日新月异的今天,我们身边的许多设备都在向着更加智能化、便携化的方向发展。而在气象观测领域,移动式气象站的出现,不仅改变了传统气象观测的固有模式,更以其灵活性和实时性,在气象监测、灾害预警等领域发挥着越…...

软件测试必备 - 14个接口与自动化测试练习网站
随着互联网和移动应用的快速发展,接口和自动化测试的重要性日益凸显。越来越多的企业开始重视API测试,因为它不仅能提升开发效率,还能确保系统的稳定性和安全性。这些练习网站为测试人员提供了宝贵的资源,帮助他们掌握必要的技能,应对日益复杂的测试需求。 在软件测试的世…...

基于 HTML+ECharts 实现的数据可视化大屏案例(含源码)
数据可视化大屏案例:基于 HTML 和 ECharts 的实现 数据可视化已成为企业决策和业务分析的重要工具。通过直观、动态的图表展示,数据可视化大屏能够帮助用户快速理解复杂的数据关系,发现潜在的业务趋势。本文将介绍如何利用 HTML 和 ECharts 实…...

vardaccico前端私有库
vardacico docker pull verdaccio/verdaccio:4 docker run -it --rm --name verdaccio -p 4873:4873 verdaccio/verdaccio Docker | Verdaccio 拷贝docker中的配置到宿主机 进入docker内部 docker exec -it verdaccio /bin/sh 进入到指定目录 cd /verdaccio 开始拷贝到指定目…...

先用先发!小样本故障诊断新思路!Transformer-SVM组合模型多特征分类预测/故障诊断(Matlab)
先用先发!小样本故障诊断新思路!Transformer-SVM组合模型多特征分类预测/故障诊断(Matlab) 目录 先用先发!小样本故障诊断新思路!Transformer-SVM组合模型多特征分类预测/故障诊断(Matlab&#…...

学习大数据DAY26 简单数据清洗练习和 Shell 脚本中的数据库编程
目录 上机练习 14 mysql 命令 sql 语句实现步骤 shell 脚本导入 csv 格式文件到 mysql 数据库 secure-file-priv 特性 把文件拷贝到 mysql 指定目录下 上机练习 15 mysqldump 命令 上机练习 16 上机练习 14 运用上一节课学的 Shell 工具完成 1. 清洗数据《infotest.t…...

开发业务(3)——swoole和聊天室入门开发
在普通的PHP代码里面,我们不需要考虑性能和异步问题,包括不限于我们想要使用php搭建一个http服务器(在node/python/go里面都有http模块,但是PHP没有这种功能)。而同样的原因,很难实现php游戏的开发…...

Linux系统服务——【web,http协议,apache服务和nginx服务】(sixteen day)
一、web基础以及http协议 1、web基本概念和常识 前端开发一般用uniapp. 1、Web:为用户提供的一种在互联网上浏览信息的服务,Web 服务是动态的、可交互的、跨平台的和图形化的。 2、Web 服务为用户提供各种互联网服务,这些服务包括信息浏览服务…...

100、Python 关于时间日期的一些操作
在Python中,我们用于处理时间和日期相关的类型最常用的模块是datetime模块。该模块提供了很多与时间日期相关的类,对我们处理时间日期变得很方便。 以下是一些常见的关于时间日期的操作。 一、datetime类 1、获取当前日期和时间(年、月、日…...

【精通Redis】Redis命令详解
引言 Redis是一个内存数据库,在学习它的内部原理与实现之前,我们首先要做到的就是学会使用,学会其丰富的命令操作。 一、字符串 Redis的字符串类型之前笔者的一篇入门介绍中曾经说过,不是简单的只存人可以阅读的字符串…...

项目经理的开源工具指南:优化您的选择过程
国内外主流的10款开源项目管理系统对比:PingCode、Worktile、禅道、Teambition、Gogs、码云 Gitee、Jira、Redmine、ProjectLibre、OpenProject。 在选择合适的开源项目管理系统时,很多团队面临诸多挑战:功能是否全面?易用性如何&…...

如何防御IP劫持
摘要 IP劫持是一种网络攻击方式,攻击者通过各种手段获取对某个IP地址的控制权,并将其用于恶意目的。这种攻击可能会导致数据泄露、服务中断等严重后果。本文将介绍IP劫持的基本概念、攻击方式以及防御策略,并提供一些实际的代码示例。 IP劫…...

C++绝对值
在C中,你可以使用标准库中的abs函数来获取一个整数的绝对值。对于浮点数,也有一个类似的函数叫做fabs。下面是如何使用这些函数的示例: 对于整数 对于整数,你可以使用std::abs函数,它存在于<cstdlib>头文件中。…...

C# dataGridView 去掉左边多出来空列
1.问题 在使用winform做界面程序时,dataGridView控件创建好后,左侧会多出一列为空,如何删除呢 2.解决方法 你可以在属性窗口中进行设置 如图: 将RowHeadersVisible 属性设置为False 或者代码设置 this.dataGridView1.RowHea…...

esp32
买了单片机模块,学8266...

IDEA 本地有jar包依赖文件,但是所有引用的jar包全部爆红
前端时间 看源码,下载源码额按钮不见了,折腾了很久,遂打算重新安装idea,但是重新安装后,发现代码全都爆红,按照晚上说的删除idea 文件夹,idea缓存删除,都不好使,但是看到…...

如何在调整节拍时间的过程中保持生产流程的稳定性?
在快节奏的工业生产领域,节拍时间(Takt Time)——即完成一个完整产品所需的标准时间,是维持生产效率和流程稳定性的关键指标。然而,市场需求的波动、技术升级或是生产线的微调,都可能要求我们对节拍时间进行…...

3. Docker的数据管理与持久化
在Docker容器化应用中,数据的持久化和管理是一个关键问题。容器的生命周期短暂,容器的停止和删除会导致数据丢失。因此,了解Docker的数据卷(Volumes)和挂载(Mounts)的管理方式,对保障…...

Logback原理及应用详解(九)
本系列文章简介: 在软件开发的过程中,日志记录是一项至关重要的功能。它不仅帮助开发者在开发阶段追踪代码的执行流程和调试问题,还在生产环境中扮演着监控应用运行状态、记录关键业务信息和排查故障的重要角色。随着软件系统的日益复杂和分布…...

SpringBoot 禁用RabbitMQ自启动
1.背景 在实际开发中,项目中使用了mq,但是在测试的时候用不到mq,或者测试环境的mq挂了, 希望能正常启动项目 2.步骤 这很简单在配置文件中增加一个配置就可以了 spring:autoconfigure:exclude: org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration 表示启…...

unity 实现图片的放大与缩小(根据鼠标位置拉伸放缩)
1创建UnityHelper.cs using UnityEngine.Events; using UnityEngine.EventSystems;public class UnityHelper {/// <summary>/// 简化向EventTrigger组件添加事件的操作。/// </summary>/// <param name"_eventTrigger">要添加事件监听的UI元素上…...

Scrapy 爬取旅游景点相关数据(五)
本期内容:(1)爬取日本其他城市数据存入数据库(2)爬取景点评论数据 1 爬取其他城市景点数据 只爬取一个城市的数据对于做数据可视化系统可能是不够的,因为数据样本量少嘛,本期来爬取其他城市的景…...

程序员纯粹八股文的危害有哪些,应该如何来解决?
“八股文”这个词在程序员面试的上下文中通常指的是那些被广泛讨论、反复练习的问题和答案,它们往往围绕着一些经典的技术知识点,例如算法、数据结构、设计模式等。这些知识在面试中被频繁提及,以至于应聘者经常会提前准备并背诵这些答案&…...

LabVIEW操作系列1
系列文章目录 我的记录: LabVIEW操作系列 文章目录 系列文章目录前言五、特殊用法5.1 取值范围表示5.2 对输入值取值范围进行限定5.3 控制多个While循环停止运行。5.4 获取按钮上的文本5.5 获取按钮上的文本【进阶】 六、使用步骤1.引入库2.读入数据 七、其余功能7.…...

【前端 09】JavaScript中的对象与JSON
JavaScript中的对象与JSON 在JavaScript中,对象和JSON(JavaScript Object Notation)是两个紧密相连但又有区别的概念。它们都在数据处理和交换中扮演着重要角色。本文将详细讲解JavaScript中的自定义对象以及JSON对象的基本概念、格式、用法…...

C# 字符串罗马数字123转汉字一二三
要将字符串 "123" 转换为 "一二三",可以通过以下几种方法来实现。 1. 使用映射字典 可以创建一个映射字典,将数字字符映射到对应的中文数字,然后遍历原始字符串进行替换: using System; using System.Coll…...

红杉资本视角:大公司在AI领域的投资策略与市场影响
在人工智能(AI)的快速发展浪潮中,大型科技公司如谷歌、Meta等正在积极投资,以确保在未来技术竞争中占据有利地位。红杉资本等投资机构对此现象进行了深入分析,探讨了大公司在AI领域的投资策略及其对市场的影响。本文将…...