练习时长两年半的扫雷

news/2024/11/6 17:20:47/

目录

设计思路

游戏运行效果

函数的声明

头文件game.h

游戏主体(源文件)

1.game.c

2.test.c

各文件的阐述

各部分设计心得

1.打印菜单

2.初始化雷池

3.打印雷池以及玩家界面

打印效果

如何改变雷的数量与雷池大小

4.生成随机雷

5.排雷与对局判断

对于越界的看法


设计思路

1.菜单

2.棋盘  需要一个9 * 9 的数组  为了防止越界可以用11 * 11  游戏的实现用11 * 11  玩家看到的则是9 * 9

3.布置雷   非雷 '0'   雷'1'   这里的 零 一 均为字符

4.排查雷  玩家输入坐标  非雷周围一圈的坐标有几个雷就将坐标显示替换为该数

5.判断输赢 全部雷排序除即胜利

游戏运行效果

 

这里就不把全部雷排完了,需要一定时间,待会的心得我会分享一个非常舒服的测试小技巧

函数的声明

头文件game.h

#define _CRT_SECURE_NO_WARNINGS 1#include <stdio.h>#include<time.h>#define ROW 9
#define COL 9#define ROWS ROW+2
#define COLS COL+2#define EASY_COUNT 10           //雷的个数//设计思路
//1.选择菜单
//2.棋盘  需要一个9 * 9 的数组   为了越界可以用11 * 11 游戏的实现用11 * 11   玩家看到的则是9 * 9
//3.布置雷   非雷 '0'   雷'1'    这里的 零 一 均为字符
//4.排查雷    玩家输入坐标   非雷周围一圈的坐标有几个雷就显示几
//5.判断输赢     全部雷排序除即胜利//打印菜单
void menu();//初始化棋盘   1.游戏内部棋盘    2.玩家棋盘
void InitBoard(char board[ROWS][COLS], int rows, int cols, char ch);//打印棋盘
void DisplayBoard(char board[ROWS][COLS], int row, int col);//布置雷
void SetMine(char Mine[ROWS][COLS], int row, int col);//排查雷
void FindMine(char Mine[ROWS][COLS], char Show[ROWS][COLS], int row, int col);
int Find(char Mine[ROWS][COLS], int row, int col);

游戏主体(源文件)

1.game.c

#define _CRT_SECURE_NO_WARNINGS 1#include "game.h"void InitBoard(char board[ROWS][COLS], int rows, int cols, char ch)
{int i = 0;for (i = 0; i < rows; i++)  //注意取值范围  不要越界{int j = 0;for (j = 0; j < cols; j++){board[i][j] = ch;}}
}//注意:需要打印的坐标是x与y的范围是 1-9
//故循环中的 i 与 j 不要初始化为 0  避免后面布置雷的个数一直不对void DisplayBoard(char board[ROWS][COLS], int row, int col)
{int x = 0;printf("------扫雷游戏------\n");for (x = 0; x <= row; x++){printf("%d ", x);}printf("\n");int i = 1;int j = 1;for (i = 1; i <= row; i++){printf("%d", i);for (j = 1; j <= col; j++){printf(" %c", board[i][j]);}printf("\n");}
}//注意:随机数的生成要在循环内部  每次判断前都要生成一次
//否则坐标字符一直为'1'  会出现死循环   void SetMine(char Mine[ROWS][COLS], int row, int col)
{int count = EASY_COUNT;while (count){int x = rand() % row + 1;int y = rand() % row + 1;if (Mine[x][y] == '0'){Mine[x][y] = '1';count--;}}}int Find(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;char Visited[ROWS][COLS];    //用来存放已经输入过的坐标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;}if (Visited[x][y] == '1'){printf("该坐标已排查过,请重新输入\n");continue;}else{int count = Find(Mine, x, y);Show[x][y] = count + '0';DisplayBoard(Show, ROW, COL);win++;Visited[x][y] = '1';}}else{printf("坐标非法,请重新输入\n");}}if (win == row * col - EASY_COUNT){printf("恭喜你,排雷成功\n");DisplayBoard(Mine, ROW, COL);}}

2.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];//存放布置好的雷char Show[ROWS][COLS];//存放排查出的雷的信息  即玩家页面//初始化棋盘InitBoard(Mine, ROWS, COLS, '0');InitBoard(Show, ROWS, COLS, '*');//打印棋盘DisplayBoard(Show, ROW, COL);//布置雷SetMine(Mine, ROW, COL);DisplayBoard(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:game();break;case 0:printf("退出游戏\n");break;default:printf("输入错误,请重新输入\n");break;}} while (input);return 0;
}

各文件的阐述

game.h头文件用来声明函数
game.c游戏功能的实现
test调用game.c的函数,用于运行测试

分文件写代码可以很好的避免被开源

把game.c改为静态库  使用时导入静态库即可  

各部分设计心得

1.打印菜单

封装一个专门打印菜单的函数,后期想要美化菜单直接在函数修改即可,不用在海量的主体代码寻找菜单部分的代码,提高工作效率

2.初始化雷池

玩家所看到的棋盘是 9 * 9 的  为了防止越界 设计时调用的是 11 * 11的二维数组

需要两个雷池  一个是设计游戏的 雷池  一个是玩家所看到的雷池 

即      一个存放雷的信息         一个提供给玩家进行游玩

存放雷池的数组全部初始化为  '0'

(这里的'0'为字符   数组为字符数组)

玩家游玩数组全部初始化为 '*'   

这里的初始化排雷的时候有妙用

void InitBoard(char board[ROWS][COLS], int rows, int cols, char ch)
{int i = 0;for (i = 0; i < rows; i++)  //注意取值范围  不要越界{int j = 0;for (j = 0; j < cols; j++){board[i][j] = ch;}}
}

由于对两个数组进行初始化的符号不同,故可以多增加一个形参接收初始化的字符

3.打印雷池以及玩家界面

封装一个打印函数,需要打印哪个数组就传哪个数组即可

为了方便玩家排雷   在雷池的周围标注行和列  优化游戏体验

void DisplayBoard(char board[ROWS][COLS], int row, int col)
{int x = 0;printf("------扫雷游戏------\n");for (x = 0; x <= row; x++){printf("%d ", x);}printf("\n");int i = 1;int j = 1;for (i = 1; i <= row; i++){printf("%d", i);for (j = 1; j <= col; j++){printf(" %c", board[i][j]);}printf("\n");}
}

列的打印很简单 用一个循环先打印出来即可

行的打印则需要稍稍注意 在每次打印雷池数据时打印一个数即可

打印效果

如何改变雷的数量与雷池大小

这是就体现了定义的好处了

可以通过修改定义来扩展雷池

//玩家页面

#define ROW 9       
#define COL 9        

//雷池信息

#define ROWS ROW+2
#define COLS COL+2

//雷的个数
#define EASY_COUNT 10     

 改变雷的数量和雷池大小直接从定义更改即可     

上一篇与坤对弈也有提到    性感坤坤在线邀请老铁对弈 (>_<)

4.生成随机雷

这是我们所需要的雷池数组   下标从0开始

画图方便理解   很容易可以看出 

生成的随机雷的坐标范围x,y只需要在1 - 9 

即图中红框内的范围

void SetMine(char Mine[ROWS][COLS], int row, int col)
{int count = EASY_COUNT;while (count){int x = rand() % row + 1;int y = rand() % row + 1;if (Mine[x][y] == '0'){Mine[x][y] = '1';count--;}}}

随机数的生成用rand()函数  需配合srand()使用  调用头文件#include <stdio.h>  

坐标范围是 1 - 9  故 rand() % row + 1 即  0 - 8  左右加一  故为 1 - 9

rand % row =   0   ~  row -1

5.排雷与对局判断

通过分析已知需要排查  row * col - EASY_COUNT  次

//可建立一个新数组来存放已经排查过的坐标
char Visited[ROWS][COLS]
 
int Find(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');
}

这个函数计算了输入坐标周围的雷的个数 并返回了字符

数字 3 想变成 字符 '3'  只需减去一个'0' 字符零

ASCALL码    51  -   48  = 3

void FindMine(char Mine[ROWS][COLS], char Show[ROWS][COLS], int row, int col)
{int x = 0;int y = 0;int win = 0;char Visited[ROWS][COLS];    //用来存放已经输入过的坐标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;}if (Visited[x][y] == '1'){printf("该坐标已排查过,请重新输入\n");continue;}else{int count = Find(Mine, x, y);Show[x][y] = count + '0';DisplayBoard(Show, ROW, COL);win++;Visited[x][y] = '1';}}else{printf("坐标非法,请重新输入\n");}}if (win == row * col - EASY_COUNT){printf("恭喜你,排雷成功\n");DisplayBoard(Mine, ROW, COL);}}

对于越界的看法

数组越界可能不会立即导致程序崩溃或报错。这取决于您使用的编程语言和运行时环境。有些语言和运行时环境会在数组越界时立即报错,而有些则不会。如果您的程序在数组越界时仍能正常运行,但在程序结束时报错,那么这可能是因为您使用的编程语言或运行时环境在程序结束时才检测到并报告了错误。

         ⠰⢷⢿⠄
⠀⠀⠀⠀⠀⣼⣷⣄
⠀⠀⣤⣿⣇⣿⣿⣧⣿⡄
⢴⠾⠋⠀⠀⠻⣿⣷⣿⣿⡀
🏀 ⠀⢀⣿⣿⡿⢿ ⠈⣿
⠀⠀⠀⢠⣿⡿⠁⠀⡊⠀ ⠙
⠀⠀⠀⢿⣿⠀⠀⠹⣿
⠀⠀⠀⠀⠹⣷⡀⠀⣿⡄
⠀⠀⠀⠀⣀⣼⣿⠀⢈⣧                                              我能在这打篮球,你能吗?


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

相关文章

VMware、CentOS、XShell、Xftp的安装

第 1 章 VMware 1.1 VMware 安装 一台电脑本身是可以装多个操作系统的&#xff0c;但是做不到多个操作系统切换自如&#xff0c;所以我们 需要一款软件帮助我们达到这个目的&#xff0c;不然数仓项目搭建不起来。 推荐的软件为 VMware&#xff0c;VMware 可以使用户在一台计…

MS5147/MS5148模数转换器可pin对pin兼容ADS1247/ADS1248

‎ADS1246、ADS1247 和 ADS1248 是高度集成的精密 24 位模数转换器 &#xff08;ADC&#xff09;。这些器件具有一个板载、低噪声、可编程增益放大器 &#xff08;PGA&#xff09;、一个带有单周期建立数字滤波器的精密三角积分 &#xff08;ΔΣ&#xff09; ADC 和一个内部振…

【学习笔记】低速数字输入电路

1、方案设计&#xff1a;单通道、单向、反相器 该电路采用单通道&#xff0c;单向光耦&#xff0c;只支持漏型输入&#xff0c;电路的输入端压差满足24V DC10%(21.6V DC-26.4V DC)&#xff0c;输出端电压在0~3.3V范围摆动。 1.1关键技术规格 1.2具体原理图 1.3电路原理详解 …

leetcode 806. 写字符串需要的行数

题目描述解题思路执行结果 leetcode 806. 写字符串需要的行数. 题目描述 写字符串需要的行数 我们要把给定的字符串 S 从左到右写到每一行上&#xff0c;每一行的最大宽度为100个单位&#xff0c;如果我们在写某个字母的时候会使这行超过了100 个单位&#xff0c;那么我们应该把…

【A*算法——清晰解析 算法逻辑——算法可以应用到哪些题目】例题1.第K短路

A*算法 A*算法是什么例题1. 第K短路题意解析 欢迎观看我的博客&#xff0c;如有问题交流&#xff0c;欢迎评论区留言&#xff0c;一定尽快回复&#xff01;&#xff08;大家可以去看我的专栏&#xff0c;是所有文章的目录&#xff09;   文章字体风格&#xff1a; 红色文字表示…

R语言相关系数的可视化

R相关系数的可视化 文章目录 R相关系数的可视化[toc]1、序列自相关2、序列偏自相关3、简单相关4、相关图可视化5、不同方法6、其他一些修饰 1、序列自相关 自相关是指同一时间序列在不同时间 t t t上取值的相关程度&#xff0c;假设时间序列 { X t } t 1 T \{X_t\}_{t1}^{T} …

三十三、微服务,SpringCloud架构

1、微服务架构 1.1 单体应用架构 将项目所有模块(功能)打成jar或者war&#xff0c;然后部署一个进程 优点: 1:部署简单:由于是完整的结构体&#xff0c;可以直接部署在一个服务器上即可。 2:技术单一:项目不需要复杂的技术栈&#xff0c;往往一套熟悉的技术栈就可以完成开发。…

物联网| 定时器计数器开发之中断方法|定时器中断处理函数|完整测试代码|物联网之蓝牙4.0 BLE基础-学习笔记(6)

文章目录 11 定时器计数器开发之中断方法定时器中断处理函数:完整测试代码&#xff1a; 11 定时器计数器开发之中断方法 LED控制电路同前节&#xff1a; CC2530的T3定时器(8位&#xff09;需要了解T3GJL,T3CCTLO,T3CCO,T3CCTL1,T3CC寄存器。如下表所示&#xff1a; 按照表格…