引入
这两天偶然间玩到了扫雷的游戏,下的是微软旗下的扫雷,感觉比起以前简陋的界面好了太多
感觉扫雷找到规律也可以玩的很有意思,仔细一想,扫雷不就一二维数组,给我也完全可以实现啊。便开始了我的设计扫雷之旅。
由于本人想兼顾扫雷的灵活性和与原版的功能相似性,我还是花了些时间去完善这些功能,标题也说了,包括空白展开,标记等。以下开始我们的讲解吧!
思路
主要思路是创建两个数组,一个用来记录扫雷的后台数据包括:雷的位置,并记录各个位置周围雷的数量。一个用来展示玩家能看到的界面--展示界面,根据玩家输入展示想给其展示的内容,我画张图来方便大家理解
用户输入一个地址,就将后台数组的数据传入展示数组并打印,这样就完成了对格子的探测。
如果选中的是雷,则判断游戏结束并退出,这样实现了失败的判定。
如果 总格子个数-排除的非雷个数=等于雷的个数,则完成了游戏胜利的判断。
如果选中的是0,则用一个递归函数展开,则完成了空白展开的功能。
将展示的内容根据传入地址将*改成$,则完成了对未知位置的标记。
以上便是主要的代码功能概述,下面详细讲解。
涉及头文件索引
在进行讲解之前,我想做一个多数博主都不会做的事,就是,把用到的较生僻头文件和功能都简单介绍下,见代码
#include<stdio.h> //输入输出头文件,这个都懂 #include<stdlib.h> //srand生成种子和rand生成随机数的头文件 //rand生成的随机数是与srand生成的种子有关,而srand随机生成的种子又与time(NULL)有关 #include<time.h> //调用函数time()生成时间戳以及调用Sleep()函数表示停留时间 #include<windows.h> //调用system("cls");函数,作用是清屏
以上内容如果不太懂的朋友强烈建议专门去看看相关内容,了解透这些运用之后,相信一定会更容易理解我的调用。那么开始我们的代码内容吧!
主函数
这里直接把代码放到下面,旁边有注释,还是比较好理解的
#define _CRT_SECURE_NO_WARNINGS #include "mine_sweep.h"//头文件和函数声明太多我就单独创了个头文件放进去了 int main() { int x = 0, y = 0;//关于游戏界面大小——行-列 char mine[105][105];//后台界面 char show[105][105];//展示界面 srand((unsigned int)time(NULL));//随机生成种子 int input = 0; int digit_m = 10;//雷数量 do { input=menu();//打印菜单 if (input == 1) { printf("开始"); printf("\n请输入扫雷棋盘大小(长:宽):"); scanf("%d%d", &x, &y); printf("\n请输入设置雷的个数:"); scanf("%d", &digit_m); Initboard(x, y, mine, '0');//初始化棋盘--后台区 Initboard(x, y, show, '*');//初始化棋盘--展示曲 Init_mine(x, y, mine,show, digit_m);//初始化雷 playgame(x, y, digit_m, mine, show);//游戏运行函数 Sleep(15000); //结束界面展示停留 } else if (input == 0); else { printf("输入错误"); Sleep(1000); } system("cls"); //清屏 } while (input);//判断是否继续 printf("退出游戏"); return 0; }
分支函数功能实现
菜单函数
int menu() { printf("************************\n"); printf("******欢迎来到扫雷******\n"); printf("***** 1.开始玩 *****\n"); printf("***** *****\n"); printf("***** 0.退出 *****\n"); printf("************************\n"); printf("请选择:"); int m; scanf("%d", &m); return m; }
也没啥好说的,就展示菜单以及一个返回值,通过返回值判断是否继续游戏
初始化棋盘函数
初始化棋盘函数对后台和展示棋盘都适用,根据传入的参数初始化相应的二维数组,见代码
void Initboard(int x,int y,char arr[105][105],char ch) { for (int i = 0; i <= x+1; i++) for (int j = 0; j <= y+1; j++) arr[i][j] = ch;//将数组各个元素初始化为ch }
初始化雷函数
雷的初始化就涉及到随机生成数字和种子了,随机生成种子在主函数中已经提前完成,在这里就只用 生成随机数就行,不过建议也要注意一下生成特定随机数范围的方式,见代码
void Init_mine(int x, int y, char mine[105][105],char show[105][105], int digit) { int mine_x, mine_y; for (int i = 0; i < digit; i++) {//随机生成数字 start:; mine_x = rand() % x + 1; mine_y = rand() % y + 1; if (mine[mine_x][mine_y] == '0')//防止两个雷生成在同一位置 mine[mine_x][mine_y] = '*'; else goto start; } for (int i = 1; i <= x; i++) {//处理雷周围的数字,放到mine中,便于后期调用 for (int j = 1; j <= y; j++) { if (mine[i][j] == '*')continue; if (mine[i - 1][j] == '*')mine[i][j]++; if (mine[i + 1][j] == '*')mine[i][j]++; if (mine[i][j + 1] == '*')mine[i][j]++; if (mine[i][j - 1] == '*')mine[i][j]++; if (mine[i - 1][j - 1] == '*')mine[i][j]++; if (mine[i + 1][j - 1] == '*')mine[i][j]++; if (mine[i - 1][j + 1] == '*')mine[i][j]++; if (mine[i + 1][j + 1] == '*')mine[i][j]++; } } }
建议大家都注意下后台数组的处理方式,对编写扫雷代码很有帮助,方便处理数据
游戏运行函数
其实也没有多复杂,就是对两个数组的处理而已,见代码
void playgame(int x, int y, int digit_m, char mine[105][105], char show[105][105]) { int x1, y1, judge; int m = 0; int* blank = &m; while (*blank < x * y - digit_m) { system("cls"); Showboard(x, y, show); printf("或者输入标记的格子(1 行 列)\n"); printf("请输入要探测格子的位置(0 行 列):"); scanf("%d%d%d", &judge, &x1, &y1); if (mine[x1][y1] == '*'&&judge!=1) { *blank = 0; break; } else if (x1<1 && x1>x && y1<1 && y1>y) { printf("\n输入错误,请重新输入!"); continue; } if (judge == 0) { blank_unfold(x, y, x1, y1, mine, show, blank); } else if (show[x1][y1] != '*' && judge == 1) { printf("已展示格子不可标记!"); Sleep(1500); } else if (judge == 1)show[x1][y1] = '$'; else { printf("输入错误!"); Sleep(1500); } } system("cls"); Showboard(x, y, mine); if (*blank) { win_maliao(); } else { printf("\n踩到雷了,游戏结束!\n"); printf("15秒后返回初始界面。\n"); } }
其中还涉及到了胜利界面展示,展示界面函数和空白展开函数,下面进行讲解
界面展示函数
对于界面的展示还是很重要的,有时一个游戏的美观与舒适与否很大程度决定了一个游戏的品质,见代码
void Showboard(int x, int y, char arr[105][105]) { printf("%d |", 0); for (int i = 1; i <= y; i++) printf(" %d |", i); printf("\n"); for (int i = 0; i <= y; i++) printf("----"); printf("\n"); for (int i = 1; i <= x; i++) { printf("%d ", i); for (int j = 1; j <= y; j++) { if (arr[i][j] == '*' || arr[i][j] == '$') printf("| %c ", arr[i][j]); else printf("| %d ", arr[i][j] - '0'); } printf("|"); printf("\n"); for (int b = 0; b <= y; b++) printf("----"); printf("\n"); } }
主要用|和-符号来优化界面,最后的效果是这样的,见下图
空白展开函数
空白展开在这里算是个拓展功能,不实现的话其实也玩的动,但是有的话会大大提高其可玩性,主要运用到函数的递归,由于有标记功能,这里的代码也需要有一定改动,见代码
void blank_unfold(int x, int y, int x1, int y1, char mine[105][105], char show[105][105], int* blank) { if (x1<1 || x1>x || y1<1 || y1>y)return;//当输入超出范围时返回 if (show[x1][y1] == '0' || (show[x1][y1] != '*' && show[x1][y1] != '$')) return; //在位置已被探测时返回 else if (mine[x1][y1] != '0') {//在位置不是空白时展开返回 show[x1][y1] = mine[x1][y1]; (*blank)++; return; } else { //递归同时将空白展开 show[x1][y1] = '0'; (*blank)++; blank_unfold(x, y, x1 - 1, y1, mine, show,blank); blank_unfold(x, y, x1 + 1, y1, mine, show,blank); blank_unfold(x, y, x1, y1 - 1, mine, show,blank); blank_unfold(x, y, x1, y1 + 1, mine, show,blank); blank_unfold(x, y, x1 - 1, y1 - 1, mine, show, blank); blank_unfold(x, y, x1 - 1, y1 + 1, mine, show, blank); blank_unfold(x, y, x1 + 1, y1 - 1, mine, show, blank); blank_unfold(x, y, x1 + 1, y1 + 1, mine, show, blank); } }
彩蛋函数(胜利界面展示)
皮一下,闲着的时候弄得马里奥,胜利的时候免费批发
void win_maliao() { printf("\n恭喜获得胜利!\n"); printf("送你个马里奥\n"); printf(" ********\n"); printf(" ************\n"); printf(" ####....#.\n"); printf(" #..###.....##....\n"); printf(" ###.......###### ### ###\n"); printf(" ........... #...# #...#\n"); printf(" ##*####### #.#.# #.#.#\n"); printf(" ####*******###### #.#.# #.#.#\n"); printf(" ...#***.****.*###.... #...# #...#\n"); printf(" ....**********##..... ### ###\n"); printf(" ....**** *****....\n"); printf(" #### ####\n"); printf(" ###### ######\n"); printf("##############################################################\n"); printf("#...#......#.##...#......#.##...#......#.##------------------#\n"); printf("###########################################------------------#\n"); printf("#..#....#....##..#....#....##..#....#....#####################\n"); printf("########################################## #----------#\n"); printf("#.....#......##.....#......##.....#......# #----------#\n"); printf("########################################## #----------#\n"); printf("#.#..#....#..##.#..#....#..##.#..#....#..# #----------#\n"); printf("########################################## ############\n"); printf("15秒后返回初始界面。\n"); }
代码总和---CV可游玩
到这里差不多就要结束了,以上代码涉及了很多头文件,想来整合运行会比较困难,这些工作我就代大家做了,也是希望大家能玩玩我编的扫雷,见代码
#include<stdio.h>//各种头文件 #include<stdlib.h> #include<time.h> #include<windows.h> #include<string.h> void Initboard(int x,int y, char arr[105][105],char ch);//初始棋盘函数 void Showboard(int x, int y, char arr[105][105]);//打印界面函数 int menu();//菜单初始化函数 void Init_mine(int x, int y, char arr[105][105],char show[105][105], int digit);//随机初始化雷函数 void playgame(int x,int y,int digit_m, char mine[105][105], char show[105][105]);//游戏运行函数 void blank_unfold(int x, int y, int x1, int y1, char mine[105][105], char show[105][105],int* blank);//空白展开函数 void win_maliao();//胜利界面展示 void Initboard(int x,int y,char arr[105][105],char ch) { for (int i = 0; i <= x+1; i++) for (int j = 0; j <= y+1; j++) arr[i][j] = ch; } void Showboard(int x, int y, char arr[105][105]) { printf("%d |", 0); for (int i = 1; i <= y; i++) printf(" %d |", i); printf("\n"); for (int i = 0; i <= y; i++) printf("----"); printf("\n"); for (int i = 1; i <= x; i++) { printf("%d ", i); for (int j = 1; j <= y; j++) { if (arr[i][j] == '*' || arr[i][j] == '$') printf("| %c ", arr[i][j]); else printf("| %d ", arr[i][j] - '0'); } printf("|"); printf("\n"); for (int b = 0; b <= y; b++) printf("----"); printf("\n"); } } int menu() { printf("************************\n"); printf("******欢迎来到扫雷******\n"); printf("***** 1.开始玩 *****\n"); printf("***** *****\n"); printf("***** 0.退出 *****\n"); printf("************************\n"); printf("请选择:"); int m; scanf("%d", &m); return m; } void Init_mine(int x, int y, char mine[105][105],char show[105][105], int digit) { int mine_x, mine_y; for (int i = 0; i < digit; i++) { start:; mine_x = rand() % x + 1; mine_y = rand() % y + 1; if (mine[mine_x][mine_y] == '0') mine[mine_x][mine_y] = '*'; else goto start; } for (int i = 1; i <= x; i++) { for (int j = 1; j <= y; j++) { if (mine[i][j] == '*')continue; if (mine[i - 1][j] == '*')mine[i][j]++; if (mine[i + 1][j] == '*')mine[i][j]++; if (mine[i][j + 1] == '*')mine[i][j]++; if (mine[i][j - 1] == '*')mine[i][j]++; if (mine[i - 1][j - 1] == '*')mine[i][j]++; if (mine[i + 1][j - 1] == '*')mine[i][j]++; if (mine[i - 1][j + 1] == '*')mine[i][j]++; if (mine[i + 1][j + 1] == '*')mine[i][j]++; } } } void playgame(int x, int y, int digit_m, char mine[105][105], char show[105][105]) { int x1, y1, judge; int m = 0; int* blank = &m; while (*blank < x * y - digit_m) { system("cls"); Showboard(x, y, show); printf("或者输入标记的格子(1 行 列)\n"); printf("请输入要探测格子的位置(0 行 列):"); scanf("%d%d%d", &judge, &x1, &y1); if (mine[x1][y1] == '*'&&judge!=1) { *blank = 0; break; } else if (x1<1 && x1>x && y1<1 && y1>y) { printf("\n输入错误,请重新输入!"); continue; } if (judge == 0) { blank_unfold(x, y, x1, y1, mine, show, blank); } else if (show[x1][y1] != '*' && judge == 1) { printf("已展示格子不可标记!"); Sleep(1500); } else if (judge == 1)show[x1][y1] = '$'; else { printf("输入错误!"); Sleep(1500); } } system("cls"); Showboard(x, y, mine); if (*blank) { win_maliao(); } else { printf("\n踩到雷了,游戏结束!\n"); printf("15秒后返回初始界面。\n"); } } void blank_unfold(int x, int y, int x1, int y1, char mine[105][105], char show[105][105], int* blank) { if (x1<1 || x1>x || y1<1 || y1>y)return; if (show[x1][y1] == '0' || (show[x1][y1] != '*' && show[x1][y1] != '$'))return; else if (mine[x1][y1] != '0') { show[x1][y1] = mine[x1][y1]; (*blank)++; return; } else { show[x1][y1] = '0'; (*blank)++; blank_unfold(x, y, x1 - 1, y1, mine, show,blank); blank_unfold(x, y, x1 + 1, y1, mine, show,blank); blank_unfold(x, y, x1, y1 - 1, mine, show,blank); blank_unfold(x, y, x1, y1 + 1, mine, show,blank); blank_unfold(x, y, x1 - 1, y1 - 1, mine, show, blank); blank_unfold(x, y, x1 - 1, y1 + 1, mine, show, blank); blank_unfold(x, y, x1 + 1, y1 - 1, mine, show, blank); blank_unfold(x, y, x1 + 1, y1 + 1, mine, show, blank); } } void win_maliao() { printf("\n恭喜获得胜利!\n"); printf("送你个马里奥\n"); printf(" ********\n"); printf(" ************\n"); printf(" ####....#.\n"); printf(" #..###.....##....\n"); printf(" ###.......###### ### ###\n"); printf(" ........... #...# #...#\n"); printf(" ##*####### #.#.# #.#.#\n"); printf(" ####*******###### #.#.# #.#.#\n"); printf(" ...#***.****.*###.... #...# #...#\n"); printf(" ....**********##..... ### ###\n"); printf(" ....**** *****....\n"); printf(" #### ####\n"); printf(" ###### ######\n"); printf("##############################################################\n"); printf("#...#......#.##...#......#.##...#......#.##------------------#\n"); printf("###########################################------------------#\n"); printf("#..#....#....##..#....#....##..#....#....#####################\n"); printf("########################################## #----------#\n"); printf("#.....#......##.....#......##.....#......# #----------#\n"); printf("########################################## #----------#\n"); printf("#.#..#....#..##.#..#....#..##.#..#....#..# #----------#\n"); printf("########################################## ############\n"); printf("15秒后返回初始界面。\n"); } int main() { int x = 0, y = 0; char mine[105][105];//后台界面 char show[105][105];//展示界面 srand((unsigned int)time(NULL)); int input = 0; int digit_m = 10; do { input=menu();//打印菜单 if (input == 1) { printf("开始"); printf("\n请输入扫雷棋盘大小(长:宽):"); scanf("%d%d", &x, &y); printf("\n请输入设置雷的个数:"); scanf("%d", &digit_m); Initboard(x, y, mine, '0');//初始化棋盘--后台区 Initboard(x, y, show, '*');//初始化棋盘--展示曲 Init_mine(x, y, mine,show, digit_m);//初始化雷 playgame(x, y, digit_m, mine, show);//游戏运行函数 Sleep(15000); //结束界面展示 } else if (input == 0); else { printf("输入错误"); Sleep(1000); } system("cls"); //清屏 } while (input);//判断是否继续 printf("退出游戏"); return 0; }
运行截图
本篇文章已经代码制作编写不易,还请大家在走之前给一个小小的赞啊!!!
如果对你有帮助的话,别忘了放收藏夹关注我哦--比心(> - < )---♥
同时如果博主的文章有任何错误,都欢迎在评论区提出来,我会积极去改,也感谢大家对我的支持捏。