简单介绍:
最基本的规则:你点到一个数字,如果是3,那就说明最靠近他它周围的8个格里有3个雷。.然后通过相邻或者相间的数字之间的交集来判断哪些是雷,若点击猜中了雷,则游戏结束。
(在一些版本的扫雷游戏当中还有着时间的限制与要求 )
长话短说,接下来我们用c语言和控制台来初步实现扫雷游戏。此次游戏的实现需要引用三个文件,分别是被包含在源文件当中的test.c与game.c,被分配在头文件当中的game.h。
这三个文件的作用分别如下:
一、主题框架(不包含游戏函数的实现)
此处引用game.h文件来实现游戏函数。
#define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include "game.h" void menu() { printf("-----------------------------\n"); printf("- 1.开始游戏 0.退出游戏 -\n"); printf("-----------------------------\n"); } void game() { ; } int main() { int n; do { menu(); printf("请选择:>"); scanf_s("%d", &n); switch (n) { case 1: game(); break; case 0: printf("已退出游戏\n"); break; default: printf("选择错误,请重新选择-》\n\n"); break; } } while (n); return 0; }
n 用来判定是否n进行游戏,menu()函数则为游戏开始前的选项,game()函数用来实现游戏的运行。其中game()函数的书写是最重要的部分。
此处只包含选择是否开始游戏的界面,接下来实现游戏当中的game函数。
二、game函数实现
1、识别雷,统计坐一格内标雷的个数。
现在就拿一个一个9*9的格子来讲,如果我们要知道这个雷放在哪里,就需要用一个二位数组把这个雷存起来。这样子才能判断是否踩雷。所以这里定义一个9*9的二维数组arr[ 9 ][ 9 ]来将这些雷存起来,具体雷的个数视情况而定。
接下来就是基本的棋盘构建了。同样也可以用9*9的二维数组arr[ 9 ][ 9 ]来封装棋盘。
在游戏刚开始,点击一个坐标,那么他就必须显示这个坐标周围一格内有多少个雷,如下:
这种情况比较好处理,但是如果这个坐标出现在边界位置,还是用原来的方法去遍历这个坐标周围的一格内的数据,就会形成数组越界的错误,如图:
可能遇到这种情况的第一种反应差不多都是增加一个判断条件,去识别是否为边界坐标,那这样就在时间和空间上造成了极大的浪费。反向思考,那我们就可以让边界的坐标在遍历计算雷的个数的时候不形成越界,也就是扩大原来棋盘二维数组的大小,将原来的arr[ 9 ][ 9 ]扩大为arr[ 11 ][ 11 ]
2、布置雷
此处我们将雷定义为‘ 1 ’,非雷就定义为‘ 0 ’ ;当我们排查雷的时候,去识别雷的时候就会形成歧异,无法分辨是我们排查出来的雷,还是下次输入的时候,他本身被当作为雷所以我们需要两个二维数组来进行区分,用一个二维数组l e i [11][11]来存放雷,
用另外一个二维数组 p a i c h a [11][11]来存放排查雷的信息,这样子就不会形成歧异。
考虑到后面方便修改棋盘大小,这里在game.h使用宏定义来实现棋盘的大小。后面直接引用到test.c中。
二维数组lei布置雷的元素初始化为‘ 1 ’,其余的元素初始化为‘ 0 ’;
二维数组p a i c h a初始化为‘ * ’,排除雷后,具体位置改为具体数字字符;
接下来初始化棋盘:将雷初始化为全0,将信息数组初始化为全*,创建函数进行初始化,并将其放入game.h进行声明,然后在game.c当中实现。
char lei[hang][lie]={0}; char paicha[hang][lie]={0}; chushihua(paicha, hang, lie,'*'); chushihua(lei,hang,lie,'0');
void chushihua(char arr[hang][lie], int h, int l,char set ) { for (int i = 0;i < h;i++) { for (int j = 0;j < l;j++) { arr[i][j] = set; } } }
//set_mine(lei,Hang,Lie); void set_mine(char c[hang][lie], int h, int l) { int count = 10; while(count) { int x = rand() % h + 1; int y = rand() % l + 1; if (c[x][y] == '0') { c[x][y] = '1'; count--; } } }
这里布置雷为随机布置,所以要使用rand()函数,而在rand函数使用之需使用srand时间戳,
且需在game.h当中包含头文件stdlib.h和time.h 。
我们之前用字符‘0’将雷所在数组初始化,现在用‘1’来布置雷,效果如下
3、打印棋盘。
创建函数来打印棋盘dayin();图中的*为未知的,也就是玩家所能看到的的棋盘,上面的只有‘0’与‘1’的棋盘是游戏内雷的位置,是玩家看不到的内容。
dayin(lei, Hang, Lie); dayin(paicha,Hang,Lie);
void dayin(char b[hang][lie], int h, int l) { for (int tem = 0;tem <= l;tem++) { if (tem == l - 1) printf("-----"); else printf("----"); }printf("\n"); for (int i = 0;i <=9;i++) { if (i != 9) { printf("| %d ", i); } else printf("| %d |", i); }printf("\n"); for (int i = 1;i < hang-1;i++) { for (int tem = 0;tem < l+1;tem++) { if (tem == l - 1) printf("-----"); else printf("----"); }printf("\n"); printf("| %d ", i); for (int j = 1;j <= l;j++) { if (j == l) printf("| %c |", b[i][j]); else printf("| %c ", b[i][j]); }printf("\n"); } for (int tem = 0;tem < l+1;tem++) { if (tem == l - 1) printf("-----"); else printf("----"); }printf("\n"); }
4、排雷。
在game()函数当中创建排雷函数:pai(lei,paicha);也就是将排查出来的雷放在paicha数组当中去;此处有10个雷,如果排查了71次没有失败,则是排雷成功,否则排雷失败。
//pai(lei, paicha, Hang, Lie); void pai(char d[hang][lie], char e[hang][lie], int h, int l) { int x, y; int win = 0; while (win<h*l-nums_mine) { printf("\n请输入要排查的坐标(中间用空格隔开)\n"); scanf_s("%d %d", &x, &y); if (x >= 1 && x <= h && y >= 1 && y <= l) { if (e[x][y] == '*') { if (d[x][y] == 1) { printf("\n您踩雷了,游戏结束\n"); dayin(d, h, l); } else { int count = get_mine(d, x, y); e[x][y] = count + '0'; dayin(e, Hang, Lie); win++; } } } else printf("坐标非法,请重新输入\n"); } if (win == h * l - nums_mine) { printf("\nyou win\n"); dayin(e, Hang, Lie); } }
玩家输入坐标x,y,如果非法,则重新输入,如果合法,则排雷后跳出循环。
这里使用get_mine函数来使x,y坐标处显示周为一格内的雷的数量;
count为整形数据,+上一个字符‘ 0 ’让结果换算为对应字符形式。
我们之前用字符‘0’来初始化lei数组,现在除了雷,其余元素全部为字符‘0’,在get_mine 当中,我们把x,y坐标周围一格内的雷加起来转化为对应数字,于是就得到了x,y周围雷的数量:
int get_mine(char v[hang][lie], int x, int y) { return (v[x - 1][y ] + v[x - 1][y - 1] + v[x - 1][y + 1] + v[x ][y - 1] + v[x ][y + 1] + v[x + 1][y - 1] + v[x + 1][y ] + v[x + 1][y + 1])-8*'0'; }
输入坐标2,3,结果如图;
至此整个扫雷就初步完成了。