扫雷(升级版)附全代码

上次我写了简单版本的扫雷(建议看一下扫雷【C语言】-CSDN博客),但是有些功能并没有实现。比如:

  1. 没有如果排查位置不是雷,可以展开周围的功能。
  2. 没有标记的功能。

在这篇中这些功能都会被实现。

文章目录

展开

标记

适配

扫雷全代码

game.h

game.c

test.c


展开

展开是用递归解决的。

当传入一个非雷坐标时,检查周围8个格子包括它。在让xing数组的该位置等于First_difference函数的返回值。如果函数的返回值存在0那么就再次调用展开函数。如果不存在则不调用。

在完成该函数中有几个要注意的条件。

  1. 检查坐标是否在有效范围内。
  2. 不要把*后的雷给替换。
  3. 不要出现死递归(当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;
}

以上就是主要本篇内容,如果有什么不懂的可以私信我,如果有什么错误请你指出。

相关推荐
爱吃生蚝的于勒1 小时前
C语言内存函数
c语言·开发语言·数据结构·c++·学习·算法
失落的香蕉4 小时前
C语言串讲-2之指针和结构体
java·c语言·开发语言
ChoSeitaku6 小时前
链表循环及差集相关算法题|判断循环双链表是否对称|两循环单链表合并成循环链表|使双向循环链表有序|单循环链表改双向循环链表|两链表的差集(C)
c语言·算法·链表
DdddJMs__1356 小时前
C语言 | Leetcode C语言题解之第557题反转字符串中的单词III
c语言·leetcode·题解
娃娃丢没有坏心思7 小时前
C++20 概念与约束(2)—— 初识概念与约束
c语言·c++·现代c++
ahadee8 小时前
蓝桥杯每日真题 - 第11天
c语言·vscode·算法·蓝桥杯
No0d1es9 小时前
2024年9月青少年软件编程(C语言/C++)等级考试试卷(九级)
c语言·数据结构·c++·算法·青少年编程·电子学会
Che3rry10 小时前
C/C++|关于“子线程在堆中创建了资源但在资源未释放的情况下异常退出或挂掉”如何避免?
c语言·c++
kuiini11 小时前
C 语言学习-02【编程习惯】
c语言·学习
木辛木辛子12 小时前
L2-2 十二进制字符串转换成十进制整数
c语言·开发语言·数据结构·c++·算法