C语言(扫雷游戏)

                     Hi~!这里是奋斗的小羊,很荣幸各位能阅读我的文章,诚请评论指点,关注+收藏,欢迎欢迎~~     

                        💥个人主页:小羊在奋斗

                        💥所属专栏:C语言   

        本系列文章为个人学习笔记,在这里撰写成文一为巩固知识,二为同样是初学者的学友展示一些我的学习过程及心得。文笔、排版拙劣,望见谅。

                                一、扫雷游戏

                                                1、扫雷游戏规则

                                                2、扫雷游戏的实现

                                                3、

一、扫雷游戏

1、扫雷游戏的规则

        首先我们来介绍一下扫雷游戏的玩法,扫雷游戏的常规界面(9*9)如下:

         上面游戏板上有许多个格子,有些格子里面埋有雷,玩家需要点击格子揭开它们,如果揭开的格子里是雷则被炸死游戏结束,若果揭开的格子不是雷则显示点开的格子周围有多少个雷,玩家需要通过给出的信息进行逻辑判断和猜测来排除所有的雷。

2、扫雷游戏的实现

        2.1打印游戏界面

        了解完游戏的玩法后,我们就要来好好想想要怎么通过代码来实现这个小游戏。

        首先,我们需要新建一个 main.c 文件来存放函数的主体代码,新建一个 game.c 文件用来游戏实现代码,新建一个 game.h 来包含其中会用到的一些头文件和相关函数的声明。

        跟其他游戏一样,我们得有个游戏菜单吧,在 —> 猜数字小游戏 这篇文章中我们已经有了一种打印游戏菜单的方法,不妨我们就继续延用这种办法吧。

main.c 

#define  _CRT_SECURE_NO_WARNINGS#include "game.h"//这里我将头文件<stdio.h>包含到game.h,再在main.c和//game.c文件中包含game.h,避免重复引用void menu()
{printf("##########################\n");printf("########  1.play  ########\n");printf("########  0.exit  ########\n");printf("##########################\n");
}int main()
{int input = 0;do{menu();printf("请选择:");scanf("%d", &input);switch (input)//通过输入的input来选择开始游戏还是退出游戏{case 1:printf("开始游戏!\n");break;case 0:printf("退出游戏!");break;default:  //如果不小心输入错误的值,还要提示重新选择printf("选择错误,请重新选择!\n");break;}} while (input);//do—while循环可以帮助我们实现重复玩游戏return 0;
}

        代码运行先打印一个简易的游戏菜单,提示我们选择1开始游戏,选择0退出游戏,选择其他值则提示选择错误,重新选择。当我们选择1开始游戏,游戏结束后通过 break 跳出来到 while 判断,input 的值为1继续循环开始游戏;当我们选择0则退出游戏,通过 break 跳出来到 while 判断,input 的值为0退出循环;当我们选择其他非0的值通过 break 跳出来到 while 判断,非0继续循环。

        通过代码执行可以试验出我们当前的逻辑是正确的。我们在写工程量比较大的代码时,写完一段程序最好运行试验一下是否符合我们的想法。

 

        2.2游戏分析

        接下来我们就要分析一下该如何实现这个游戏了。首先我们得有一个矩形棋盘吧,这里我们就先设计一个简单的 9*9 游戏棋盘。提到矩形 9*9 棋盘我们就很容易联想到之前学习过的二维数组,二维数组就能很好的帮我们实现这个事情,并且二维数组还能通过坐标唯一确定一个小格子。有了游戏棋盘在玩游戏之前还应该由系统自动布置好雷的位置,并且位置是随机的,影藏在棋盘下我们看不到。

        我们设计的这个棋盘不仅要事先随机布置隐藏好雷,还要在我们玩的时候显示周围雷的个数,是不是对这个棋盘要求太高了,我们实现起来也比较复杂。这里我们有一个还不错的解决办法,我们可以定义两个二维数组,一个用来随机产生并且隐藏雷,在我们玩游戏的时候并不打印;另一个在我们玩的时候打印显示排雷的信息也就是周围雷的个数。

        提到定义两个二维数组就不得不想清楚我们究竟要定义两个什么类型的二维数组呢?在这之前,我们需要考虑一下怎么区分雷和非雷。其实这一步有很多种方法,想要怎么设计完全由你自己决定,这里我们不妨就定义字符 ‘0’ 为雷,字符 ‘1’ 为非雷吧,至于为什么要定义为字符而不是我们常见的数字1和0,其实是有原因的。

        我们前面说过,如果揭开的格子下不是雷,就要将这个格子周围的雷的数目加起来并在我们揭开的这个格子上显示,要显示的话当然显示的是数字,如果这个格子周围恰好是一个雷就要在这个格子上显示数字1,这就非常容易与我们定义的雷(0)或非雷(1)冲突,我们定义为字符的话就可以很好的避免这个问题。

 

         还有一个隐藏的问题,如果我们想排查(8,7)这个坐标,很明显越界了,那我们要判断这个坐标是不是雷之前还要先判断数组是否越界,因为数组越界是比较危险的事情,谁也不知道越界访问到的是什么数据,严重还会导致程序崩溃,所以我们要想办法避免这个问题。

        我们可以把之前定义的两个字符型二维数组大小改为 11 行 11 列,而不是用 9 行 9 列,在操作的时候外面一圈不操作,只在 9*9 的棋盘内排雷,这样就不会有越界的问题。

        2.3打印游戏棋盘

       接上所述,我们定义了两个 11 行 11 列的字符型二维数组,定义好后我们先将埋雷的二维数组初始化为 ‘1’,将显示排雷信息的二维数组初始化为 * ,因为埋雷的二维数组并不打印,所以我们就实现了用一个棋盘覆盖另一个棋盘的效果。

        到这里我们先来看一下效果:

         测试效果跟我们预期的一样,当然,在真正玩的时候上面埋雷的棋盘是不打印的,这里我们只是测试一下棋盘是否初始化成功。

        相关代码如下:

        main.c 

#define  _CRT_SECURE_NO_WARNINGS#include "game.h"//这里我将头文件<stdio.h>包含到game.h,再在main.c和//game.c文件中包含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 };//存放排雷的信息//初始化二维数组Init_Board(mine, ROWS, COLS, '1');Init_Board(show, ROWS, COLS, '*');//打印棋盘Display_Board(mine, ROW, COL);Display_Board(show, ROW, COL);}int main()
{int input = 0;do{menu();printf("请选择:");scanf("%d", &input);switch (input)//通过输入的input来选择开始游戏还是退出游戏{case 1:game();break;case 0:printf("退出游戏!");break;default:  //如果不小心输入错误的值,还要提示重新选择printf("选择错误,请重新选择!\n");break;}} while (input);//do—while循环可以帮助我们实现重复玩游戏return 0;
}

         game.c

#define  _CRT_SECURE_NO_WARNINGS#include "game.h"void Init_Board(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 Display_Board(char board[ROWS][COLS], int row, int col)
{int i = 0;printf("————————扫雷————————\n");for (i = 0; i <= row; 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");}
}

        game.h 

#pragma once#include <stdio.h>#define ROW 9  //定义二维数组的行和列方便修改大小
#define COL 9
#define ROWS ROW + 2
#define COLS COL + 2//初始化两个二维数组
void Init_board(char board[ROWS][COLS], int rows, int cols, char set);//打印棋盘
void Display_Board(char board[ROWS][COLS], int row, int col);

        注意: 虽然我们有些函数操作的是 ROW 和 COL , 但我们函数传参的时候传的还是 ROWS 和 COLS , 因此我们形参接收的时候一定要用 ROWS 和 COLS 接收。

        2.4埋雷

        我们之前确定了定义 ‘0’ 为雷,下面我们就来探讨如何埋雷。

        首先,我们需要确定埋多少个雷,可以定义一个符号常量来选择埋多少个雷,这里就先埋10个雷。其次,埋雷的话肯定是要随机的埋10个雷,那就要产生10个随机的坐标,产生随机数的函数我们在之前的猜数字小游戏中已经使用过,这里就不过多介绍了。(猜数字小游戏

        我们在埋雷的过程中还需要判断这个坐标是否已经埋了雷,这个不难实现,只需要加一个 if 语句即可。我们来看代码实现:

        main.c

#define  _CRT_SECURE_NO_WARNINGS#include "game.h"//这里我将头文件<stdio.h>包含到game.h,再在main.c和//game.c文件中包含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 };//存放排雷的信息//初始化二维数组Init_Board(mine, ROWS, COLS, '1');Init_Board(show, ROWS, COLS, '*');//打印棋盘//Display_Board(mine, ROW, COL);Display_Board(show, ROW, COL);//埋雷Set_Mine(mine, ROW, COL);Display_Board(mine, ROW, COL);//打印看一下埋雷是否成功}int main()
{int input = 0;srand((unsigned int)time(NULL));//调用rand函数之前先要调用srand函数do{menu();printf("请选择:");scanf("%d", &input);switch (input)//通过输入的input来选择开始游戏还是退出游戏{case 1:game();break;case 0:printf("退出游戏!");break;default:  //如果不小心输入错误的值,还要提示重新选择printf("选择错误,请重新选择!\n");break;}} while (input);//do—while循环可以帮助我们实现重复玩游戏return 0;
}

        game.c 

#define  _CRT_SECURE_NO_WARNINGS#include "game.h"void Init_Board(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 Display_Board(char board[ROWS][COLS], int row, int col)
{int i = 0;printf("————————扫雷————————\n");for (i = 0; i <= row; 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 Set_Mine(char mine[ROWS][COLS], int row, int col)
{int x = 0;int y = 0;int count = 0;while (count < EASY_COUNT){x = rand() % row + 1;//产生范围为1-9的随机数y = rand() % col + 1;if (mine[x][y] != '0'){mine[x][y] = '0';count++;}}
}

        game.h 

#pragma once#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 Init_board(char board[ROWS][COLS], int rows, int cols, char set);//打印棋盘
void Display_Board(char board[ROWS][COLS], int row, int col);//埋雷
void Set_Mine(char mine[ROWS][COLS], int row, int col);

        运行结果为: 

 

         可以看到,我们已经实现了埋10个雷。

        2.5扫雷

        接下来就到了最后一步,实现扫雷。

        我们需要输入一个坐标,判断此坐标下是否埋着雷,如果是雷则打印 “你踩雷了,游戏失败!”,并且打印出所有雷的位置;如果不是雷则需要在这个坐标处显示周围8个坐标内雷的个数,继续输入坐标扫雷。

        怎么获得排查过的坐标周围雷的个数呢?我们不难发现,(x,y)周围8个坐标分别可以表示为x或y加-1、0、1得到的9个坐标,然后把这9个坐标的值分别进去字符 ‘0’,使其转换为整型再加起来,经过处理就能得到雷的个数。

        最终的代码为:

        main.c

#define  _CRT_SECURE_NO_WARNINGS#include "game.h"//这里我将头文件<stdio.h>包含到game.h,再在main.c和//game.c文件中包含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 };//存放排雷的信息//初始化二维数组Init_Board(mine, ROWS, COLS, '1');Init_Board(show, ROWS, COLS, '*');//打印棋盘//Display_Board(mine, ROW, COL);Display_Board(show, ROW, COL);//埋雷Set_Mine(mine, ROW, COL);//Display_Board(mine, ROW, COL);//打印看一下埋雷是否成功//扫雷Find_Mine(mine, show, ROW, COL);
}int main()
{int input = 0;srand((unsigned int)time(NULL));//调用rand函数之前先要调用srand函数do{menu();printf("请选择:");scanf("%d", &input);switch (input)//通过输入的input来选择开始游戏还是退出游戏{case 1:game();break;case 0:printf("退出游戏!");break;default:  //如果不小心输入错误的值,还要提示重新选择printf("选择错误,请重新选择!\n");break;}} while (input);//do—while循环可以帮助我们实现重复玩游戏return 0;
}

        game.c

#define  _CRT_SECURE_NO_WARNINGS#include "game.h"void Init_Board(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 Display_Board(char board[ROWS][COLS], int row, int col)
{int i = 0;printf("————————扫雷————————\n");for (i = 0; i <= row; 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 Set_Mine(char mine[ROWS][COLS], int row, int col)
{int x = 0;int y = 0;int count = 0;while (count < EASY_COUNT){x = rand() % row + 1;//产生范围为1-9的随机数y = rand() % col + 1;if (mine[x][y] != '0'){mine[x][y] = '0';count++;}}
}int Get_Mine_Count(char mine[ROWS][COLS], int x, int y)
{int i = 0;int count = 0;for (i = -1; i <= 1; i++){int j = 0;for (j = -1; j <= 1; j++){count += (mine[x + i][y + j] - '0');}}return (9 - count);
}void Find_Mine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{int x = 0;int y = 0;int count = 0;while (count < (row * col - EASY_COUNT))//排查出所有的非雷坐标后退出循环{printf("请输入想要排查的坐标:");scanf("%d %d", &x, &y);if (x >= 1 && x <= row && y >= 1 && y <= col)//必须输入范围内的坐标{if (mine[x][y] == '0'){printf("你踩雷了,游戏结束!\n");Display_Board(mine, ROW, COL);printf("\n\n\n");break;}else{int count = Get_Mine_Count(mine, x, y);show[x][y] = count + '0';//整型count需要加上字符‘0’才能赋值给字符型数组showDisplay_Board(show, ROW, COL);}}else{printf("输入的坐标有误,x和y的范围为1-%d\n", row);}}if (count == EASY_COUNT){printf("恭喜你,扫雷成功!\n");Display_Board(mine, ROW, COL);}
}

        game.h 

#pragma once#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 Init_board(char board[ROWS][COLS], int rows, int cols, char set);//打印棋盘
void Display_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);

            至此,我们就完成了整个游戏的实现。

                                    点击跳转主页—> 💥个人主页小羊在奋斗

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

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

相关文章

webgl canvas系列——animation中基本旋转、平移、缩放(模拟冒泡排序过程)

文章目录 ⭐前言⭐canvas绘制图片&#x1f496;状态保存和恢复&#x1f496;移动、旋转、缩放、变形&#x1f496;移动绘制一个渐变的box&#x1f496;旋转&#x1f496;缩放 ⭐模拟冒泡排序过程⭐结束 ⭐前言 大家好&#xff0c;我是yma16&#xff0c;本文分享webgl canvas系…

JAVA学习笔记25(面向对象编程(高级))

1.4 final关键字 ​ *final可以修饰类、属性、方法和局部变量 1.可能会用到final关键字 1.当不希望类被继承时&#xff0c;可以用final修饰 final class A{ }2.当不希望父类的某个方法被子类覆盖/重写(override)时&#xff0c;可以用final关键字修饰 【访问修饰符 final 返…

GB4806.11食品接触用天然橡胶餐具检测标准解读

GB 4806.11-2023是食品安家标准&#xff0c;针对食品接触用橡胶材料及制品进行了详细规定。该标准于2023年发布&#xff0c;旨在确保食品接触用橡胶材料及制品的安全性和卫生性&#xff0c;以保障消费者的健康。 与之前的版本相比&#xff0c;GB 4806.11-2023主要进行了以下修…

企业常用Linux正则表达式与三剑客/企业生产环境及知识/企业中远程连接ssh工具(为什么连接有时慢?)

企业高薪思维: 1.学习去抓重点有价值知识 2.猛劲学&#xff0c;使劲学&#xff08;能否给别人将会&#xff0c;讲明白&#xff0c;写明白&#xff0c;练习明白&#xff09;&#xff0c;在学习过程中你觉得学会了60-80%&#xff0c;其实你只会了40-50%&#xff0c;你要讲明白会操…

构建云原生湖仓:Apache Iceberg与Amoro的结合实践

随着大数据技术的快速发展&#xff0c;企业对数据的处理和分析需求日益增长。传统的数据仓库已逐渐无法满足现代业务对数据多样性和实时性的要求&#xff0c;这促使了数据湖和数据仓库的融合&#xff0c;即湖仓一体架构的诞生。在云原生技术的推动下&#xff0c;构建云原生湖仓…

AWD线下攻防万字最完整战术(记第一届“长城杯”半决赛战术)

目录 准备阶段 1.登录比赛平台&#xff08;获取资产&#xff09; 查看账号账号修改 服务器SSH口令mysqlWEB服务口令(后台密码)数据库后台管理员密码 账号用户检查 2.dump源码&#xff08;方便应急响应恢复靶机&#xff09; 网站源码备份 压缩文件解压文件备份到服务器本地上传…

【原创】springboot+mysql疫苗预约管理系统设计与实现

个人主页&#xff1a;程序猿小小杨 个人简介&#xff1a;从事开发多年&#xff0c;Java、Php、Python、前端开发均有涉猎 博客内容&#xff1a;Java项目实战、项目演示、技术分享 文末有作者名片&#xff0c;希望和大家一起共同进步&#xff0c;你只管努力&#xff0c;剩下的交…

Linux部署Coturn以及关于打洞的思考

目录 Coturn介绍部署架构图 2.1 局域网——无NAT映射 2.2 NAT网Corturn安装步骤验证 4.1 局域网——无NAT映射 4.2 NAT网 4.2.1 Cywin安装步骤 4.2.2 Coturn安装步骤 4.2.3 验证引言 下文部署架构图为Corturn为解决互联网NAT环境下“找朋友”的部署架构,也是Coturn发挥其价值…

玩转 AIGC!使用 SD-WebUI 实现从文本到图像转换

节前&#xff0c;我们组织了一场算法岗技术&面试讨论会&#xff0c;邀请了一些互联网大厂朋友、参加社招和校招面试的同学&#xff0c;针对算法岗技术趋势、大模型落地项目经验分享、新手如何入门算法岗、该如何准备、面试常考点分享等热门话题进行了深入的讨论。 基于大家…

javaScript常用知识点

1. this指向问题 在绝大多数情况下&#xff0c;函数的调用方式决定了this的值。this不能在执行期间被赋值&#xff0c;并且在每次函数被调用时this的值也可能会不同。 this指向的对象称为函数的上下文对象context&#xff1b;this的指向取决于函数被调用方式this的指向不是函数…

HCIP-Datacom-ARST必选题库_22_SDWAN【1道题】

一、单选 1.SD-WAN解决方案适合如下哪个场景? 企业分支互联 企业数据中心网络内部互联 企业园区无线网络部署 略

【更新】cyのMemo(20240422~)

序言 胡哥首马在淮安325完赛&#xff0c;他的本硕都在淮安度过&#xff0c;七年的跑步生涯画上句号&#xff0c;真的是很圆满。七年&#xff0c;从180斤瘦到120斤&#xff0c;历经种种&#xff0c;胡哥理解的跑步&#xff0c;不是快&#xff0c;而是稳&#xff0c;他在比赛中从…

Python-08-程序跳转语句(break、continue)、空语句pass

目录 1、程序跳转语句 2、空语句pass 3、本章小结 1、程序跳转语句 程序跳转语句break用于跳&#xff08;退&#xff09;出循环结构&#xff0c;通常与if一起搭配使用 语法结构 while 表达式1: 执行代码 if 表达式2: break s0 #存储累加和 i1 #&#xff08;…

力扣HOT100 - 226. 翻转二叉树

解题思路&#xff1a; class Solution {public TreeNode invertTree(TreeNode root) {if (root null) return null;TreeNode left invertTree(root.left);TreeNode right invertTree(root.right);root.left right;root.right left;return root;} }

《ElementUI 基础知识》png 图片扩展 icon用法

前言 UI 设计给的切图是 .png 格式。但想与 Element UI icon 用法类似&#xff0c;方案如下。 实现 步骤一 准备图片 步骤二 新建文件&#xff0c;可使用 CSS 预处理语言 styl 或 scss。 stylus 方式 文件 icon.styl /* 定义一个混合 */ cfgIcon(w, h) {display: inlin…

json-cpp的下载与使用

1.json-cpp 的概要 JSON 是一种数据交换格式&#xff0c;常用于网络应用编程中的序列和反序列化。 JSON 的数据类型只有如下几种&#xff1a; 对象&#xff0c;使用 {} 包含数组&#xff0c;使用 [] 包含字符串&#xff0c;使用 "" 包含数字&#xff08;包含整数和…

如何判别三角形和求10 个整数中最大值?

分享每日小题&#xff0c;不断进步&#xff0c;今天的你也要加油哦&#xff01;接下来请看题------> 一、已知三条边a&#xff0c;b&#xff0c;c能否构成三角形&#xff0c;如果能构成三角形&#xff0c;判断三角形的类型&#xff08;等边三角形、等腰三角形或普通三角形 …

DAPP的商业模型创新: 探索可持续盈利路径

去中心化应用&#xff08;Decentralized Applications&#xff0c;DAPPs&#xff09;作为区块链技术的重要应用之一&#xff0c;在近年来蓬勃发展。然而&#xff0c;随着市场竞争的加剧和用户需求的不断变化&#xff0c;DAPP开发者们面临着寻找可持续盈利路径的挑战。本文将探讨…

注意libaudioProcess.so和libdevice.a是不一样的,一个是动态链接,一个是静态

libaudioProcess.so是动态链接&#xff0c;修改需要改根文件系统&#xff0c;需要bsp重新配置 libdevice.a是静态链接&#xff0c;直接替换就行 动态链接文件修改 然后执行fw_update.sh

VUE 插件收集

VsCode插件清单 中文插件 Chinese (Simplified) (简体中文) Language Pack for Visual Studio Code 代码提示 Vue 2 Snippets Vetur插件让vue文件代码高亮 Vue VSCode Snippets自动生成vue模板内容插件 LiveServer实时刷新网页 Bracket Pair Colorizer彩虹括号 Material …