扫雷作为无人不晓的游戏,可以说非常火。其实利用数组和函数就能写一个简单版的扫雷!
目录
我建议创建多个项目这样方便管理而且更简洁。我在这里创建了这3个。
test.c:测试函数。
game.c:函数实现。
game.h:函数声明和定义常量。
初始化棋盘
我们要做一个9×9的棋盘,并且要用到两个二维数组一个是明面(xing)一个是暗面(digital)。虽然要做9×9的棋盘但是我们要定义11×11的数组(关于为什么这样到后面就知道了)要是char类型。数组中的行和列我把它定义为常量(方便后期更改)。
#define line 9//行
#define column 9//列
#define lines line + 2
#define columns column + 2
初始化函数其实很简单只需要遍历一遍,再把值赋进去就行。
//初始化棋盘
void Initialize(char function[lines][columns], int Lines, int Columns, char n)
{
for (int i = 0; i < Lines; i++)
{
for (int j = 0; j < Columns; j++)
{
function[i][j] = n;//赋值
}
}
}
注:这里的n是表示要赋的值。有两种:' * '是明面的(xing数组),' " '是暗面的(digital数组)。
打印棋盘
在打印棋盘时用的是xing数组,遍历一遍即可。如果直接打印那我们在后期玩的时候就会不知道坐标。所以我们还要给数组行和列排序。
//打印棋盘
void Print(char function[lines][columns], int Line, int Column)
{
printf("--------扫雷-------\n");
int b = 1;
for (int k = 0; k <= Line; k++)//数组行排序
{
printf("%d ", k);
}
printf("\n");
for (int i = 1; i <= Line ; i++)//打印棋盘
{
printf("%d ", b);//数组列排序
for (int j = 1; j <= Column ; j++)
{
printf("%c ", function[i][j]);
}
b++;
printf("\n");
}
}
埋雷
雷是随机分布的具体是怎么实现,我就不在此多说了,如果想看的可以到文章的最后看。大家看我写的就行。雷的数量我把它定义为常量(方便后期更改)。
//雷
#define thunder 10
在test.c中加上srand((unsigned int)time(NULL))(头文件<stdlib.h>,<time.h>)。因为thunder是一个常量不能被更改,所以要定义一个变量。
//埋雷
void Bury(char function[lines][columns], int Line, int Column)
{
int num = thunder;
while (num)
{
int x = rand() % line + 1;
int y = rand() % column + 1;
if (function[x][y] == '"')//判断这个地方是不是雷
{
function[x][y] = '!';//'!'代表雷
num--;
}
}
}
x,y怎么理解呢?
一个数除9会余0~8中的随机一位,加上一后x和y的范围就是1~9。
周围雷数
选中一个坐标后我们要计算它周围8个格子中有几个雷要怎么做呢?
其实只需要把周围8个格子相加(虽然是char类型,计算时是用ASCII码值计算),然后减去8个' " '的ASCII码值,最后乘-1(!比"要大一位所以减后是负数)。因为是11×11的棋盘不用担心边缘的位置发生非法访问。
//周围雷数
char First_difference(char digital[lines][columns], int x, int y)
{
return (digital[x - 1][y - 1] + digital[x - 1][y] + digital[x - 1][y + 1] +
digital[x][y - 1] + digital[x][y + 1] +
digital[x + 1][y - 1] + digital[x + 1][y] + digital[x + 1][y + 1] - 34 * 8) * -1;
}
排雷
排雷肯定是个循环,但是要循环多少次呢?那就要看有多少不是雷了。
如果在排雷中不幸排到雷那就跳出循环。如果没有那就让First_difference函数返回周围有几个雷,让返回值加上48(First_difference返回的是char类型,让它加48对应字符数字)。让xing数组的该位置等于它即可。最后打印。
怎么判定成功呢?其实只需要一个flag变量。在每次没选到雷时flag++,最后如果flag等于没雷的数量那就成功了。
//排查雷
void Minesweeping(char digital[lines][columns], char xing[lines][columns], int Line, int Column)
{
int a = line * column - thunder;//循环次数(不是雷的数量)
int flag = 0;
int x = 0;
int y = 0;
while (a--)
{
printf("请选择你要排查的坐标:");
scanf("%d %d", &x, &y);
if (digital[x][y] == '!')//选中雷
{
printf("\n");
printf("很遗憾你死了,雷分布如下。注:!是雷\n");
Print(digital, line, column);
break;
}
else//未选中雷
{
char r = First_and_then_difference(digital, x, y);
xing[x][y] = r + 48;
Print(xing, line, column);
flag++;
}
}
if (flag == line * column - thunder)
{
printf("恭喜你通过了!!!\n");
}
}
这是升级版的扫雷的地址扫雷(升级版)附全代码-优快云博客 。
整体代码
test.c
#include "game.h"//自己写的头文件只能用""
void test()
{
//创建数组
char xing[lines][columns] = { 0 };
char digital[lines][columns] = { 0 };
//初始化
Initialize(digital, lines, columns, '"');//暗
Initialize(xing, lines, columns, '*');//明
//埋雷
Bury(digital, line, column);
//打印
Print(xing, line, column);
//排雷
Minesweeping(digital, xing, line, column);
}
int main()
{
srand((unsigned int)time(NULL));
test();
return 0;
}
game.h
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
//行
#define line 9
//列
#define column 9
#define lines line + 2
#define columns column + 2
//雷
#define thunder 10
//初始化棋盘
void Initialize(char function[lines][columns], int Lines , int Columns, char n);
//打印棋盘
void Print(char function[lines][columns], int Line, int Column);
//埋雷
void Bury(char function[lines][columns], int Line, int Column);
//周围雷数
char First_difference(char digital[lines][columns], int x, int y);
//排查雷
void Minesweeping(char digital[lines][columns], char xing[lines][columns], int Line, int Column);
game.c
#include "game.h"
//初始化棋盘
void Initialize(char function[lines][columns], int Lines, int Columns, char n)
{
for (int i = 0; i < Lines; i++)
{
for (int j = 0; j < Columns; j++)
{
function[i][j] = n;
}
}
}
//打印棋盘
void Print(char function[lines][columns], int Line, int Column)
{
printf("--------扫雷-------\n");
int b = 1;
for (int k = 0; k <= Line; k++)
{
printf("%d ", k);
}
printf("\n");
for (int i = 1; i <= Line ; i++)
{
printf("%d ", b);
for (int j = 1; j <= Column ; j++)
{
printf("%c ", function[i][j]);
}
b++;
printf("\n");
}
}
//埋雷
void Bury(char function[lines][columns], int Line, int Column)
{
int num = thunder;
while (num)
{
int x = rand() % line + 1;
int y = rand() % column + 1;
if (function[x][y] == '"')
{
function[x][y] = '!';
num--;
}
}
}
//周围雷数
char First_difference(char digital[lines][columns], int x, int y)
{
return (digital[x - 1][y - 1] + digital[x - 1][y] +
digital[x - 1][y + 1] + digital[x][y - 1] +
digital[x][y + 1] + digital[x + 1][y - 1] +
digital[x + 1][y] + digital[x + 1][y + 1] - 34 * 8) * -1;
}
//排查雷
void Minesweeping(char digital[lines][columns], char xing[lines][columns], int Line, int Column)
{
int a = line * column - thunder;
int flag = 0;
int x = 0;
int y = 0;
while (a--)
{
printf("请选择你要排查的坐标:");
scanf("%d %d", &x, &y);
if (digital[x][y] == '!')
{
printf("\n");
printf("很遗憾你死了,雷分布如下。注:!是雷\n");
Print(digital, line, column);
break;
}
else
{
char r = First_difference(digital, x, y);
xing[x][y] = r + 48;
Print(xing, line, column);
flag++;
}
}
if (flag == line * column - thunder)
{
printf("恭喜你通过了!!!\n");
printf("\n");
}
}
实现随机数
C语言提供了rand函数,这个是用来生成随机数的。头文件为stdlib.h。给大家简单操作一下。
通过以上我们不难发现第一次和第二次结果一样。事实上rand是伪随机数。伪随机数不是真正的随机数,是通过某种算法生成的。真正的随机数是无法预测的。而rand函数是对一个叫"种子"的基准值进行运算生成的随机值。因为种子默认为1,所以想生成不同随机数,就要让种子改变。
C语言为我们提供了srand函数。用来初始化随机数的生成器。程序中在调用rand 函数之前先调用srand 函数,通过srand 函数的参数seed来设置rand函数生成随机数的时候的种子,只要种子在变化,每次生成的随机数序列也就变化起来了。
那也就是说给srand的种子是如果是随机的,rand就能生成随机数;在生成随机数的时候又需要一个随机数,这就矛盾了。
在程序中我们一般是使用程序运行的时间作为种子的,因为时间时刻在发生变化的。在C语言中有一个函数叫time,就可以获得这个时间。time会返回当前的日历时间。其实也就是返回1970年1月1日0时0分0秒到现在程序运行之间的差值。time函数的参数timer如果是非NULL的指针的话,函数也会将这个返回的差值放在timer指向的内存中带回去。
如果 timer是NULL,就只返回这个时间的差值。time函数返回的这个时间差也被叫做:时间戳。 time函数的时候需要包含头文件:time.h如果只是让time返回时间戳的话可以这样写time(NULL);
以上写的可能不够具体,如果存在什么问题的话,可以私信我。