?write in front?
?大家好,我是謓泽,希望你看完之后,能对你有所帮助,不足请指正!共同学习交流?
?2021年度博客之星物联网与嵌入式开发TOP5→周榜31→总榜2513?
?本文由 謓泽 原创 CSDN首发? 如需转载还请通知⚠
?个人主页:打打酱油desu-CSDN博客
?欢迎各位→点赞? + 收藏⭐️ + 留言?
?系列专栏:YY_打打酱油desu-CSDN博客
✉️我们并非登上我们所选择的舞台,演出并非我们所选择的剧本?
目录
?write in front?
Ⅰ 前言
Ⅱ 模块化编程
Ⅲ 游戏思路与逻辑
Ⅳ 实现游戏步骤/过程
① 创建颜色函数
?创建颜色函数color()
② 菜单界面(menu)
③ 实现多行多列扫雷
④ 实现多个雷
⑤ 棋盘初始化
⑥ 棋盘的打印
⑦ 布置雷的信息
⑧ 玩家输入雷实现步骤
⑨ 排查 x,y 周围有多少雷
Ⅴ 结果演示
Ⅵ 模块化代码实现
(一)、test.c
(二)、game.h
(三)、game.c
Ⅰ 前言
扫雷游戏,想必大家都有玩过吧。没完过的话也可以试着玩一玩,这样对写扫雷游戏这个小游戏的化是会有一个很好的思路的。那么本片博客就来介绍如何实现扫雷游戏的具体步骤。
扫雷游戏链接? 扫雷游戏网页版 - Minesweeper
Ⅱ 模块化编程
再说实现三子棋逻辑思路前,我们来说说什么是 模块化编程 吧?
传统方式编程:所有的函数均放在main.c里,若使用的模块比较多,则一个文件内会有很多的代码,不利于代码的组织和管理,而且很影响编程者的思路。
模块化编程:把各个模块的代码放在不同的.c文件里,在.h文件里提供外部可调用函数的声明,其它.c文件想使用其中的代码时,只需要#include "XXX.h"文件即可。使用模块化编程可极大的提高代码的可阅读性、可维护性、可移植性等。
传统方式编程:所有的函数均放在main.c里,若使用的模块比较多,则一个文件内会有很多的代码,不利于代码的组织和管理,而且很影响编程者的思路。
模块化编程:把各个模块的代码放在不同的.c文件里,在.h文件里提供外部可调用函数的声明,其它.c文件想使用其中的代码时,只需要#include "XXX.h"文件即可。使用模块化编程可极大的提高代码的可阅读性、可维护性、可移植性等!
总的来说就是:当你代码比较多的时候,就可以采用模块化编程来完成这个程序?
Ⅲ 游戏思路与逻辑
创建菜单界面函数选择退出游戏或者是进入游戏。存放布置好雷的新星以及存放排查出雷的信息。首先,进行雷的初始化棋盘。然后,再打印出雷的初始化棋盘。注意:一定是要先进行 初始化 然后再 打印棋盘。接着,就可以布置雷的信息了。最后,输入排查雷的坐标。检查出的坐标是不是雷,布置雷存放的是字符(1) 没有放置的是字符(0)输入坐标的时候一共有④种情况:《很遗憾,你被炸死了!》、《宁已经在这里输入过坐标了,请重新输入!》、《宁输入的坐标范围错误!重新输入》、《恭喜你,排雷成功!太优秀了!》 然后,再回到步骤①,是否选择 进入游戏 以及 退出游戏。Ⅳ 实现游戏步骤/过程
① 创建颜色函数
?创建颜色函数color()
前景色颜色的对应值↓
0=黑色 8=灰色 1=蓝色 9=淡蓝色 十六进制 2=绿色 10=淡绿色 A 3=湖蓝色 11=淡浅绿色 B 4=红色 12=淡红色 C 5=紫色 13=淡紫色 D 6=黄色 14=淡黄色 E 7=白色 15=亮白色 F
color()创建颜色函数如下↓
void color(short x){if (x >= 0 && x <= 15)SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), x); elseSetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7);}
使用颜色函数的好处实际上无非就是让程序运行看上去更加美观、鲜明,实际上没什么实际作用,这点是我们要知道的。
这里的STD_OUTPUT_HANDLE需要引头文件#include<Windows.h>,才可以进行使用。
② 菜单界面(menu)
菜单界面函数实际上就像是我们的一个界面,就好比是游戏的界面目录,餐馆当中的菜单。一样的道理。这个是库函数就有的我们只需要直接引用下即可。示例代码如下↓
void menu(){color(0); //Black 黑色system("cls");//清屏.color(10);printf("|-----------|扫雷游戏|-----------|\n");printf("|********************************|\n");printf("|★★★★★★★★★★★★★★★★|\n");printf("|★★ 1.开始 0.退出 ★★|\n");printf("|★★★★★★★★★★★★★★★★|\n");printf("|0 = 不是雷 ---------- 1 = 它是雷|\n");printf("|--------------------------------|\n");}
注→在这里用到了一个system("cls"); 达到了一个清屏的效果,只有加了这个,你才可以让cmd中的界面全部为黑色。因为我们还在这个清屏指令上+color(0); 这个代表的是,黑色。
③ 实现多行多列扫雷
#define ROW 9#define COL 9
使用 #define 宏定义在这里的好处:
方便程序的修改,不用对整个程序进行修改,只需对宏定义上进行修改。提高程序的运行效率,更加方便模块化。在三子棋基础上,只需改变宏定义的值,就可以实现多子棋的效果。在程序当中,是9行9列的,如果想修改成10行10列的只需要把#define改成10即可!
10行10列的扫雷棋盘如下 ?
但是十行十列就是会出现这个的情况,当然这个问题也是非常的好解决的。大家可以看下怎么去解决这个问题。☆⌒(*^-゜)v THX!!
④ 实现多个雷
#define Thunder 10
这里 #define 在上面提到过,就不提了。
修改雷的个数也只需要把这上面的数字(10)修改变的数字修改,当然修改请理性修改,你不可能 9*9 的棋盘,给很多雷吧,那还怎么玩哈哈哈?。
比如修改成 40 个雷,看看效果如下所示 ?
⑤ 棋盘初始化
打印棋盘,本质上是打印数组的内容。如下所示?
void Initialization(char board[ROWS][COLS], int rows, int cols, char set){int i = 0;int j = 0;for (i = 0; i < rows; i++){for (j = 0; j < cols; j++){board[i][j] = set;}}}
char set 是实参传递到形参的字符。
实参数组名 行 可以进行省略,但是 列 不能进行省略。
⑥ 棋盘的打印
打印棋盘,本质上是打印数组的内容,这里数组的内容是字符'0'。如下所示?
void Print_board(char board[ROWS][COLS], int row, int col){int i = 0; int j = 0;color(7);printf("════════════════════\n");for (i = 0; i <= row; i++){if (i == 0){printf("%d|", i);}else{printf("%d|", i);}}printf("\n/|══════════════════");printf("\n");for (i = 1; i <= row; i++){printf("%d|", i);for (j = 1; j <= col; j++){printf("%c|", board[i][j]);}printf("\n");}color(6);printf("\n-----扫雷游戏------\n");}
打印棋盘的效果图,如下所示?
⑦ 布置雷的信息
打印完棋盘之后,就开始布置雷。
void Lay_thunder(char Findout[ROWS][COLS], int row, int col){//布置雷int count = Thunder;while (count){int x = rand() % row + 1;int y = rand() % col + 1;if (Findout[x][y] = '0'){Findout[x][y] = '1';count--;}}}
这里还用到了一个知识点【随机数】
在实际开发中,我们往往需要一定范围内的随机数,过大或者过小都不符合要求,那么,如何产生一定范围的随机数呢?我们可以利用取模的方法:
int a = rand() % 10; //产生0~9的随机数,注意10会被整除如果要规定上下限:
int a = rand() % 51 + 13; //产生13~63的随机数
分析:取模即取余,rand()%51+13
我们可以看成两部分:rand()%51
是产生 0~50 的随机数,后面+13
保证 a 最小只能是 13,最大就是 50+13=63
使用 <time.h> 头文件中的 time() 函数即可得到当前的时间(精确到秒),就像下面这样:
srand((unsigned)time(NULL));
?注意:这个在程序当中是只执行一次即可!
⑧ 玩家输入雷实现步骤
这里的玩家输入坐标,在玩家输入下棋的时候,定义了个静态局部变量,在执行代码的时候。玩游戏的时候会提醒一次, 输入第一个坐标记得空一格!每次进入游戏只有一次,这里主要就是用到了 静态局部变量 就可以保证上一次的值不会被销毁。
检查坐标处是不是雷,布置存放的是字符'1',没有放置雷存放的是字符'0'。
判断坐标输入合法性几种情况:
很遗憾,你被炸死了!宁已经在这里输入过坐标了,请重新输入!宁输入的坐标范围错误!重新输入。恭喜你,排雷成功!太优秀了!void Check(char Layouts[ROWS][COLS], char Findout[ROWS][COLS], int row, int col){//1.输入排查雷的坐标//2.检查坐标处是不是雷,布置雷存放的是字符'1',没有放置雷存放的是字符'0'。int x, y;int win = 0;while (win<row*col - Thunder){static int j = 1;//延长生明周期,while (j){color(8);printf("--------------------------\n");printf("[输入第一个坐标记得空一格!]\n");printf("--------------------------\n");j--;break;}color(11);printf("---------------\n");printf("请输入坐标>:");//x与y坐标范围 1~9scanf("%d %d", &x, &y);printf("---------------\n");//判断坐标的合法性if (x >= 1 && x <= row && y >= 1 && y <= col){if (Layouts[x][y] == '1'){printf("|══════════════════|\n");printf("|很遗憾,你被炸死了!|\n");printf("|══════════════════|\n");Print_board(Layouts, ROW, COL);Sleep(5000);break;}if (Findout[x][y] == '0'){color(6);printf("|═══════════════════════════════════|\n");printf("|宁已经在这里输入过坐标了,请重新输入!|\n");printf("|═══════════════════════════════════|\n");}if (Findout[x][y] == '1'){color(6);printf("|════════════════════════════════════|\n");printf("|宁已经在这里输入过坐标了,请重新输入!|\n");printf("|════════════════════════════════════|\n");}else{//不是雷情况下,统计x,y周围坐标有几个雷int Count = Statistics(Layouts, x, y);Findout[x][y] = Count + '0';Print_board(Findout, row, col);win++;}}else{printf("|═════════════════════════════|\n");printf("|宁输入的坐标范围错误!重新输入|\n");printf("|═════════════════════════════|\n");}}if (win == row*col - Thunder){printf("|═══════════════════════|\n");printf("|恭喜你,排雷成功!太优秀了!|\n");printf("|═══════════════════════|\n");Print_board(Findout, ROW, COL);}}
⑨ 排查 x,y 周围有多少雷
static int Statistics(char Layouts[ROWS][COLS], int x, int y){return Layouts[x-1][y-1]+Layouts[x][y-1] +Layouts[x+1][y-1]+Layouts[x-1][y]+Layouts[x+1][y]+Layouts[x-1][y+1]+Layouts[x][y+1]+Layouts[x+1][y+1] - 8*'0';}
?注意:静态局部变量去修饰函数的时候,让这个函数只能在自己所在的源文件内看到,其它的内部当中是看不到的。
Ⅴ 结果演示
被雷"砸死"的结果演示。
Ⅵ 模块化代码实现
(一)、test.c
测试游戏的逻辑。
//扫雷游戏的测试#define _CRT_SECURE_NO_WARNINGS 1#include<stdio.h>#include "game.h"void menu(){color(0); //Black 黑色system("cls");//清屏.color(10);printf("|-----------|扫雷游戏|-----------|\n");printf("|********************************|\n");printf("|★★★★★★★★★★★★★★★★|\n");printf("|★★ 1.开始 0.退出 ★★|\n");printf("|★★★★★★★★★★★★★★★★|\n");printf("|0 = 不是雷 ---------- 1 = 它是雷|\n");printf("|--------------------------------|\n");}void game(){printf(" ---------\n");printf("|PLAY GAME|\n");printf(" ---------\n");char Layouts[ROWS][COLS] = { 0 };//存放布置好雷的信息char Findout[ROWS][COLS] = { 0 };//存放排查出雷的信息//初始化棋盘Initialization(Layouts, ROWS, COLS, '0');//mineInitialization(Findout, ROWS, COLS, 'x');//show//打印棋盘/*Print_board(Layouts, ROW, COL);*/Print_board(Findout, ROW, COL);//布置雷Lay_thunder(Layouts, ROW, COL);/*Print_board(Findout, ROW, COL);*///排查雷Check(Layouts,Findout,ROW,COL);}void test(){int input = 0;srand((unsigned)time(NULL));do{menu();color(5);printf("\n");printf("|═════════════════════════════════|\n");printf("|Please enter the interface number|:");scanf("%d", &input);switch (input){case 1:game();break;case 0:printf("|════════|\n");printf("|退出游戏|\n");printf("|════════|\n");break;default:printf("\n");printf("|═════════════════════════════════|\n");printf("|由于你输入错误罚你5s不能玩(→_→)|\n");printf("|═════════════════════════════════|\n");Sleep(5000);}} while (input);}int main(void){test();return 0;}
(二)、game.h
关于游戏包含的函数声明,符号声明头文件的包含以及宏定义。
//游戏的函数的声明//一开始保持神秘感:■ 第①个棋盘初始化//不是雷:〇 第②个棋盘初始化//是雷话:★//排查出来雷的信息:数字表达,例如:Ⅰ - 1(这是周围有1个雷),两个雷的时候 - Ⅱ,依次类推!//1:①个数字存放布置好雷的信息2:①个数组存放排查出的雷的信息。—— 都用 char 类型 字符数组 来进行实现!#include<stdio.h>#include<Windows.h>#include<stdlib.h>#include<time.h>#define Thunder 10#define ROW 9#define COL 9#define ROWS ROW+2#define COLS COL+2//颜色函数void color(short x);//初始化函数,初始化11*11,因为 行 & 列 都需要加1void Initialization(char board[ROWS][COLS], int rows, int cols, char set);//打印棋盘,最终打印 9*9 棋盘即可void Print_board(char board[ROWS][COLS], int row, int col);//布置雷void Lay_thunder(char Findout[ROWS][COLS], int row, int col);//排查雷void Check(char Layouts[ROWS][COLS], char Findout[ROWS][COLS], int row, int col);
(三)、game.c
游戏和相关函数实现。
#define _CRT_SECURE_NO_WARNINGS 1//游戏的函数的实现#include "game.h"#include<stdio.h>void color(short x){if (x >= 0 && x <= 15)SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), x);elseSetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7);}void Initialization(char board[ROWS][COLS], int rows, int cols, char set){int i = 0;int j = 0;for (i = 0; i < rows; i++){for (j = 0; j < cols; j++){board[i][j] = set;}}}void Print_board(char board[ROWS][COLS], int row, int col){int i = 0; int j = 0;color(7);printf("════════════════════\n");for (i = 0; i <= row; i++){if (i == 0){printf("%d|", i);}else{printf("%d|", i);}}printf("\n/|══════════════════");printf("\n");for (i = 1; i <= row; i++){printf("%d|", i);for (j = 1; j <= col; j++){printf("%c|", board[i][j]);}printf("\n");}color(6);printf("\n-----扫雷游戏------\n");}void Lay_thunder(char Findout[ROWS][COLS], int row, int col){//布置雷int count = Thunder;while (count){int x = rand() % row + 1;int y = rand() % col + 1;if (Findout[x][y] = '0'){Findout[x][y] = '1';count--;}}}//静态局部变量去修饰函数的时候,让这个函数只能在自己所在的源文件内看到,其它的内部当中是看不到的。static int Statistics(char Layouts[ROWS][COLS], int x, int y){return Layouts[x-1][y-1]+Layouts[x][y-1] +Layouts[x+1][y-1]+Layouts[x-1][y]+Layouts[x+1][y]+Layouts[x-1][y+1]+Layouts[x][y+1]+Layouts[x+1][y+1] - 8*'0';}void Check(char Layouts[ROWS][COLS], char Findout[ROWS][COLS], int row, int col){//1.输入排查雷的坐标//2.检查坐标处是不是雷,布置雷存放的是字符'1',没有放置雷存放的是字符'0'。int x, y;int win = 0;while (win<row*col - Thunder){static int j = 1;//延长生明周期,while (j){color(8);printf("--------------------------\n");printf("[输入第一个坐标记得空一格!]\n");printf("--------------------------\n");j--;break;}color(11);printf("---------------\n");printf("请输入坐标>:");//x与y坐标范围 1~9scanf("%d %d", &x, &y);printf("---------------\n");//判断坐标的合法性if (x >= 1 && x <= row && y >= 1 && y <= col){if (Layouts[x][y] == '1'){printf("|══════════════════|\n");printf("|很遗憾,你被炸死了!|\n");printf("|══════════════════|\n");Print_board(Layouts, ROW, COL);Sleep(5000);break;}if (Findout[x][y] == '0'){color(6);printf("|═══════════════════════════════════|\n");printf("|宁已经在这里输入过坐标了,请重新输入!|\n");printf("|═══════════════════════════════════|\n");}if (Findout[x][y] == '1'){color(6);printf("|════════════════════════════════════|\n");printf("|宁已经在这里输入过坐标了,请重新输入!|\n");printf("|════════════════════════════════════|\n");}else{//不是雷情况下,统计x,y周围坐标有几个雷int Count = Statistics(Layouts, x, y);Findout[x][y] = Count + '0';Print_board(Findout, row, col);win++;}}else{printf("|═════════════════════════════|\n");printf("|宁输入的坐标范围错误!重新输入|\n");printf("|═════════════════════════════|\n");}}if (win == row*col - Thunder){printf("|═══════════════════════|\n");printf("|恭喜你,排雷成功!太优秀了!|\n");printf("|═══════════════════════|\n");Print_board(Findout, ROW, COL);}}
好了,那么这个扫雷游戏就到这里了,不知道你学会了没有。对于初学者这是可以尝试下,对编程的思维和逻辑,以及代码的理解能力帮助都是非常大的( •̀ .̫ •́ )✧
别忘记?(╹ڡ╹ )