扫雷游戏中递归展开与第一次点击不会是雷

第一次尝试编写扫雷游戏,对于我们小白来说,是对逻辑能力的培养。在创作扫雷游戏的过程中不断创新去优化这个游戏,也是一个自我提升与提高逻辑能力的最有效的方法。

一、总代码

我先将自己的总代码放在这里,以供大家参考。

这里用了一个自创头文件game.h,与两个源文件 game.c和test.c。

game.h里面存放的是test.c文件中所需要的头文件以及对一些函数的声明:

#pragma once
#include<stdio.h>
#include<windows.h>
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
#define set_count 10
#include<time.h>
#include<stdlib.h>
void InitBoard(char board[ROWS][COLS], int rows, int cols,char set);
void DisPlay(char board[ROWS][COLS], int row, int col);
void Set_mine(char ms[ROWS][COLS], int row, int col);
void Findmine(char ms[ROWS][COLS], char dp[ROWS][COLS], int row, int col);

game.c中存放的便是test.c文件中game()函数中所需要的一些自定义函数的实现:

#include"game.h"
void InitBoard(char board[ROWS][COLS], int rows, int cols,char set)
{
	int i = 0;
	int j = 0;	
	for (i = 0; i < ROWS; i++)
	{
		for (j = 0; j < ROWS; j++)
		{
			board[i][j] = set;
		}
	}
	
}
void DisPlay(char board[ROWS][COLS], int row, int col)
{
	int i = 0;
	int j = 0;
	printf("--------扫雷-------\n");
	for (i = 0; i <= ROW; i++)
	{
		printf("%d ", i);
	}
	printf("\n");
	for (i = 1; i <= ROW; i++)
	{
		printf("%d ", i);
		for (j = 1; j <= COL; j++)
		{
			
			printf("%c ", board[i][j]);
		}
		printf("\n");
	}
	printf("-----------------\n");
}
void Set_mine(char ms[ROWS][COLS], int row, int col)
{
	int count = set_count;
	
	while (count)

	{		
		int x = rand() % ROW + 1;
		int y = rand() % COL + 1; 
		if (ms[x][y] == '0')
		{
			ms[x][y] = '1';
			count--;
		}
	}
}

int GetMine(char ms[ROWS][COLS], int x, int y)
{
	return ms[x - 1][y - 1] +
		ms[x - 1][y] +
		ms[x - 1][y + 1] +
		ms[x][x - 1] +
		ms[x][y + 1] +
		ms[x + 1][y - 1] +
		ms[x + 1][y] +
		ms[x + 1][y + 1] - 8 * '0';
		
}
void Disapper(char ms[ROWS][COLS], char dp[ROWS][COLS], int x, int y)
{
	int i = 0;
	int j = 0;
	int c = GetMine(ms, x, y);
	if (ms[x][y] == '0')
	{
		if (c == 0)
		{
			dp[x][y] = ' ';
			for (i = x - 1; i <= x + 1; i++)
			{
				for (j = y - 1; j <= y + 1; j++)
				{
					if (dp[i][j] == '*'&&ms[i][j]!='1')
					{
					Disapper(ms, dp, i, j, c);
					}
				}
			}
		}
		else
		{
			dp[x][y] = c + '0';
		}
	}

}


void Findmine(char ms[ROWS][COLS], char dp[ROWS][COLS], int row, int col)
{
	
	int x = 0;
	int y = 0;
	int win = 0;
	
	while (win<ROW*COL- set_count)
	{
		printf("请输入你要排查雷的坐标\n");
		scanf_s("%d %d", &x, &y);
		system("cls");
		int count = 0;
		if (x >= 1 && x <= ROW && y >= 1 && y <= COL)
		{
			if (ms[x][y] == '1')
			{
				count++;
				if (count == 1 && dp[x][y] == '*' && ms[x][y] == '1')
				{
					ms[x][y] = '0';
					
					
						int a = rand() % ROW + 1;
						int b = rand() % COL + 1;
						if ((a != x || b != y) && ms[a][b] == '0')
						{
							ms[a][b] = '1';
                            DisPlay(dp, ROW, COL);
							continue;
						}
					
				}

				printf("很遗憾,你被炸死了");
				DisPlay(ms,dp, ROW, COL);
				break;
			}
			else
			{
				
				 Disapper(ms,dp, x, y);

				//递归
				
				DisPlay(dp, ROW, COL);
				win++;
				
			}
		}
		else
		{
			printf("输入的坐标非法,请重新输入坐标\n");
		}
	}
	if (win == ROW*COL - set_count)
	{
		printf("恭喜你,排雷成功");
		DisPlay(ms, ROW, COL);

	}
}

test.c中存放的是我们游戏的大概流程:

#include"game.h"
void menu()
{
	printf("****************\n");
	printf("**** 1.play ****\n");
	printf("**** 0.exit ****\n");
	printf("****************\n");
}
void game()
{
	char ms[ROWS][COLS] = { 0 };
	char dp[ROWS][COLS] = { 0 };
	InitBoard(ms, ROWS, COLS, '0');
	InitBoard(dp, ROWS, COLS, '*');
	DisPlay(dp, ROW, COL);
	//放雷
	Set_mine(ms, ROW, COL);
	//DisPlay(ms, ROW, COL);
//排查雷
	Findmine(ms, dp, ROW, COL);

}
int main()
{
	srand((unsigned int)time(NULL));
	int input;
	do
	{
		menu();
		printf("请输入你的选择:>\n");
		scanf_s("%d", &input);
		system("cls");
		switch (input)
		{
		case 1:
			game();
			
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("输入错误,请重新输入\n");
			break;
		}
	} while (input);



	return 0;
}

二、递归展开

代码如下:

void Disapper(char ms[ROWS][COLS], char dp[ROWS][COLS], int x, int y)
{
	int i = 0;
	int j = 0;
	int c = GetMine(ms, x, y);
	if (ms[x][y] == '0')
	{
		if (c == 0)
		{
			dp[x][y] = ' ';
			for (i = x - 1; i <= x + 1; i++)
			{
				for (j = y - 1; j <= y + 1; j++)
				{
					if (dp[i][j] == '*'&&ms[i][j]!='1')
					{
					Disapper(ms, dp, i, j, c);
					}
				}
			}
		}
		else
		{
			dp[x][y] = c + '0';
		}
	}

}

先看扫雷游戏中的展开:

 当我点击一个位置时,这个位置左右直接爆炸性的展开,这是为什么呢?

由图我们可以发现,当我们点开一个位置时,这个位置周围没有雷,这些位置周围也没有雷的时候,就会自动展开。进而再去对它周围雷重复进行这样的操作。

所以我们由此可以知道这个位置展开的首要条件就是:

1、第一个位置不是雷。

2、这个位置周围没有雷。

既然它周围没有雷的时候才会展开,那么反过来说,当它周围有雷的时候这个位置就不会展开咯。

所以当排查到这个位置左右有雷的时候,我们就不会将其展开,而是显示它周围雷的个数。

我们用空格字符来代替展开,当它符合展开条件时,我们就会将这个位置原来的字符替换成空格字符,以表示它已被展开。

运用递归方式做的时候,我们都知道是要给递归一个限制条件的,不然就会成为死循环。那么这里的限制条件是什么呢?

1、这个位置不是空格字符(防止排查其它位置时,重复排查到这个位置,进入死循环)

2、这个地方不是雷

展示:

当我们输入坐标9 1时,可以看到,已经有了爆炸性展开的效果。

三、第一个位置不是雷

在游戏的过程中,第一次输入坐标,一不小心就会第一发就中雷,所以我们编写这一串代码,来防止我们第一次踩雷。

具体内容就是:假如我第一次踩到了雷,那我们就将这个雷换了,换成不是雷,把这颗雷换到另外的地方,并且,这个地方也不能与其它雷的位置重合。

代码如下:

if (count == 1 && dp[x][y] == '*' && ms[x][y] == '1')
				{
					ms[x][y] = '0';
					
					
						int a = rand() % ROW + 1;
						int b = rand() % COL + 1;
						if ((a != x || b != y) && ms[a][b] == '0')
						{
							ms[a][b] = '1';
							DisPlay(dp, ROW, COL);
                            continue;

						}
					
				}

这个代码要放在Findmine函数里,具体位置看我的放在game.c文件中的Findmine()函数。

展示:

 我们先将带雷的棋盘打印出来 方便大家理解

可以看出第一行第三列的位置有一个雷,所以第一次我们输入坐标1 3来查看它是否会将这个雷移除

 可以看出,原先的雷已被移走。

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值