如果我们要实现扫雷,那么我们要解决以下问题:
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;
}
}
}