目录
前言
写这篇文章前呢,我先看了一下大佬们写的C语言扫雷代码,近300行的代码可以说是应有尽有。为了让这篇文章有些不同之处呢,我便偏向核心逻辑,选了113行的核心代码,将扫雷的核心部分剖析开来。希望此文章可以助你成功入门。
游戏规则
(扫雷游戏在线玩 - Minesweeper)
键盘输入坐标,选择要排查的雷的坐标。如果是雷,游戏失败,反之格子里的数字表示该格子周围雷的个数,如:
最终我们将所有非雷的格子都排查完以后,可获得游戏胜利。
核心逻辑
- 我们创建两个二维数组,一个用于显示(即玩家看到的),一个用来存放雷的信息。
- 随机布置雷,放在存雷信息的数组。
- 排查用户输入的坐标,如果是雷则结束游戏,如果不是雷则扫描周围雷的个数,并在被排查的格子里显示出周围雷的个数,当用户排完后结束游戏。
深度剖析
menu菜单函数
void menu()
{
printf(" 扫雷 \n");
printf(" 1.开始游戏 \n");
printf(" 2.退出游戏 \n");
}
main主函数
main()
{
int n=0;
me:
menu();//引用菜单函数
scanf("%d", &n);
if (1 == n)//反着写的话,如果不注意写成‘=’的话就会报错
{
game();//这个函数先不用管它,它里面引用了一系列函数,后面再讲
}
else if (2 == n)
{
printf("感谢游玩");
}
else
{
printf("输入不合法,请重新输入");
goto me;
}
}
game游戏函数
难点解答:数组多创建一圈
讲一下为什么数组是11x11的二维数组,因为我们排查雷的时候要排查周围一圈的格子。我们在9x9的扫雷游戏上再扩一圈全部是非雷的格子,这样我们在排查到边或者角的格子时不用考虑超出问题,在输入坐标时也更为方便。
void game()
{
char boom[11][11] = { '0'}, show[11][11] = {'0'};//创建两个数组
init(show,'*');//init函数用来初始化,这里传什么则未排查的格子显示的就是什么
init(boom, '0');//boom存放雷,‘0’为非雷,‘1’为雷,这里先清空雷
put(boom);//用于放置雷的函数
find(boom, show);//排雷函数
}
init初始化函数
void init(char a[11][11],char set)
{
for (int i = 0; i < 11; i++)
{
for (int j = 0; j < 11; j++)
{
a[i][j] = set;
}
}
}
put置雷函数
难点解答:用rand函数和时间戳生成随机数
rand函数生成的是一个伪随机数,它会提前获取一个数,再将此数经过一个复杂算法,该算法每次调用时都会返回一个明显不相关的数字序列。而获取的数是由srand函数提供的,比如现在我们为srand函数传入数字1,如下图:
我们看似得到了一串随机的数字,但不信你去你电脑上运行一下,是不是和我的结果完全一样呢?因此,这是提前计算好的数字,并不能做到每时每刻都在变化。嗯?每时每刻变化的是什么?是时间啊!
时间戳的概念
时间戳是指格林威治时间1970年01月01日00时00分00秒(北京时间1970年01月01日08时00分00秒)起至现在的总秒数。是每时每刻都在变化的。而我们要获取到时间戳也很简单,代码如下:
#include<stdio.h>
#include<time.h>//头文件
main()
{
printf("%d",time(NULL));
}
没错,我们将时间戳传进srand函数,那得到的就是真随机数了。 现在我们需要的是1~9的随机数作为x和y布置雷(最外圈不布置),那我们将数字取9的余数,得到0~8的随机数后加1即可。
void put(char a[11][11])
{
srand((unsigned)time(NULL));
for (int i = 1; i <= 10; i++)
{
int x = (rand() % 9)+1;
int y = (rand() % 9)+1;
if( '1'==a[x][y])//防止重复布置
{
i--;
}
a[x][y] ='1';
}
}
Count扫描雷个数的函数
因为我们的‘1’表示雷,‘0’表示非雷,故将格子周围存雷数组里的数字加起来,得到的就是周围雷的个数,再将其传到show数组即可。(boom里的是字符型,别忘了转为整形)
int Count(char boom[11][11], int x, int y)
{
return boom[x-1][y]+boom[x-1][y-1]+boom[x][y-1]+
boom[x+1][y-1]+boom[x+1][y]+boom[x+1][y+1] +
boom[x][y+1]+boom[x-1][y+1]-8*'0';
}
display展示函数
此函数用于将二维数组里9x9的部分输出
void display(char a[11][11])
{
for (int i = 0; i <= 9; i++)
{
printf("%d ", i);//打印列号
}
printf("\n");
for (int i = 1; i < 10; i++)
{
int j = 0;
printf("%d ", i);
for (int j = 1; j < 10; j++)
{
printf("%c ", a[i][j]);//打印行号
}
printf("\n");
}
}
find排雷函数
void find(char boom[11][11],char show[11][11])
{
int i = 0,x = 0, y = 0,count=0;
display(show);
printf("请输入要排查的坐标\n");
while (i < 71)//当排查了71次还未被炸死即胜利(9*9-10)
{
scanf("%d%d", &x, &y);
if ((x >= 1 && x <= 9) && (y >= 1 && y <= 9))
{
if (boom[x][y] == '1')
{
printf("很遗憾,排雷失败\n");
display(boom);//排雷失败即展示放置雷的函数
break;
}
else
{
system("CLS");//清屏函数,头文件为stdlib
show[x][y] = Count(boom, x, y)+'0';//整形转字符型
display(show);
printf("请输入要排查的坐标\n");
i++;
}
}
}
}
完整代码
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
void menu()
{
printf(" 扫雷 \n");
printf(" 1.开始游戏 \n");
printf(" 2.退出游戏 \n");
}
void init(char a[11][11],char set)
{
for (int i = 0; i < 11; i++)
{
for (int j = 0; j < 11; j++)
{
a[i][j] = set;
}
}
}
void put(char a[11][11])
{
srand((unsigned)time(NULL));
for (int i = 1; i <= 10; i++)
{
int x = (rand() % 9)+1;
int y = (rand() % 9)+1;
if( '1'==a[x][y])
{
i--;
}
a[x][y] ='1';
}
}
int Count(char boom[11][11], int x, int y)
{
return boom[x-1][y]+boom[x-1][y-1]+boom[x][y-1]+
boom[x+1][y-1]+boom[x+1][y]+boom[x+1][y+1] +
boom[x][y+1]+boom[x-1][y+1]-8*'0';
}
void display(char a[11][11])
{
for (int i = 0; i <= 9; i++)
{
printf("%d ", i);
}
printf("\n");
for (int i = 1; i < 10; i++)
{
int j = 0;
printf("%d ", i);
for (int j = 1; j < 10; j++)
{
printf("%c ", a[i][j]);
}
printf("\n");
}
}
void find(char boom[11][11],char show[11][11])
{
int i = 0,x = 0, y = 0,count=0;
display(show);
printf("请输入要排查的坐标\n");
while (i < 71)
{
scanf("%d%d", &x, &y);
if ((x >= 1 && x <= 9) && (y >= 1 && y <= 9))
{
if (boom[x][y] == '1')
{
printf("很遗憾,排雷失败\n");
display(boom);
break;
}
else
{
system("CLS");
show[x][y] = Count(boom, x, y)+'0';
display(show);
printf("请输入要排查的坐标\n");
i++;
}
}
}
}
void game()
{
char boom[11][11] = { '0'}, show[11][11] = {'0'};
init(show,'*');
init(boom, '0');
put(boom);
find(boom, show);
}
main()
{
int n=0;
me:
menu();
scanf("%d", &n);
if (1 == n)
{
game();
}
else if (2 == n)
{
printf("感谢游玩");
}
else
{
printf("输入不合法,请重新输入");
goto me;
}
}
运行结果
排雷失败
排雷成功
“纸上得来终觉浅,绝知此事要躬行”,学会了就自己动手试试吧!
————(如有问题,欢迎评论区提问)————