扫雷是一个非常经典地小游戏。今天我用c语言来实现它。
首先明确扫雷地思路:
1.用一个二维数组来存放雷的位置(arr2),用另一个二维数组来存放棋盘(arr1)。
2.我输入arr1中的某个位置坐标,计算机去计算这个位置周围一圈的雷数,并把这个这个点打印成雷数。如果是0,则打印成空白,并将周围一圈的点作为一个新的位置点,去计算,这样可以实现拓展空白的功能。
那我要完成这么多,就需要实现这几个函数:1.打印函数,打印棋盘。2.埋雷函数,计算机随机埋雷。3.接收指令函数,让计算机明白我是想要扫雷,还是标记雷,还是取消标记雷。4.扫雷函数,给计算机一个坐标,去判断有没有被炸死,没有炸死那这个地方有多少雷,如果是0,则向外拓展。5.标记雷函数,给出坐标,计算机把这个雷标记起来,这个点就不能再被扫描了。6.取消标记雷函数,就是取消标记。7.拓展函数,拓展函数实现对空白的拓展,因为是要扫描周围一圈,所以在雷盘(arr1)上,我们最多只能去扫描角落的点,那么它会去扫描周围一圈有多少雷,这样就超出了雷盘的大小,所以我们的arr2需要比arr1大一圈,再用函数递归实现拓展。
首先,写出菜单函数
void menu()
{
system("title 扫雷");
system("color f0");
system("date /T");
system("TIME /T");
printf("-----------------------------\n");
printf("****** 1.开始游戏 *******\n");
printf("****** 0.退出游戏 *******\n");
printf("-----------------------------\n");
int input = 0;
char arr1[HANG][LIE] = { 0 };
char arr2[HANG + 2][LIE + 2] = { 0 };
printf("请选择:");
do
{
scanf("%d", &input);
switch (input)
{
case 1:
game(arr1,arr2,HANG,LIE);
break;
case 0:
printf("退出游戏");
return;
default:
printf("错误,重新输入:");
}
}while (input);
}
然后写出两个初始化函数,对arr1和arr2进行初始化
void chushihua2(char arr[HANG+2][LIE+2],int hang,int lie,char a)
{
int i = 0;
int j = 0;
for (i = 0; i < hang; i++)
for (j = 0; j < lie; j++)
arr[i][j] = a;
}
void chushihua(char arr[HANG][LIE], int hang, int lie,char a)
{
int i = 0;
int j = 0;
for (i = 0; i < hang; i++)
for (j = 0; j < lie; j++)
arr[i][j] = a;
}
然后写出打印函数
void display(char arr[HANG][LIE], int hang, int lie)
{
//system("cls");
int i = 0;
int j = 0;
for (i = 0; i < hang; i++)
printf(" %d ", i + 1);
printf("\n");
for (i = 0; i < hang; i++)
{
printf("%d", i + 1);
for (j = 0; j < lie - 1; j++)
{
printf(" %c |", arr[i][j]);
}
printf(" %c\n ", arr[i][j]);
if (i < hang - 1)
{
for (j = 0; j < lie - 1; j++)
printf("---|");
printf("---\n");
}
}
}
接着写出游戏主题,game函数
void game(char arr1[HANG][LIE],char arr2[HANG+2][LIE+2],int hang,int lie)
{
flag = 0;
// arr1 棋盘 arr2 答案
chushihua(arr1, HANG, LIE,'#');
chushihua2(arr2, HANG + 2, LIE + 2,'0');
put_lei(arr2, HANG + 2, LIE + 2);
while (1)
{
display(arr1,hang,lie);
jieguo(arr1,arr2,hang,lie);
put_order(arr1,arr2,hang,lie);
}
}
然后是填雷函数
void put_lei(char arr[HANG + 2][LIE + 2], int hang, int lie)
{
int count = 0;
printf("计算机正在埋雷\n");
while (count < NUM)
{
int i = rand() % (hang - 2) + 1;
srand((unsigned int)(time(NULL)));
int j = rand() % (lie - 2) + 1;
if (arr[i][j] == '0')
{
arr[i][j] = '1';
count++;
}
}
}
然后是给出指令函数 为了方便测bug 多加了一个调试模式
void put_order(char arr1[HANG][LIE],char arr2[HANG+2][LIE+2],int hang,int lie)
{
if (max == 1)
{
int i = 1;
while (i)
{
int x = 0;
int y = 0;
printf("打印棋盘(1) or 打印藏雷盘(2) or 打印所有雷的坐标(3) or 退出调试(4):");
scanf("%d", &i);
switch (i)
{
case 1:
for (x = 0; x < HANG; x++)
{
for (y = 0; y < LIE; y++)
printf("%c ", arr1[x][y]);
printf("\n");
}
break;
case 2:
for (x = 0; x < HANG+2; x++)
{
for (y = 0; y < LIE+2; y++)
printf("%c ", arr2[x][y]);
printf("\n");
}
break;
case 3:
for (x = 0; x < HANG + 2; x++)
{
for (y = 0; y < LIE + 2; y++)
{
if (arr2[x][y] == '1')
printf("%d ,%d \n", x, y);
}
}
break;
case 4:
max = 0;
return;
default:
printf("错误,重新输入:");
}
}
}
if (max == 0)
{
printf("扫雷(1) or 标记雷(2) or 取消标记雷(3) or 提示(4) or 调试模式(5):");
int input = 0;
while (1)
{
scanf("%d", &input);
switch (input)
{
case 1:
saolei(arr1, arr2, hang, lie);
return;
case 2:
biaojilei(arr1, hang, lie);
return;
case 3:
quxiaobiaojilei(arr1, hang, lie);
return;
case 4:
tishi(arr1, arr2, hang, lie);
return;
case 5:
max = 1;
return;
default:
printf("错误,重新输入:");
}
}
}
}
接着写出标记 取消标记 提示函数。标记函数需要创建一个全局变量flag(已标记的数量),如果flag=0,那就不能取消标记,因为没有标记过。如果flag = NUM(雷的个数),那就不能再标记了,因为如果把整个棋盘都标记,那样可以直接取得胜利。
void biaojilei(char arr[HANG][LIE],int hang,int lie)
{
if (flag == NUM)
{
printf("标记雷个数达到上线\n");
return;
}
int i = 0;
int j = 0;
printf("输入标记坐标:");
while (1)
{
scanf("%d %d", &i, &j);
if (i<1 || i>hang || j<1 || j> lie)
{
printf("错误,重新输入:");
continue;
}
if (arr[i - 1][j - 1] =='@')
{
printf("该坐标已被标记,重新输入:");
continue;
}
if (arr[i - 1][j - 1] != '#')
{
printf("该坐标已被扫描,重新输入:");
continue;
}
arr[i - 1][j - 1] = '@';
flag++;
break;
}
}
void quxiaobiaojilei(char arr[HANG][LIE],int hang,int lie)
{
if (flag == 0)
{
printf("还没有标记雷,不能取消标记\n");
return;
}
int i = 0;
int j = 0;
printf("输入标记的坐标:");
while (1)
{
scanf("%d %d", &i, &j);
if (i<1 || i>hang || j<1 || j> lie)
{
printf("错误,重新输入:");
continue;
}
if(arr[i-1][j-1] != '@')
{
printf("此位置没有被标记,无法取消标记,重新输入:");
continue;
}
else
{
arr[i - 1][j - 1] = '#';
flag--;
break;
}
}
}
void tishi(char arr1[HANG][LIE], char arr2[HANG + 2][LIE + 2], int hang, int lie)
{
int i = 0;
int j = 0;
for (i = 0; i < hang; i++)
for (j = 0; j < lie; j++)
{
if (arr2[i+1][j+1] == '1' && arr1[i][j] == '#')
{
arr1[i][j] = '@';
flag++;
return;
}
}
}
接下来是扫雷与拓展空白函数
int jisuanleishu(char arr[HANG+2][LIE+2],int hang,int lie,int i,int j)
{
int sz= arr[i - 1][j - 1] + arr[i - 1][j] + arr[i - 1][j + 1] + arr[i][j - 1] + arr[i][j + 1] + arr[i + 1][j - 1] + arr[i + 1][j] + arr[i + 1][j + 1] - 8 * '0';
return sz;
}
void panduan(char arr1[HANG][LIE], char arr2[HANG + 2][LIE + 2], int hang, int lie,int i ,int j)
{
int sz = jisuanleishu(arr2, hang, lie, i, j);
if (sz == 0)
{
arr1[i - 1][j - 1] = ' ';
if (i - 1 >= 1 && i - 1 <= hang && j - 1 >= 1 && j - 1 <= lie && arr1[i - 2][j - 2] == '#')
panduan(arr1, arr2, hang, lie, i - 1, j - 1);
if (i >= 1 && i <= hang && j - 1 >= 1 && j - 1 <= lie && arr1[i - 1][j - 2] == '#')
panduan(arr1, arr2, hang, lie, i , j - 1);
if (i + 1 >= 1 && i + 1 <= hang && j - 1 >= 1 && j - 1 <= lie && arr1[i][j - 2] == '#')
panduan(arr1, arr2, hang, lie, i + 1, j - 1);
if (i - 1 >= 1 && i - 1 <= hang && j >= 1 && j <= lie && arr1[i - 2][j - 1] == '#')
panduan(arr1, arr2, hang, lie, i - 1, j );
if (i + 1 >= 1 && i + 1 <= hang && j >= 1 && j <= lie && arr1[i][j - 1] == '#')
panduan(arr1, arr2, hang, lie, i + 1, j);
if (i - 1 >= 1 && i - 1 <= hang && j + 1 >= 1 && j + 1 <= lie && arr1[i - 2][j] == '#')
panduan(arr1, arr2, hang, lie, i - 1, j + 1);
if (i >= 1 && i <= hang && j + 1 >= 1 && j + 1 <= lie && arr1[i - 1][j] == '#')
panduan(arr1, arr2, hang, lie, i , j + 1);
if (i + 1 >= 1 && i + 1 <= hang && j + 1 >= 1 && j + 1 <= lie && arr1[i][j] == '#')
panduan(arr1, arr2, hang, lie, i + 1, j + 1);
}
else
arr1[i - 1][j - 1] = '0' + sz;
}
void saolei(char arr1[HANG][LIE],char arr2[HANG+2][LIE+2],int hang,int lie)
{
int i = 0;
int j = 0;
printf("输入扫描的坐标:");
while (1)
{
scanf("%d %d", &i, &j);
if (i<1 || i>hang || j<1 || j> lie)
{
printf("错误,重新输入:");
continue;
}
if (arr1[i - 1][j - 1] != '#')
{
printf("这个坐标不能扫描,因为不是未知点\n");
printf("重新输入:");
continue;
}
if (arr2[i][j] == '1')
{
printf("很遗憾,你被炸死了\n");
printf("三秒后返回\n");
Sleep(3000);
system("cls");
menu();
}
else
{
panduan(arr1, arr2, hang, lie, i, j);
return;
}
}
}
最后需要一个判断出扫雷是否成功的函数
void jieguo(char arr1[HANG][LIE], char arr2[HANG+2][HANG+2],int hang,int lie)
{
int i = 0;
int j = 0;
int x = 0;
int y = 0;
for (i = 0; i < hang; i++)
{
for (j = 0; j < lie; j++)
{
if (arr1[i][j] == '#' && arr2[i + 1][j + 1] != '1')
{
y = 0;
break;
}
else
y++;
}
if (y == 0)
break;
}
for (i = 0; i < hang; i++)
{
for (j = 0; j < lie; j++)
{
if (arr1[i][j] == '@' && arr2[i + 1][j + 1] == '1')
x++;
if (x + y == NUM)
{
printf("扫雷成功!\n");
printf("三秒后返回\n");
Sleep(3000);
system("cls");
menu();
return;
}
}
}
}
至此,扫雷大部分已经完成
测试图如下