(八)数组和函数实践:扫雷游戏

目录

1. 扫雷游戏分析和设计

1.1 扫雷游戏的功能说明

1.2 游戏的分析和设计

1.2.1 数据结构的分析 

1.2.2 文件结构设计

2. 扫雷游戏的代码实现

3. 如何生成用户版本

 4. 完整的排雷程序


1. 扫雷游戏分析和设计

1.1 扫雷游戏的功能说明

        1)使用控制台实现经典的扫雷游戏

        2)游戏可以通过菜单实现继续玩或者退出游戏

        3)扫雷的棋盘是9*9的格子

        4)默认随机布置10个雷

        5)可以排查雷

                如果位置不是雷,就显示周围几个雷

                如果位置是雷,就炸死游戏结束

                把除10个雷之外的所有非雷都找出来,排雷成功,游戏结束

预计的游戏界面:

1.2 游戏的分析和设计

1.2.1 数据结构的分析 

        扫雷的过程中,布置的雷和排查出的雷的信息都需要存储,所以我们需要⼀定的数据结构来存储这些信息。
        因为我们需要在 9*9 的棋盘上布置雷的信息排查雷,我们首先想到的就是创建⼀个 9*9 的数组来存放信息。

        那如果这个位置布置雷,我们就存放1,没有布置雷就存放0。

        假设我们排查 (2,5) 这个坐标时,我们访问周围的⼀圈 8 个⻩⾊位置,统计周围雷的个数是1
假设我们排查 (8,6) 这个坐标时,我们访问周围的⼀圈 8 个⻩⾊位置,统计周围雷的个数时,最下⾯的三个坐标就会越界,为了防止越界,我们在设计的时候,给数组扩⼤⼀圈,雷还是布置在中间的  9*9 的坐标上,周围⼀圈不去布置雷就⾏,这样就解决了越界的问题。所以我们将存放数据的数组创建成11*11是⽐较合适。 

        再继续分析,我们在棋盘上布置了雷,棋盘上雷的信息(1)和非雷的信息(0),假设我们排查了某⼀个位置后,这个坐标处不是雷,这个坐标的周围有 1 个雷,那我们需要将排查出的雷的数量信息记录存储,并打印出来,作为排雷的重要参考信息的。那这个雷的个数信息存放在哪呢?如果存放在布置雷的数组中,这样雷的信息和雷的个数信息就可能或产⽣混淆和打印上的困难。


        这⾥我们肯定有办法解决,⽐如:雷和非雷的信息不要使⽤数字,使⽤某些字符就⾏,这样就避免冲突了,但是这样做棋盘上有雷和非雷的信息,还有排查出的雷的个数信息,就⽐较混杂,不够⽅便。

        这⾥我们采⽤另外⼀种⽅案,我们专⻔给⼀个棋盘(对应⼀个数组mine)存放布置好的雷的信息,再给另外⼀个棋盘(对应另外⼀个数组show)存放排查出的雷的信息。这样就互不⼲扰了,把雷布置到mine数组,在mine数组中排查雷,排查出的数据存放在show数组,并且打印show数组的信息给后期排查参考。

        同时为了保持神秘,show数组开始时初始化为字符 '*',为了保持两个数组的类型⼀致,可以使⽤同⼀套函数处理,mine数组最开始也初始化为字符'0',布置雷改成字符'1'。如下如:

对应的数组应该是: 

char mine[11][11] = { 0 };//存放布置好的雷的信息,数组全部初始化为 '0'
//char mine[11][11] = {'0'};这只是初始化一个元素为字符0
char show[11][11] = { 0 };//存放排查出雷的信息,数组全部初始化为 '*'

1.2.2 文件结构设计

test.c //⽂件中写游戏的测试逻辑 
game.c //⽂件中写游戏中函数的实现等
game.h //⽂件中写游戏需要的数据类型和函数声明等

2. 扫雷游戏的代码实现

1)首先创建在 VS 中好三个文件 test.c  game.c  game.h

2)每个工程有且仅有一个 main 函数,敲写 main 函数,并且实现第一个功能:游戏可以通过菜单实现继续玩或者退出游戏

test.c

int main()
{test();return 0;
}

        main 函数中可以调用函数,简洁明了;可以在 test 函数中实现大的框架功能,打印菜单提示信息,进行手动输入选择进入游戏,还是退出游戏;进入游戏,游戏的执行,可以再写另外一个函数来实现此功能。总结:在实现一个大的功能时,先把整体框架定好,再去完成一个个的细节,比如,进行游戏的功能,先把它确定好,再去实现编写这个功能的函数。

test.c

void test()
{int input = 0;//对调用随机函数的种子进行设定srand((unsigned int)time(NULL));do{menu();//打印菜单,提示信息    printf("请选择:>");scanf("%d", &input);switch(input){case 1:game();break;case 0:printf("游戏结束,退出游戏\n");break;  default:printf("选择错误,重新选择\n");break;}}while(input);
}

test.c

打印提示信息的菜单函数

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

test.c

实现扫雷游戏的函数

void game()
{//完成扫雷游戏char mine[ROWS][COLS] = { 0 };//存放布置好的雷的信息,数组全部初始化为 '0'//char mine[ROWS][COLS] = {'0'};这只是初始化一个元素为字符0char show[ROWS][COLS] = { 0 };//存放排查出雷的信息,数组全部初始化为 '*'//初始化棋盘InitBoard(mine, ROWS, COLS, '0');InitBoard(show, ROWS, COLS, '*');//布置雷 就是在9*9的棋盘上随机布置 10 个雷SetMine(mine, ROW, COL);/*DisplayBoard(mine, ROW, COL);*///打印棋盘/*DisplayBoard(mine, ROW, COL);*/DisplayBoard(show, ROW, COL);//排查雷FindMine(mine, show, ROW, COL);
}

对扫雷游戏 game() 函数进行分析:

        首先对存放布置好雷的信息的数组 mine 和 存放排查出雷的信息的数组 show,进行初始化:

char mine[ROWS][COLS] = { 0 };//存放布置好的雷的信息,数组全部初始化为 '0'
//char mine[ROWS][COLS] = {'0'};这只是初始化一个元素为字符0
char show[ROWS][COLS] = { 0 };//存放排查出雷的信息,数组全部初始化为 '*'

        然后对,棋盘进行初始化赋值,就是填充字符 ‘0’ 和 ‘*’ ,对 mine 数组赋值字符 ‘0’,对 show 数组赋值字符 '*',建立一个函数,传参进去,有数组,数组的大小,还有对每个元素赋什么值这样一个函数,其实说白了就是对二维数组进行赋值:

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

game.c

void InitBoard(char arr[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++){arr[i][j] = set;}}
}

        赋值结束后,想看下是否赋值的对不对,写个遍历二维数组的程序,进行打印,也是传入要遍历的数组,以及要遍历的数组的大小,只需要遍历我们需要显示的棋盘,不需要遍历棋盘我们故意做大一圈的棋盘,所以就是传入的是 row 和 col:

game.c

void DisplayBoard(char arr[ROWS][COLS], int row, int col)
{int i = 0;//打印列号printf("<-------扫雷游戏------->\n");for (i = 0; i <= col; i++){printf("%2d ", i);//%2d 输出两个宽度的整数,且默认是右对齐//printf("%-2d ", i);左对齐}printf("\n");for (i = 1; i <= row; i++){int j = 0;printf("%2d ", i);for (j = 1; j <= col; j++){printf("%2c ", arr[i][j]);}printf("\n");}
}

        初始化完成后,就是进行布雷,布雷肯定要用到随机值,在 ROW 行 COL 列里进行随机摆放字符 ‘1’ ,仍然是传入需要布雷的数组,以及数组的大小,在该大小的二维数组中,该函数中,通过宏定义的布雷个数赋值给局部变量 count ,然后通过 rand 函数 产生随机值,随机在数组的位置上进行赋值布雷; rand() % 9,模上一个9,余数是0-8;模上一个10,余数是0-9,布置雷后,想查看的话,可以再 调用 DisplayBoard(show, ROW, COL) 进行查看。

game.c

void SetMine(char arr[ROWS][COLS], int row, int col)
{int count = EASY_COUNT;//布雷的个数while (count){int x = rand() % row + 1;// rand() % 9,模上一个9,余数是0-8;模上一个10,余数是0-9;int y = rand() % col + 1;if (arr[x][y] == '0'){arr[x][y] = '1';count--;}}
}

布置好雷后,就可以进行排查雷,排查雷,需要传入 布置好雷的信息的数组,传入 排查出雷的信息的数组,以及需要排查的范围大小;首先进入排雷,可以先判断,你输入的坐标是否是雷,也就是判断数组中的元素是否是字符 ‘1’,如果是,则直接宣布你被炸死,并且跳出循环,如果不是,那就要统计该坐标周围有几个雷 ‘1’,统计完成后,把这个数值赋值给 排查出雷的信息的数组show,然后重新显示 排查出雷的信息的数组 show;

代码就是有时候需要从外到里写,比如定框架的时候,就是先写外边大的框架,再写细节处;而这里就是从里往外写,比如,判断完你输入的坐标是否是雷后,外层可以再次判断你输入的坐标是否已经被排查过了,在此之外,还可以判断你输入的坐标是否是有效的;还可以再循环上进行判断,你可以排查多少次,进行一个循环。

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 (show[x][y] == '*'){if (mine[x][y] == '1'){printf("很遗憾,你被炸死了\n");DisplayBoard(mine, ROW, COL);break;}else{//该坐标不是雷,就得统计坐标周围有几个雷int count = GetMineCount(mine, x, y);show[x][y] = count + '0';DisplayBoard(show, ROW, COL);win++;}}else{printf("该坐标已被排查过了,重新输入坐标\n");}}else{printf("坐标非法,请重新输入\n");}}if (win == row * col - EASY_COUNT){printf("恭喜你,排雷成功\n");DisplayBoard(show, ROW, COL);}
}

3. 如何生成用户版本

 这里点击,平时程序员用的是 Debug 版本:调试版本;

Release:用户使用版本,修改为 Release 后,编译以下,可以在该工程目录下的文件夹下,找到后缀 .exe 文件,可以把这个发给用户,用户双击就可以运行。

 4. 完整的排雷程序

test.c

#define _CRT_SECURE_NO_WARNINGS   1#include "game.h"void menu()
{printf("***********************\n");printf("*******1. play ********\n");printf("*******0. exit ********\n");printf("***********************\n");
}void game()
{//完成扫雷游戏char mine[ROWS][COLS] = { 0 };//存放布置好的雷的信息,数组全部初始化为 '0'//char mine[ROWS][COLS] = {'0'};这只是初始化一个元素为字符0char show[ROWS][COLS] = { 0 };//存放排查出雷的信息,数组全部初始化为 '*'//初始化棋盘InitBoard(mine, ROWS, COLS, '0');InitBoard(show, ROWS, COLS, '*');//布置雷 就是在9*9的棋盘上随机布置 10 个雷SetMine(mine, ROW, COL);/*DisplayBoard(mine, ROW, COL);*///打印棋盘/*DisplayBoard(mine, ROW, COL);*/DisplayBoard(show, ROW, COL);//排查雷FindMine(mine, show, ROW, COL);
}
void test()
{int input = 0;srand((unsigned int)time(NULL));do{menu();printf("请选择:>");scanf("%d", &input);//1 0 xswitch (input){case 1:game();break;case 0:printf("游戏结束,退出游戏\n");break;default:printf("选择错误,重新选择\n");break;}} while (input);
}int main()
{test();return 0;
}

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 InitBoard(char arr[ROWS][COLS], int rows, int cols, char set);// 打印棋盘
void DisplayBoard(char arr[ROWS][COLS], int row, int col);// 布置雷
void SetMine(char arr[ROWS][COLS], int row, int col);//排查雷
void FindMine(char arr[ROWS][COLS],char show[ROWS][COLS], int row, int col);

game.c

#define _CRT_SECURE_NO_WARNINGS   1
#include <stdio.h>
#include "game.h"void InitBoard(char arr[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++){arr[i][j] = set;}}
}void DisplayBoard(char arr[ROWS][COLS], int row, int col)
{int i = 0;//打印列号printf("<-------扫雷游戏------->\n");for (i = 0; i <= col; i++){printf("%2d ", i);//%2d 输出两个宽度的整数,且默认是右对齐//printf("%-2d ", i);左对齐}printf("\n");for (i = 1; i <= row; i++){int j = 0;printf("%2d ", i);for (j = 1; j <= col; j++){printf("%2c ", arr[i][j]);}printf("\n");}
}void SetMine(char arr[ROWS][COLS], int row, int col)
{int count = EASY_COUNT;//布雷的个数while (count){int x = rand() % row + 1;// rand() % 9,模上一个9,余数是0-8;模上一个10,余数是0-9;int y = rand() % col + 1;if (arr[x][y] == '0'){arr[x][y] = '1';count--;}}
}
//这个函数只是用来为 FindMine 函数做服务的,所有没必要把它暴露在头文件中,而且不想让别人看到可以放在这里,再加上static
static int GetMineCount(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 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 (show[x][y] == '*'){if (mine[x][y] == '1'){printf("很遗憾,你被炸死了\n");DisplayBoard(mine, ROW, COL);break;}else{//该坐标不是雷,就得统计坐标周围有几个雷int count = GetMineCount(mine, x, y);show[x][y] = count + '0';DisplayBoard(show, ROW, COL);win++;}}else{printf("该坐标已被排查过了,重新输入坐标\n");}}else{printf("坐标非法,请重新输入\n");}}if (win == row * col - EASY_COUNT){printf("恭喜你,排雷成功\n");DisplayBoard(show, ROW, COL);}
}

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

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

相关文章

数据结构和算法-栈

数据结构和算法-栈 文章目录 数据结构和算法-栈1. 栈的介绍2. 栈的应用场景3. 栈的快速入门3.1 用数组模拟栈3.2 课堂作业-用链表模拟栈 4. 栈实现综合计算器4.1 课堂作业-加入小括号5. 栈的三种表达式-**前缀、中缀、后缀表达式(逆波兰表达式)**5.1 前缀表达式(波兰表达式)5.1…

中低压MOS 适用于电子烟等产品—— 较小的开关损耗 过流能力好

工作原理&#xff1a; 当用户在吸嘴处抽吸时&#xff0c;气流经过进气孔&#xff0c;穿 过电路板上方的咪头&#xff0c;咪头即产生电信号&#xff0c;驱 动芯片板&#xff0c;让电池供电给雾化芯&#xff0c;雾化芯中的 发热丝将电能转化成热能&#xff0c;当温度达到雾化液…

LeetCode-2487. 从链表中移除节点【栈 递归 链表 单调栈】

LeetCode-2487. 从链表中移除节点【栈 递归 链表 单调栈】 题目描述&#xff1a;解题思路一&#xff1a;可以将链表转为数组&#xff0c;然后从后往前遍历&#xff0c;遇到大于等于当前元素的就入栈&#xff0c;最终栈里面的元素即是最终的答案。解题思路二&#xff1a;递归&am…

【一步到位】汽车过户全攻略:轻松搞定,告别繁琐流程

校长车行是一家昆明二手车代办公司&#xff0c;今天我们要聊一聊一个让很多人头疼的问题——汽车过户。相信很多朋友在购买二手车或者需要将车辆转让给他人时&#xff0c;都会遇到这个繁琐的流程。那么&#xff0c;如何才能轻松搞定汽车过户呢&#xff1f;接下来&#xff0c;就…

(0-1)分布

假设离散型随机变量X只可能取到0、1两个值&#xff0c;它的分布律为&#xff1a; &#xff0c;其中&#xff0c; 那么称X服从参数为p的0-1分布&#xff0c;也叫两点分布。 其实上面公式就是将下面两个式子写在一起&#xff1a;

【Hive_02】查询语法

1、基础语法2、基本查询&#xff08;Select…From&#xff09;2.1 全表和特定列查询2.2 列别名2.3 Limit语句2.4 Where语句2.5 关系运算函数2.6 逻辑运算函数2.7 聚合函数 3、分组3.1 Group By语句3.2 Having语句3.3 Join语句&#xff08;1&#xff09;等值与不等值Join&#x…

SUPER-ADAM: Faster and Universal Framework of Adaptive Gradients

这周看了啥&#xff1a; 本周主要来看看别人是如何证明收敛的&#xff0c;围绕算法SUPER-ADAM 的更新过程和论文后面的证明&#xff0c;&#xff08;这篇证明比上周的亲切多了&#xff0c;我哭死&#xff09;仔细看了证明每一步的推导&#xff08;至于作者如何想出的&#xff…

verilog基础语法之比较器

逻辑运算符以及逻辑电路概述 逻辑运算符常用于条件判断语句&#xff0c;输出为布尔值True/False。逻辑运算符是基于比较器构造的。比较器电路是产生逻辑比较的本质&#xff1b;比较器电路的复杂度与位宽和比较类型相关&#xff1b;一般情况下可以先构造基本比较器&#xff0c;…

原生Html 引入element UI + vue3 表单校验设置

效果&#xff1a; 提交时&#xff0c;检验结果展示 html源码 <!DOCTYPE html> <html> <!--带搜索输入框下拉弹窗 --> <head><meta charset"UTF-8"><!-- import Vue before Element --><script src"../js/vue3.3.8/vu…

jmeter,通过Ant插件生成html报告,展示接口详细信息

一、下载Ant 下载地址&#xff1a;Apache Ant - 二进制发行版 二、安装 1、Ant环境变量 解压Ant目录&#xff1b;配置系统环境变量&#xff0c;添加ANT_PATH&#xff0c;值为D:\Software\Ant_plugIn\apache-ant-1.10.14配置系统环境变量Path&#xff0c;添加Ant路径 %ANT_H…

Unity之OpenXR+XR Interaction Toolkit接入Meta Quest3

前言 随着备受期待的Meta Quest 3与今年10月10日发布,这款来自Meta的下一代VR游戏头戴设备承诺将彻底改变您的游戏方式。 Meta Quest 3,玩家只需轻松一触即可在虚拟现实和真实世界之间无缝切换,无需摘下头戴设备进行快速现实检查。 Meta Quest 3最引人注目的特点之一是其能…

webpack学习-5.代码分离

webpack学习-5.代码分离 1.入口起点2.防止重复2.1 入口依赖2.2 SplitChunksPlugin 3.动态导入3.1 使用符合 ECMAScript 提案 的 import() 语法3.2 使用 webpack 特定的 require.ensure 4.预获取/预加载模块5.分析bundle6.总结 1.入口起点 代码分离是 webpack 中最引人注目的特…

AIGC - 环境搭建

一. 硬件环境 1. 超微7048主板&#xff0c;最多可搭载4块GPU 2. 2个Intel的 Xen至强 14核 CPU 3. 目前安装了一块Nvidia 的P40 GPU&#xff0c;后续根据需要还最多可以扩展3块GPU 4. 4T机械 2T Nvme固态&#xff0c; 5. 4条64G DDR4内存条&#xff0c;共 196G内存…

QT多项目管理

.pro文件配置解释&#xff1a;​​​​​​ Qt 中的多项目管理_qt子目录项目-CSDN博客Qt 模块化开发之 pro 子项目开发_qt 子项目-CSDN博客关于Qt编译库&#xff08;1&#xff09;&#xff1a;在子项目中编译动态库并且使用_qt编译动态库后配置qt-CSDN博客QT release下的编译…

涵盖多种功能,龙讯旷腾Module第六期:输运性质

Module是什么 在PWmat的基础功能上&#xff0c;我们针对用户的使用需求开发了一些顶层模块&#xff08;Module&#xff09;。这些Module中的一部分是与已有的优秀工具的接口&#xff0c;一部分是以PWmat的计算结果为基础得到实际需要的物理量&#xff0c;一部分则是为特定的计…

排序算法(二)-冒泡排序、选择排序、插入排序、希尔排序、快速排序、归并排序、基数排序

排序算法(二) 前面介绍了排序算法的时间复杂度和空间复杂数据结构与算法—排序算法&#xff08;一&#xff09;时间复杂度和空间复杂度介绍-CSDN博客&#xff0c;这次介绍各种排序算法——冒泡排序、选择排序、插入排序、希尔排序、快速排序、归并排序、基数排序。 文章目录 排…

排序-归并排序与计数排序

文章目录 一、归并排序1、概念2、过程3、代码实现4、复杂度5、稳定性 二、 计数排序1、思路2、代码实现3、复杂度&#xff1a;4、稳定性 一、归并排序 1、概念 是建立在归并操作上的一种有效,稳定的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已…

关键点检测☞png格式换bmp,且labelme标注的json中imagePath同步修改格式

import os import cv2 import jsondef bmp2jpg(in_img_path, out_dir_name): # .png -> .bmp# img = cv2.imread(in_img_path) # 彩色图片,位深24img =</

GDPU 数据结构 天码行空13

文章目录 一、【实验目的】二、【实验内容】三、实验源代码四、实验结果五、实验总结 一、【实验目的】 (1) 理解插入排序算法的实现过程&#xff1b; &#xff08;2&#xff09;理解不同排序算法的时间复杂度及适用环境&#xff1b; &#xff08;3&#xff09;了解算法性能…

Win11 跑通tensorRT

准备 1.安装cuda&#xff0c;成功之后文件夹如下图所示 2.下载cudnn&#xff0c;把cudnn对应的文件放在cuda里面 3.安装vs 4.安装对应cuda版本的tensorRT https://developer.nvidia.com/tensorrt-download 5.opencv安装 编译好 打开vs&#xff0c;配置环境 用vs打开tens…