【C语言/入门游戏】扫雷完整版(包含标记,安全保护及展开)

知识提要(自主编写游戏所需要的知识):

1.函数的基本实现;

2.二维数组;

目录

扫雷

1.基本界面的实现

2.初始化棋盘(二维数组)

3.棋盘的打印

4.布置雷

5.安全保护

6.雷数显示

7.排查雷

8.标记雷

9.展开

10.难度设置

11.全局代码


扫雷

效果图:

 从以上效果图中可见,我们需要实现的功能有:

1.随机埋雷

2.显示雷数

3.展开

4.标记

5.判定输赢

如果将雷,数字,和*同时放在一个数组里是不现实的,因为如果一个格子中已经放了雷,就不可能将其变为星号显示,所以我们得到一个大体思路,要用两个数组,一个埋雷,一个显示。

还是老规矩,创建3个文件

game.h先引用和定义必要的数据

# define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define ROW 9
#define COL 9

#define ROWS ROW+2
#define COLS COL+2

#define EASY_COUNT 10

这次我们用'*'当作未知量,'#'为标记,'1'为雷,'0'为非雷(此处为一个伏笔)

1.基本界面的实现

这一部分比较简单,所以就只简单提一句

void menu()
{
	printf("*********************************\n");
	printf("*********    1. Play    *********\n");
	printf("*********    0. Exit    *********\n");
	printf("*********************************\n");
	
}

void game()
{
	char mine[ROWS][COLS] = { 0 };//存放雷的信息
	char show[ROWS][COLS] = { 0 };//展示给玩家的棋盘
	intialize(mine,ROWS ,COLS,'0');
	intialize(show,ROWS ,COLS,'*');
	//展示棋盘
	print(show, ROW, COL);
	
	//布置雷
	setmine(mine, ROW, COL);
	
	//排查
	search(mine, show, ROW, COL,0);



}

int main()
{
	int input = 0;
	srand((unsigned int)time(NULL));
	do
	{
		menu();
		printf("请选择>:");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			printf("game start\n");
			game();
			break;
		case 0:
			printf("已退出游戏\n");
			break;
		default:
			printf("选择错误,请重新选择\n");
			break;
		}

	} while (input);
	return 0;
}

这里可能有人要问,为什么要创建11*11的数组呢?

如果我们要在9*9的棋盘中找寻雷的个数,那么就得找寻周围8个元素,但是如果要找边边角角的格子附件雷的个数,就涉及到数组越界的问题,不太好办。所以我们将数组做大一圈,保证数组访问不会越界

2.初始化棋盘(二维数组)

现在我们要考虑一个问题,这次我们有两个二维数组要初始化,而且其中内容也不同,那该怎么办呢?

其实也比较简单,只需要让初始化函数多接受一个需要初始化的量就可以了

void intialize(char board[ROWS][COLS], int row, int col, char target)
{
	int i = 0;
	for (i = 0; i < row; i++)
	{
		int j = 0;
		for (j = 0; j < col; j++)
		{
			board[i][j] = target;

		}
	}

}

这样就可以完成不同的初始化了

3.棋盘的打印

由于扫雷需要的棋盘比较大,为了方便游玩,这次还需要打印行列号

void print(char board[ROWS][COLS], int row, int col)
{
	int i = 0;
	for (i = 0; i <= row; i++)//打印列号
	{
		printf("%d ", i);
	}
	printf("\n");
	for (i = 1; i <= row; i++)
	{
		int j = 0;
		printf("%d ", i);//打印行号
		for (j = 1; j <= col; j++)
		{
			printf("%c ", board[i][j]);
		}
		printf("\n");
	}
}

效果图:

4.布置雷

布置雷就牵扯到随机数的问题,要保证雷不会重复布置且只在9*9的棋盘中布置

void setmine(char board[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	int count = 0;
	while (1)//未布置满就一直循环
	{
		x = rand() % row + 1;//使x,y在1~9间,保证数组不越界布置
		y = rand() % col + 1;
		if (board[x][y] != '1')//保证布置的雷不重复
		{
			board[x][y] = '1';
			count++;
		}
		if (count == EASY_COUNT)//布置满所有不重复的雷后才可跳出循环
			break;
	}

}

5.安全保护

为了防止第一次排查就猝死,提高游戏体验所以我们需要设计一下,让玩家如果第一次就踩雷,棋盘会重置,直到此处没有雷

first_die++;
if (first_die == 1 && mine[x][y] == '1')//first_die在test中创建,默认传递0进入
		{
			while (mine[x][y] == '1')
			{
				intialize(mine, ROWS, COLS, '0');//必须先初始化棋盘,不然会导致原本的雷依然在
				setmine(mine, ROW, COL);
			}
			
		}

6.雷数显示

int search_show(char mine[ROWS][COLS], int x, int y)
{
	return (mine[x - 1][y] +
		mine[x - 1][y - 1] +
		mine[x][y - 1] +
		mine[x + 1][y - 1] +
		mine[x + 1][y] +
		mine[x + 1][y + 1] +
		mine[x][y + 1] +
		mine[x - 1][y + 1] - 8 * '0');
}

'0'的ASCII值为48,我们将雷设计为'1'就是为了方便相加以后减去8个'0',直接就可以得到雷的数量

7.排查雷

下面就是本文章的重点之一,雷的排查,其实实现思路也比较简单,如果踩到雷,游戏结束;如果没有,继续游戏,同时显示附近雷的个数


	int x = 0;
	int y = 0;
	

	

	while (1)
	{
		printf("请输入需要排查的坐标,如:1 1\n");
		scanf("%d%d", &x, &y);
		first_die++;

		

		if (x >= 1 && x <= row && y >= 1 && y <= col)//判断输入的行列号是否在规定范围
		{
			if (mine[x][y] == '1')
			{
				printf("你死了,请再接再厉\n");
				print(mine, ROW, COL);
				break;
			}
			else
			{
				show[x][y] = search_show(mine, ROW, COL)+'0';//显示周围的雷数
				open(mine,show, x, y,row,col);
				print(show, ROW, COL);
				

			}
		}
		else
		{
			printf("输入错误,请重新输入\n");
		}

8.标记雷

我们可以在排查以后加入一个标记功能,我们规定用'#'标记,同时只能标记未知量

//标记地雷
		int input1 = 0;
		int input2 = 0;

		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{

			do//至少要运行一次
			{
				printf("请输入标记坐标,输入0 0退出标记\n");
				scanf("%d%d", &input1, &input2);

				if (input1 >= 1 && input1 <= row && input2 >= 1 && input2 <= col)
				{
					if (show[input1][input2] == '*')//只标记未知量
					{
						show[input1][input2] = '#';
						print(show, ROW, COL);
					}
					else
					{
						printf("标记失败,请重新标记\n");
					}
				}
				else if (input1 == 0 && input2 == 0)//输入0 0退出标记
					break;
				else
				{
					printf("标记错误,请重新标记\n");
				}

			} while (input1&&input2);
			printf("已退出标记\n");
		}

9.展开

这应该是最难实现的一部分,这里我们用到递归的思想

void open(char mine[ROWS][COLS],char show[ROWS][COLS], int x, int y,int row ,int col)
{
	int ret = 0;
	ret =search_show(mine,x,y);
	
	if (ret == 0)//如果周围无雷,判断展开
	{
		show[x][y] = ' ';//防止死递归,如果不将show[x][y]变为' ',则下一次检测可能又会是*,再次进入递归,直至卡死。
		if (x - 1 > 0 && y > 0 && show[x - 1][y] == '*'|| show[x - 1][y] == '#')
			open(mine, show, x - 1, y, row, col);
		if (x - 1 > 0 && y + 1 <= col && show[x - 1][y + 1] == '*'|| show[x - 1][y + 1] == '#')
			open(mine, show, x - 1, y + 1, row, col);
		if (x > 0 && y + 1 <= col && show[x][y + 1] == '*'|| show[x][y + 1] == '#')
			open(mine, show, x, y + 1, row, col);
		if (x + 1 <= row && y + 1 <= col && show[x + 1][y + 1] == '*'|| show[x + 1][y + 1] == '#')
			open(mine, show, x + 1, y + 1, row, col);
		if (x + 1 <= row && y > 0 && show[x + 1][y] == '*'|| show[x + 1][y] == '#')
			open(mine, show, x + 1, y, row, col);
		if (x + 1 <= row && y - 1 > 0 && show[x + 1][y - 1] == '*'|| show[x + 1][y - 1] == '#')
			open(mine, show, x + 1, y - 1, row, col);
		if (x > 0 && y - 1 > 0 && show[x][y - 1] == '*'|| show[x][y - 1] == '#')
			open(mine, show, x, y - 1, row, col);
		if (x - 1 > 0 && y - 1 > 0 && show[x - 1][y - 1] == '*'|| show[x - 1][y - 1] == '#')
			open(mine, show, x - 1, y - 1, row, col);
		
	}
	else//有雷则返回雷数
	{
		return show[x][y]=search_show(mine, x, y)+'0';
	}

}

10.难度设置

其实实现思路比较简单,可以再设置MIDDLE_COUNT和HARD_COUNT。

传参时,将难度数字也传进去即可

这里交给大家去自行实现,不算难

11.全局代码

game.h

# define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define ROW 9
#define COL 9

#define ROWS ROW+2
#define COLS COL+2

#define EASY_COUNT 10

//初始化
void intialize(char board[ROWS][COLS], int row, int col, char target);

//打印棋盘
void print(char board[ROWS][COLS], int row, int col);

//布置雷
void setmine(char board[ROWS][COLS], int row, int col);

//排查雷
void search(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col,int


game.c

# define _CRT_SECURE_NO_WARNINGS
# include "game.h"

void intialize(char board[ROWS][COLS], int row, int col, char target)
{
	int i = 0;
	for (i = 0; i < row; i++)
	{
		int j = 0;
		for (j = 0; j < col; j++)
		{
			board[i][j] = target;

		}
	}

}

void print(char board[ROWS][COLS], int row, int col)
{
	int i = 0;
	for (i = 0; i <= row; i++)
	{
		printf("%d ", i);
	}
	printf("\n");
	for (i = 1; i <= row; i++)
	{
		int j = 0;
		printf("%d ", i);
		for (j = 1; j <= col; j++)
		{
			printf("%c ", board[i][j]);
		}
		printf("\n");
	}
}

void setmine(char board[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	int count = 0;
	while (1)
	{
		x = rand() % row + 1;
		y = rand() % col + 1;
		if (board[x][y] != '1')
		{
			board[x][y] = '1';
			count++;
		}
		if (count == EASY_COUNT)
			break;
	}

}



int search_show(char mine[ROWS][COLS], int x, int y)
{
	return (mine[x - 1][y] +
		mine[x - 1][y - 1] +
		mine[x][y - 1] +
		mine[x + 1][y - 1] +
		mine[x + 1][y] +
		mine[x + 1][y + 1] +
		mine[x][y + 1] +
		mine[x - 1][y + 1] - 8 * '0');
}

void open(char mine[ROWS][COLS],char show[ROWS][COLS], int x, int y,int row ,int col)
{
	int ret = 0;
	ret =search_show(mine,x,y);
	
	if (ret == 0)//如果周围无雷,判断展开
	{
		show[x][y] = ' ';//防止死递归,如果不将show[x][y]变为' ',则下一次检测可能又会是*,再次进入递归,直至卡死。
		if (x - 1 > 0 && y > 0 && show[x - 1][y] == '*'|| show[x - 1][y] == '#')
			open(mine, show, x - 1, y, row, col);
		if (x - 1 > 0 && y + 1 <= col && show[x - 1][y + 1] == '*'|| show[x - 1][y + 1] == '#')
			open(mine, show, x - 1, y + 1, row, col);
		if (x > 0 && y + 1 <= col && show[x][y + 1] == '*'|| show[x][y + 1] == '#')
			open(mine, show, x, y + 1, row, col);
		if (x + 1 <= row && y + 1 <= col && show[x + 1][y + 1] == '*'|| show[x + 1][y + 1] == '#')
			open(mine, show, x + 1, y + 1, row, col);
		if (x + 1 <= row && y > 0 && show[x + 1][y] == '*'|| show[x + 1][y] == '#')
			open(mine, show, x + 1, y, row, col);
		if (x + 1 <= row && y - 1 > 0 && show[x + 1][y - 1] == '*'|| show[x + 1][y - 1] == '#')
			open(mine, show, x + 1, y - 1, row, col);
		if (x > 0 && y - 1 > 0 && show[x][y - 1] == '*'|| show[x][y - 1] == '#')
			open(mine, show, x, y - 1, row, col);
		if (x - 1 > 0 && y - 1 > 0 && show[x - 1][y - 1] == '*'|| show[x - 1][y - 1] == '#')
			open(mine, show, x - 1, y - 1, row, col);
		
	}
	else
	{
		return show[x][y]=search_show(mine, x, y)+'0';
	}

}

int win(char show[ROWS][COLS], int row, int col)
{
	int i = 0;
	int j = 0;
	int count = 0;
	for (i = 1; i <= row; i++)
	{
		for (j = 1; j <= col; j++)
		{
			if (show[i][j] == '*'||show[i][j]=='#')
				count++;
		}

	}
	if (count == EASY_COUNT)
		return 1;
	else
		return 0;
}

void search(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col, int first_die)
{
	int x = 0;
	int y = 0;
	

	

	while (1)
	{
		printf("请输入需要排查的坐标,如:1 1\n");
		scanf("%d%d", &x, &y);
		first_die++;

		
		//防止第一次暴毙
		if (first_die == 1 && mine[x][y] == '1')
		{
			while (mine[x][y] == '1')
			{
				intialize(mine, ROWS, COLS, '0');
				setmine(mine, ROW, COL);
			}
			
		}

		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			if (mine[x][y] == '1')
			{
				printf("你死了,请再接再厉\n");
				print(mine, ROW, COL);
				break;
			}
			else
			{
				show[x][y] = search_show(mine, ROW, COL)+'0';//显示周围的雷数
				open(mine,show, x, y,row,col);
				print(show, ROW, COL);
				

			}
		}
		else
		{
			printf("输入错误,请重新输入\n");
		}
		
		//判断输赢
		int Win = win(show, row, col);
		if (Win == 1)
		{
			printf("恭喜您,胜利了\n");
			break;
		}

		//标记地雷
		int input1 = 0;
		int input2 = 0;

		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{

			do
			{
				printf("请输入标记坐标,输入0 0退出标记\n");
				scanf("%d%d", &input1, &input2);

				if (input1 >= 1 && input1 <= row && input2 >= 1 && input2 <= col)
				{
					if (show[input1][input2] == '*')
					{
						show[input1][input2] = '#';
						print(show, ROW, COL);
					}
					else
					{
						printf("标记失败,请重新标记\n");
					}
				}
				else if (input1 == 0 && input2 == 0)
					break;
				else
				{
					printf("标记错误,请重新标记\n");
				}

			} while (input1&&input2);
			printf("已退出标记\n");
		}
	}
}


test.c

# define _CRT_SECURE_NO_WARNINGS
# include "game.h"

void menu()
{
	printf("*********************************\n");
	printf("*********    1. Play    *********\n");
	printf("*********    0. Exit    *********\n");
	printf("*********************************\n");
	
}

void game()
{
	char mine[ROWS][COLS] = { 0 };//存放雷的信息
	char show[ROWS][COLS] = { 0 };//存放排查出的雷的信息
	intialize(mine,ROWS ,COLS,'0');
	intialize(show,ROWS ,COLS,'*');
	//展示棋盘
	print(show, ROW, COL);
	
	//布置雷
	setmine(mine, ROW, COL);
	
	//排查
	search(mine, show, ROW, COL,0);



}

int main()
{
	int input = 0;
	srand((unsigned int)time(NULL));
	do
	{
		menu();
		printf("请选择>:");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			printf("game start\n");
			game();
			break;
		case 0:
			printf("已退出游戏\n");
			break;
		default:
			printf("选择错误,请重新选择\n");
			break;
		}

	} while (input);
	return 0;
}

以上就是本次的分享内容了,喜欢我的分享的话,别忘了点赞加关注哟!

如果你对我的文章有任何看法,欢迎在下方评论留言或者私信我鸭!

我是白晨,我们下次分享见!!

猜你喜欢

转载自blog.csdn.net/baichendada/article/details/120633765