纯净、安全、绿色的下载网站

首页|软件分类|下载排行|最新软件|IT学院

当前位置:首页IT学院IT技术

c语言实现扫雷 c语言实现含递归清场版扫雷游戏

Shany-Ming   2021-11-21 我要评论
想了解c语言实现含递归清场版扫雷游戏的相关内容吗Shany-Ming在本文为您仔细讲解c语言实现扫雷的相关知识和一些Code实例欢迎阅读和指正我们先划重点:C语言实现扫雷游戏完整代码,c语言编写扫雷,c语言扫雷源代码下面大家一起来学习吧

一设计思路

想必大家都玩过扫雷

 这便是一个标准的扫雷换做代码实现我们需要考虑以下几点:

1.棋盘的设计与初始化

2.在棋盘中放入雷

3.统计雷数

4.如何实现“一片”的效果

5.输赢的判断

接下来我们进行具体操作

二.实现方式

1.菜单的打印

对任意一个游戏菜单是必不可少的也是最简单的部分直接上代码

void menu()
{
	printf("------------------扫雷------------------\n");
	printf("---------------1.开始游戏---------------\n");
	printf("---------------0.退出游戏---------------\n");
}
int main()
{
	srand((unsigned int)time(NULL));
	int a = 0;
	do
	{
		menu();
		scanf("%d", &a);
		if (a == 0)
		{
			break;
		}
		game();
	} while (a);
	return 0;
}

其中srand是为了求随机值用来布置雷

2.game函数

主菜单完后进入game函数在game函数里我们就要开始主要的游戏部分如棋盘初始化与打印等当然这些步骤都依靠函数完成game函数只相当于集合了一系列的游戏模块

void game()
{
	char mine[ROWS][COLS];
	char show[ROWS][COLS];
	initeboard(mine, ROWS, COLS, '0');
	initeboard(show, ROWS, COLS, '*');//初始棋盘
	displayboard(show, ROW, COL);//打印棋盘
	mine_make(mine, ROW, COL);//设置雷
	//displayboard(mine, ROW, COL);
	find_mine(mine, show, ROWS, COLS);//排查雷
 
}

3.棋盘的初始化与打印

可以看到我在game函数里初始了两个棋盘,为什么要两个呢?

其实一个是为了放置了雷一个为了展示给玩家为什么不用一个呢我们要在放雷处用'1',表示不放雷处用‘0'这样计算一个坐标周围雷的数量就会更简单接下来看一段代码:

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define ROW 10
#define COL 10
#define ROWS ROW+2
#define COLS COL+2

这里我们看到定义了一个ROWS和COLS这又是为何呢?

回归棋盘

 扫雷时当你确认一个点时它会对此点周围的八个点进行排查看是否有泪当坐标位于红线处时没有无法判断八个因此有了ROWS与COLS这时有人就会问了:那埋雷的地方用ROW COL就可以了还不用担心雷跑到外边我们加的框想法很好但我们有两个棋盘必须对应而且也不存在跑出雷的情况往下分析你就会知道

void initeboard(char board[ROWS][COLS], int cols, int rows,char s)//棋盘初始化此处用了个节省步骤的方法不用两个棋盘依次初始化
{
	int i = 0;
	int j = 0;
	for (i = 0; i < rows; i++)
	{
		for (j = 0; j < cols; j++)
		{
			board[i][j] = s;
		}
	}
}
void displayboard(char board[ROWS][COLS], int row, int col)//棋盘打印
{
	int i = 0;
	int j = 0;
	printf(" ");//与行中打印的0%d对应
	for (j = 0; j <=col; j++)
	{
		printf(" %d  ", j);
	}
	printf("\n");
	printf("-");
	for (j = 1; j <= col + 1; j++)
	{
		printf("---");
		printf("|");
	}
	printf("\n");//列对应打印完成
	for (i = 1; i <= row; i++)
	{
		if (i <= 9)
		{
			printf(" 0%d ", i);
		}
		else
		printf(" %d ", i);
		printf("|");
		for (j = 1; j <= col; j++)
		{
			printf(" %c ", board[i][j]);
			printf("|");
		}
		printf("\n");
		printf("-");
		for (j = 1; j <= col+1; j++)
		{
			printf("---");
			printf("|");
		}
		printf("\n");//行对应嵌套在内部 打印的数前加0是为了让当行数大于9时能够对应 如09与10
	}
}

棋盘的打印做了行列对应所以可能有点不明显

 4.雷的放置雷的个数

雷的放置很简单在棋盘‘0'处放置就行因为我们对随机数的算式使随机数只会出现在0-9没有跑出的情况

mine_make(char mine[ROWS][COLS], int row, int col)//设置雷
{
	int count = 10;
	while (count)
	{
		int x = rand() % 10;
		int y = rand() % 10;
		if (mine[x][y] == '0')
		{
			mine[x][y] = '1';
			count--;
		}
	}
}

雷的个数就需要一定考虑了:

首先我们需要把周围八个位置是否有雷有多少个雷判断出来这时我们设计‘0' ‘1'类型就排上用场了但是注意这是字符不是数字

ASCII码表

 一张表 让我们知道如何转型

当然返回的数字记得转成字符类型

int get_mine(char mine[ROWS][COLS], int i, int j)//得到一个坐标附近雷的个数
{
	return mine[i - 1][j - 1] + mine[i - 1][j] + mine[i - 1][j + 1] +
		mine[i][j - 1] + mine[i][j + 1] +
		mine[i + 1][j - 1] + mine[i +1 ][j] + mine[i + 1][j + 1] - 8 * '0';//此处我们的数字其实是字符用此方法可以转为数字整形
}

5.递归实现一片效果

当不为雷是会展开附近一片不为雷提高游戏效率

void spread(char show[ROWS][COLS], char mine[ROWS][COLS], int x, int y)//递归方法实现一大片
{
	show[x][y] = ' ';//先让输入金的坐标处变为空格因为已经判定过雷所以可以直接转空格
	int i = 0;
	int j = 0;
	int ret = 0;
	for (i = x - 1; i <= x + 1; i++)
	{
		for (j = y - 1; j <= y + 1; j++)//嵌套for循环表示输入坐标包括自生及周围八个
		{
			if (i > 0 && i <= ROW && j > 0 && j <= COL && mine[i][j] != '1' && show[i][j] == '*')//防止出现负坐标避免有雷避免输入重复
			{
				ret = get_mine(mine, i, j);//判断ret是0或非0并得出周围雷数
				if (!ret)//如果ret=0!ret便是非0为真
				{
					spread(show, mine, i, j);//递归
				}
				if (ret)//ret!=0时为真便打印数
				{
					show[i][j] = ret + '0';//使数字转成对应字符
				}
			}
 
		}
	}
}

效果展示:

 6.排查雷

负责判断是否被炸死及游戏胜利

void find_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)//排查雷
{
	printf("请输入坐标\n");
	int i = 0;
	int j = 0;
	int win = 0;
	while (row*col-10)//因为是十个雷所以是—10因为下总数减10就赢了所以可以以此跳出循环当然要是雷部位10定一个变量就行此处就不改了
	{
		scanf("%d %d", &i, &j);
		if (mine[i][j] == '1')
		{
			printf("你挂了\n");
			displayboard(mine, ROW, COL);
			break;
		}
		else
		{
			show[i][j] = get_mine(mine, i, j)+'0';
			spread(show,mine, i, j);
			displayboard(show, ROW, COL);
			win++;
		}		
	}
	if (win ==row * col - 10)
	{
		printf("恭喜你成功了\n");
		displayboard(mine, ROW, COL);
	}
}

具体注释都在代码里了

正常情况把打印雷盘注释就行就可以正常游戏了

 三.完整代码

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define ROW 10
#define COL 10
#define ROWS ROW+2
#define COLS COL+2
void menu()
{
	printf("------------------扫雷------------------\n");
	printf("---------------1.开始游戏---------------\n");
	printf("---------------0.退出游戏---------------\n");
}
void initeboard(char board[ROWS][COLS], int cols, int rows,char s)//棋盘初始化此处用了个节省步骤的方法不用两个棋盘依次初始化
{
	int i = 0;
	int j = 0;
	for (i = 0; i < rows; i++)
	{
		for (j = 0; j < cols; j++)
		{
			board[i][j] = s;
		}
	}
}
void displayboard(char board[ROWS][COLS], int row, int col)//棋盘打印
{
	int i = 0;
	int j = 0;
	printf(" ");//与行中打印的0%d对应
	for (j = 0; j <=col; j++)
	{
		printf(" %d  ", j);
	}
	printf("\n");
	printf("-");
	for (j = 1; j <= col + 1; j++)
	{
		printf("---");
		printf("|");
	}
	printf("\n");//列对应打印完成
	for (i = 1; i <= row; i++)
	{
		if (i <= 9)
		{
			printf(" 0%d ", i);
		}
		else
		printf(" %d ", i);
		printf("|");
		for (j = 1; j <= col; j++)
		{
			printf(" %c ", board[i][j]);
			printf("|");
		}
		printf("\n");
		printf("-");
		for (j = 1; j <= col+1; j++)
		{
			printf("---");
			printf("|");
		}
		printf("\n");//行对应嵌套在内部 打印的数前加0是为了让当行数大于9时能够对应 如09与10
	}
}
mine_make(char mine[ROWS][COLS], int row, int col)//设置雷
{
	int count = 10;
	while (count)
	{
		int x = rand() % 10;
		int y = rand() % 10;
		if (mine[x][y] == '0')
		{
			mine[x][y] = '1';
			count--;
		}
	}
}
int get_mine(char mine[ROWS][COLS], int i, int j)//得到一个坐标附近雷的个数
{
	return mine[i - 1][j - 1] + mine[i - 1][j] + mine[i - 1][j + 1] +
		mine[i][j - 1] + mine[i][j + 1] +
		mine[i + 1][j - 1] + mine[i +1 ][j] + mine[i + 1][j + 1] - 8 * '0';//此处我们的数字其实是字符用此方法可以转为数字整形
}
void spread(char show[ROWS][COLS], char mine[ROWS][COLS], int x, int y)//递归方法实现一大片
{
	show[x][y] = ' ';//先让输入金的坐标处变为空格因为已经判定过雷所以可以直接转空格
	int i = 0;
	int j = 0;
	int ret = 0;
	for (i = x - 1; i <= x + 1; i++)
	{
		for (j = y - 1; j <= y + 1; j++)//嵌套for循环表示输入坐标包括自生及周围八个
		{
			if (i > 0 && i <= ROW && j > 0 && j <= COL && mine[i][j] != '1' && show[i][j] == '*')//防止出现负坐标避免有雷避免输入重复
			{
				ret = get_mine(mine, i, j);//判断ret是0或非0并得出周围雷数
				if (!ret)//如果ret=0!ret便是非0为真
				{
					spread(show, mine, i, j);//递归
				}
				if (ret)//ret!=0时为真便打印数
				{
					show[i][j] = ret + '0';//使数字转成对应字符
				}
			}
 
		}
	}
}
void find_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)//排查雷
{
	printf("请输入坐标\n");
	int i = 0;
	int j = 0;
	int win = 0;
	while (row*col-10)//因为是十个雷所以是—10因为下总数减10就赢了所以可以以此跳出循环当然要是雷部位10定一个变量就行此处就不改了
	{
		scanf("%d %d", &i, &j);
		if (mine[i][j] == '1')
		{
			printf("你挂了\n");
			displayboard(mine, ROW, COL);
			break;
		}
		else
		{
			show[i][j] = get_mine(mine, i, j)+'0';
			spread(show,mine, i, j);
			displayboard(show, ROW, COL);
			win++;
		}		
	}
	if (win ==row * col - 10)
	{
		printf("恭喜你成功了\n");
		displayboard(mine, ROW, COL);
	}
}
void game()
{
	char mine[ROWS][COLS];
	char show[ROWS][COLS];
	initeboard(mine, ROWS, COLS, '0');
	initeboard(show, ROWS, COLS, '*');//初始棋盘
	displayboard(show, ROW, COL);//打印棋盘
	mine_make(mine, ROW, COL);//设置雷
	displayboard(mine, ROW, COL);
	find_mine(mine, show, ROWS, COLS);//排查雷
 
}
int main()
{
	srand((unsigned int)time(NULL));
	int a = 0;
	do
	{
		menu();
		scanf("%d", &a);
		if (a == 0)
		{
			break;
		}
		game();
	} while (a);
	return 0;
}
    

总结


相关文章

猜您喜欢

  • Vue之组件 Vue之组件详解

    想了解Vue之组件详解的相关内容吗王同学要努力在本文为您仔细讲解Vue之组件的相关知识和一些Code实例欢迎阅读和指正我们先划重点:Vue详解,Vue组件下面大家一起来学习吧..
  • Vue之生命周期函数 Vue之生命周期函数详解

    想了解Vue之生命周期函数详解的相关内容吗王同学要努力在本文为您仔细讲解Vue之生命周期函数的相关知识和一些Code实例欢迎阅读和指正我们先划重点:Vue详解,Vue生命周期,Vue函数下面大家一起来学习吧..

网友评论

Copyright 2020 www.fresh-weather.com 【世纪下载站】 版权所有 软件发布

声明:所有软件和文章来自软件开发商或者作者 如有异议 请与本站联系 点此查看联系方式