上次我写了简单版本的扫雷(建议看一下扫雷【C语言】-CSDN博客),但是有些功能并没有实现。比如:
- 没有如果排查位置不是雷,可以展开周围的功能。
- 没有标记的功能。
在这篇中这些功能都会被实现。
文章目录
展开
展开是用递归解决的。
当传入一个非雷坐标时,检查周围8个格子包括它。在让xing数组的该位置等于First_difference函数的返回值。如果函数的返回值存在0那么就再次调用展开函数。如果不存在则不调用。
在完成该函数中有几个要注意的条件。
- 检查坐标是否在有效范围内。
- 不要把*后的雷给替换。
- 不要出现死递归(当i==x,j==y时可能会出现)。
cpp
//展开
void unfold(char digital[lines][columns], char xing[lines][columns], int x, int y)
{
for(int i = x - 1; i <= x + 1; i++)
{
for (int j = y - 1; j <= y + 1; j++)
{
if ((i <= line && i >= 1) && (j <= column && j >= 1))//检查是否是有效范围
{
char r = First_difference(digital, i, j);//检查周围雷数
if (digital[i][j] != '!')//防止把*后是雷给替换
{
if (r == 0 && xing[i][j] != '0')//是0继续排查周围且防止出现死递归
{
xing[i][j] = r + 48;//+48变成字符数字
unfold(digital, xing, i, j);//递归
}
else
{
xing[i][j] = r + 48;
}
}
}
}
}
}
标记
标记就比较简单了。
要先判断是否要标记,在Minesweeping函数的else中加入下面这段代码。
cpp
char b = 0;
printf("是否要标记(Y/N):");
getchar();//用来消除缓冲区中的'\n',防止b的输入发生问题。
scanf("%c", &b);
mark(xing, b);
这里我的标记是用' + '作为标记字符。取消标记的代码和标记的代码一样,只不过取消标记是把' + '变成' * '。
cpp
//标记
int key = 0;//这里key是全局变量
void mark(char xing[lines][columns], int n)
{
char s = 0;
int i = 0;
int j = 0;
//标记
if (n == 89 || n == 121)//Y,y都行
{
key++;
printf("请选择你要标记的坐标:");
getchar();
scanf("%d %d", &i, &j);
xing[i][j] = '+';
}
//取消标记
if (key > 0 && key--)//确保标记次数和取消标记次数统一
{
printf("是否要取消标记d(Y/N):");
getchar();
scanf("%c", &s);
if (s == 89 || s == 121)
{
printf("请选择你要取消标记的坐标:");
getchar();
scanf("%d %d", &i, &j);
xing[i][j] = '*';
}
}
}
适配
新添加函数后原来的Minesweeping函数就会有一些不合理的地方需要改。不过在此之前展开函数需要改改。在标记一个位置后展开的过程中可能会把标记给替换。怎么改呢?
其实只要在检查周围雷数后加上 xing[i][j] != ' + ' 即可。
cpp
//展开
void unfold(char digital[lines][columns], char xing[lines][columns], int x, int y)
{
for(int i = x - 1; i <= x + 1; i++)
{
for (int j = y - 1; j <= y + 1; j++)
{
if ((i <= line && i >= 1) && (j <= column && j >= 1))
{
char r = First_difference(digital, i, j);
if (xing[i][j] != '+')//新加的
{
if (digital[i][j] != '!')
{
if (r == 0 && xing[i][j] != '0')
{
xing[i][j] = r + 48;
unfold(digital, xing, i, j);
}
else
{
xing[i][j] = r + 48;
}
}
}
}
}
}
}
现在我们就改改Minesweeping函数。以前的循环结束条件不能用了,直接写一个死循环因为我们并不知道什么时候循环结束。失败以前的可以用,那该怎么判断成功呢?
其实只要遍历一遍xing数组看看有几个' * '和' + '。如果它们等于雷数就跳出。
cpp
//排查雷
void Minesweeping(char digital[lines][columns], char xing[lines][columns], int Line, int Column)
{
int x = 0;
int y = 0;
while (1)
{
printf("请选择你要排查的坐标:");
scanf("%d %d", &x, &y);
if (digital[x][y] == '!')
{
printf("很遗憾你死了,雷分布如下。注:!是雷\n");
Print(digital, line, column);
break;
}
else
{
char b = 0;
unfold(digital, xing, x, y);
printf("是否要标记(Y/N):");
getchar();
scanf("%c", &b);
mark(xing, b);
Print(xing, line, column);
}
//判断成功条件
int num = 0;
for (int m = 1; m <= Line; m++)
{
for (int n = 1; n <= Column; n++)
{
if (xing[m][n] == '*' || xing[m][n] == '+')
{
num++;
}
}
}
if (thunder == num)
{
printf("恭喜你通过了!!!\n");
break;
}
}
}
扫雷全代码
game.h
cpp
#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 unfold(char digital[lines][columns], char xing[lines][columns], int x, int y);
//标记
void mark(char xing[lines][columns], int n);
//排查雷
void Minesweeping(char digital[lines][columns], char xing[lines][columns], int Line, int Column);
game.c
cpp
#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 unfold(char digital[lines][columns], char xing[lines][columns], int x, int y)
{
for(int i = x - 1; i <= x + 1; i++)
{
for (int j = y - 1; j <= y + 1; j++)
{
if ((i <= line && i >= 1) && (j <= column && j >= 1))
{
char r = First_difference(digital, i, j);
if (xing[i][j] != '+')
{
if (digital[i][j] != '!')
{
if (r == 0 && xing[i][j] != '0')
{
xing[i][j] = r + 48;
unfold(digital, xing, i, j);
}
else
{
xing[i][j] = r + 48;
}
}
}
}
}
}
}
//标记
int key = 0;
void mark(char xing[lines][columns], int n)
{
char s = 0;
int i = 0;
int j = 0;
if (n == 89 || n == 121)
{
key++;
printf("请选择你要标记的坐标:");
getchar();
scanf("%d %d", &i, &j);
xing[i][j] = '+';
}
if (key > 0 && key--)
{
printf("是否要取消标记d(Y/N):");
getchar();
scanf("%c", &s);
if (s == 89 || s == 121)
{
printf("请选择你要取消标记的坐标:");
getchar();
scanf("%d %d", &i, &j);
xing[i][j] = '*';
}
}
}
//排查雷
void Minesweeping(char digital[lines][columns], char xing[lines][columns], int Line, int Column)
{
int x = 0;
int y = 0;
while (1)
{
printf("请选择你要排查的坐标:");
scanf("%d %d", &x, &y);
if (digital[x][y] == '!')
{
printf("\n");
printf("很遗憾你死了,雷分布如下。注:!是雷\n");
Print(digital, line, column);
break;
}
else
{
char b = 0;
unfold(digital, xing, x, y);
printf("是否要标记(Y/N):");
getchar();
scanf("%c", &b);
mark(xing, b);
Print(xing, line, column);
}
int num = 0;
for (int m = 1; m <= Line; m++)
{
for (int n = 1; n <= Column; n++)
{
if (xing[m][n] == '*')
{
num++;
}
}
}
if (thunder == num)
{
printf("恭喜你通过了!!!\n");
break;
}
}
}
test.c
cpp
#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;
}
以上就是主要本篇内容,如果有什么不懂的可以私信我,如果有什么错误请你指出。