史上“最”简单的扫雷(16*16 40雷)

如果我们要实现扫雷,那么我们要解决以下问题:

1.初始菜单  如果是最简单的当然不要了

2.地图的初始化

3.雷的数量和分布位置(随机分布)

4.排查雷的位置

5.判断是否正确

6.这个格子周围没有雷

First 

为了做出扫雷,我们需要这些文件头:

#include<bits/stdc++.h>
#include <conio.h>//键盘的使用
#include<Windows.h>

宏定义游戏行列数以及雷的数量:

#define Boom 40 //雷的数量
#define Row 16 //定义行数
#define Col 16 //定义列数

和一些储存变量:

int init[Row + 1][Col + 1];//记录雷的位置,-1为雷,1-8为那个格子周围雷的数量
int leftb = 16 * 16 - Boom;//未翻开且不是雷的格子
bool nowmap[Row + 1][Col + 1];//储存翻开的格子;

又因为VS不支持scanf,所以我们要用read()来输入: 

inline int read() {//快速读取,不再多说
	register int x = 0, f = 1;
	register char ch = getchar();
	while (ch < '0' || ch>'9') {
		if (ch == '-') {
			f = -1;
		}
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9') {
		x = x * 10 + ch - '0';
		ch = getchar();
	}
	return x * f;
}

如果我们要随机分布雷我就要用到 rand():

让我们来测试一下:

#include<bits/stdc++.h>
using namespace std;
int main()
{
	int n;
	for (int i = 1; i <= 10; i++) {
		//连续用rand()生成10个数
		n = rand();
		cout << n << " ";
	}
}

第一次输出:41 18467 6334 26500 19169 15724 11478 29358 26962 24464

第二次输出:41 18467 6334 26500 19169 15724 11478 29358 26962 24464

第三次输出:41 18467 6334 26500 19169 15724 11478 29358 26962 24464

哎我们发现这几次输出一样啊,那这样每一次雷的分布地方不就一样了吗?

So,我们需要一个神奇的东西来真·随机——srand((unsigned)time(NULL)):

#include<bits/stdc++.h>
using namespace std;
int main()
{
	int n;
	srand((unsigned)time(NULL));//选取种子文件
	for (int i = 1; i <= 10; i++) {
		//连续用rand()生成10个数
		n = rand();
		cout << n << " ";
	}
}

第一次输出:26906 22914 10401 12851 26845 25137 6123 25734 31886 9565

第二次输出:27171 8798 15607 28667 10357 15523 28856 18001 25837 3092

第三次输出:27256 26113 21323 31721 16392 19314 11476 7427 29154 7082

这样,每一次输出都不一样了

那么我们可以用InitGame来进行初始化:

void InitGame() {//初始化游戏
	srand((unsigned)time(NULL));//选取种子文件
	for (int i = 0; i <= Row + 1; i++) {//设置缓冲区
		for (int j = 0; j <= Col + 1; j++) {
			init[i][j] = 0;//初始没有雷
			nowmap[i][j] = false;//没有格子被翻开
		}
	}
	int numBoom = Boom;//未埋的雷的数量
	while (numBoom != 0) {
 		int r, c;
		r = rand() % Row + 1;//行数随机
		c = rand() % Col + 1;//列数随机
		if (init[r][c] != -1) {//只有这格不是雷才能设置雷
			init[r][c] = -1;//用-1来表示雷
			numBoom--;//只有成功设置了雷才能减去1
		}
	}
	for (int i = 1; i <= Row; i++) {
		for (int j = 1; j <= Col; j++) {
			if (init[i][j] != -1) {//如果这个不是雷
				//判断周围雷的数量
				int Num = 0;//暂时记录雷的数量
				for (int k = -1; k <= 1; k++) {
					for (int l = -1; l <= 1; l++) {
						if (init[i + k][j + l] == -1) {
							Num++;
						}
					}
				}
				init[i][j] = Num;//将Num赋给init
			}
		}
	}
	for (int i = 1; i <= Row; i++) {
		for (int j = 1; j <= Col; j++) {
			if (init[i][j] == 0) {
				init[i][j] = -10;//若没有雷则赋值为-10
			}
		}
	}
}

初始化之后,我们还需要用PointMap来进行地图的打印:

inline void PointMap() {//地图输出
	for (int i = 1; i <= Row; i++) {
		for (int j = 1; j <= Col; j++) {
			if (nowmap[i][j] == false) {//未被翻开
				putchar('#');
				putchar(' ');
			}
			else {
				putchar(init[i][j] + '0');
				putchar(' ');
			}
		}
		putchar('\n');
	}
}

当我们输入坐标后还要用isRight()判断坐标是否合法:

int isRight(int x, int y) {//判断坐标所在的格子类型
	//输入判断:-1为踩到雷,1为没有雷,2为非法输入,3为重复输入
	if (nowmap[x][y] == true) {//重复输入
		return 3;
	}
	else if (init[x][y] == -1) {//踩到雷了
		return -1;
	}
	else if (x <= 0 || y <= 0 || x > 16 || y > 16) {//非法输入
		return 2;
	}
	else {//没有雷
		return 1;
	}
}

但在真正的扫雷中还会出现这种现象:

 有些格子为零了

So

当我们的输入合法后还要判断是否为0,如果为零则周围一圈也输出:

void findNext(int lx, int ly) {
	for (int i = -1; i <= 1; i++) {
		for (int j = -1; j <= 1; j++) {
			if (nowmap[lx + i][ly + j] == false) {//判断有没有翻过,否则会陷入死循环
				nowmap[lx + i][ly + j] = true;
				if (init[lx + i][ly + j] == -10) {//如果又是0,则遍历这个
					findNext(lx + i, ly + j);
				}
			}

		}
	}
}

那么再稍加一点装饰就完成了

1 

那么,大体就好了。

完整Code: 

#include<bits/stdc++.h>
#include<Windows.h>
#include <conio.h>
using namespace std;
#define Boom 40 //雷的数量
#define Row 16 //定义行数
#define Col 16 //定义列数
int init[Row + 2][Col + 2];//记录雷的位置,-1为雷,1-8为那个格子周围雷的数量
int leftb = 16 * 16 - Boom;//未翻开且不是雷的格子
bool nowmap[Row + 2][Col + 2];//储存翻开的格子;
inline int read() {
	register int x = 0, f = 1;
	register char ch = getchar();
	while (ch < '0' || ch>'9') {
		if (ch == '-') {
			f = -1;
		}
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9') {
		x = x * 10 + ch - '0';
		ch = getchar();
	}
	return x * f;
}
void InitGame() {//初始化游戏
	srand((unsigned)time(NULL));//选取种子文件
	for (int i = 0; i <= Row + 1; i++) {//设置缓冲区
		for (int j = 0; j <= Col + 1; j++) {
			init[i][j] = 0;//初始没有雷
			nowmap[i][j] = false;//没有格子被翻开
		}
	}
	int numBoom = Boom;//未埋的雷的数量
	while (numBoom != 0) {
		int r, c;
		r = rand() % Row + 1;//行数随机
		c = rand() % Col + 1;//列数随机
		if (init[r][c] != -1) {//只有这格不是雷才能设置雷
			init[r][c] = -1;//用-1来表示雷
			numBoom--;//只有成功设置了雷才能减去1
		}
	}
	for (int i = 1; i <= Row; i++) {
		for (int j = 1; j <= Col; j++) {
			if (init[i][j] != -1) {//如果这个不是雷
				//判断周围雷的数量
				int Num = 0;//暂时记录雷的数量
				for (int k = -1; k <= 1; k++) {
					for (int l = -1; l <= 1; l++) {
						if (init[i + k][j + l] == -1) {
							Num++;
						}
					}
				}
				init[i][j] = Num;//将Num赋给init
			}
		}
	}
	for (int i = 1; i <= Row; i++) {
		for (int j = 1; j <= Col; j++) {
			if (init[i][j] == 0) {
				init[i][j] = -10;//若没有雷则赋值为-10
			}
		}
	}
}
inline void PointMap() {//地图输出
	for (int i = 1; i <= Row; i++) {
		for (int j = 1; j <= Col; j++) {
			if (nowmap[i][j] == false) {//未被翻开
				putchar('#');
				putchar(' ');
			}
			else {
				if (init[i][j] == -10) {//init为0
					putchar('0');
					putchar(' ');
				}
				else {
					putchar(init[i][j] + '0');
					putchar(' ');
				}
			}
		}
		putchar('\n');
	}
}
inline int isRight(int x, int y) {//判断坐标所在的格子类型
	//输入判断:-1为踩到雷,1为没有雷,2为非法输入,3为重复输入
	if (nowmap[x][y] == true) {//重复输入
		return 3;
	}
	else if (init[x][y] == -1) {//踩到雷了
		return -1;
	}
	else if (x <= 0 || y <= 0 || x > 16 || y > 16) {//非法输入
		return 2;
	}
	else {//没有雷
		return 1;
	}
}
void findNext(int lx, int ly) {
	for (int i = -1; i <= 1; i++) {
		for (int j = -1; j <= 1; j++) {
			if (nowmap[lx + i][ly + j] == false) {//判断有没有翻过,否则会陷入死循环
				nowmap[lx + i][ly + j] = true;
				if (init[lx + i][ly + j] == -10) {//如果又是0,则遍历这个
					findNext(lx + i, ly + j);
				}
			}

		}
	}
}
bool isWin() {
	int Num_1 = 0;//暂储
	for (int i = 1; i <= Row; i++) {
		for (int j = 1; j <= Col; j++) {
			if (nowmap[i][j] == true) {
				Num_1++;
			}
		}
	}
	if (Num_1 == leftb) {
		return true;
	}
	else
		return false;
}
int main()
{
	printf("****************\n");
	printf("1.start   0.exit\n");
	printf("****************\n");
	bool isStart = false;//是否开始
	while (true) {//选择是否进行游戏
		if (_kbhit()) {//键盘是否按下?
			switch (_getch()) {
			case '0'://如果按下“0”结束程序
				return 0;
			case '1'://如果按下“1”开始游戏
				system("cls");//清空控制台
				printf("Start!");
				isStart = true;//开始
				Sleep(100);
				system("cls");
				break;
			}
		}
		if (isStart == true) {
			break;
		}
	}
	InitGame();
	while (leftb != 0) {
		PointMap();//打印地图
		int x, y;//坐标
		x = read();//输入X坐标
		y = read();//输入Y坐标
		system("cls");
		int isProceed = 0x3f3f3f;//输入判断:-1为踩到雷,1为没有雷,2为非法输入,3为重复输入
		isProceed = isRight(x, y);
		if (isProceed == -1) {//踩到雷了
			printf("Boom! 踩到雷了!\n 游戏结束!");
			Sleep(1000);
			system("cls");
			for (int i = 1; i <= Row; i++) {
				for (int j = 1; j <= Col; j++) {
					if (init[i][j] == -1) {
						cout << "* ";
					}
					else if (init[i][j] == -10) {
						cout << "0 ";
					}
					else
						cout << init[i][j] << " ";
				}
				cout << endl;
			}
			Sleep(1000);
			return 0;
		}
		if (isProceed == 2) {//非法输入
			printf("非法输入,请重新输入!\n");
			Sleep(1000);
			system("cls");
			continue;
		}
		if (isProceed == 3) {//方格已被翻开
			printf("此方格已被翻开,请重新输入!\n");
			Sleep(1000);
			system("cls");
			continue;
		}
		if (isProceed == 1) {//合法且没雷
			system("cls");
			nowmap[x][y] = true;
			if (init[x][y] == -10) {
				findNext(x, y);
			}
		}
		if (isWin() == true) {
			cout << "win!";
			return 0;
		}
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值