保姆级别的扫雷游戏

一.扫雷游戏的分析和设计

1.扫雷游戏的功能说明

  • 使用控制台实现经典的扫雷游戏

  • 游戏可以通过菜单实现继续玩或者退出游戏

  • 扫雷的棋盘是9*9的格子

  • 默认随机布置10个雷

  • 可以排查雷

  1. 如果位置不是雷,就显示周围有几个雷

  2. 如果位置是雷,就炸死,游戏结束

  3. 把除10个雷之外的所有非雷都找出来,排雷成功,游戏结束

2.数据结构的分析

        扫雷过程中,布置的雷和排查出的雷的信息都需要储存,所以我们需要一定的数据结构来存储这些信息。

2.1.文件结构的设计

text.c//写游戏的测试逻辑
game.c//写游戏中函数的实现等
game.h//写游戏需要的数据结构类型和函数声明等

2.2 为什么需要创建11*11的数组?

       完成一个9*9的扫雷游戏,首先想到的是创建一个9*9的数组。但这里,还需要创建11*11的数组。理由如下:排查雷时,若排查的位置不是雷,就显示周围一圈(8个位置)有几个雷。而当该位置位于坐标的边界时,则会出现越界的情况。为了防止越界,在设计时,给数组扩大一圈,雷还是布置在9*9的坐标上,周围一圈不去布置雷,这样就解决了越界问题。

2.3 为什么要两个棋盘来存放信息?

        在棋盘上布置雷,符号‘1’为雷,符合‘0’为非雷。当我们排查雷时,若某位置不是雷,会返回该位置周围有几个雷,若有一个雷,则返回数字1。此时,若返回的数字1与符号‘1’(雷)在同一个棋盘上,玩家则无法区分它是数字1,还是符号‘1’。因此,需要两个棋盘来存放信息。

因此,需要在game.h文件中,定义行,列和10个雷,来让这3个文件都使用。只有其他两个文件都写上#include"game.h",在game.h文件中声明函数和数据结构类型都通用。

#include其余两个文件就不用加这个头文件了
#define ROW 9//行
#define COL 9//列
#define ROWS ROW+2
#define COLS COL+2
#define EASY_COUNT 10//10个雷

二.扫雷游戏的代码实现

       设计一个扫雷游戏需要初始化棋盘,打印棋盘,布置雷,排查雷。

       首先,建立text.c文件,通过菜单实现继续玩或者退出游戏,使用do while循环实现先选择后判断

(如果不太了解函数传参,可以看博主的这篇文章https://blog.csdn.net/wait___wait/article/details/135047014?spm=1001.2014.3001.5502ss)

(switch语句有些遗忘的,也可以看看博主这篇文章https://blog.csdn.net/wait___wait/article/details/134805824?spm=1001.2014.3001.5501)

main函数

#include"game.h"//自己定义的头文件用“”
void menu()
{
	printf("*******************\n");
	printf("******1.paly*******\n");
	printf("******0.exit*******\n");
	printf("*******************\n");
}
int main()
{
	int input = 0;
	do
	{
		menu();
		printf("请选择:>\n");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
		{
			game();
			break;
		}
		case 0:
		{
			printf("退出游戏\n");
			break;
		}
		default:
		{
			printf("输入不符合规定,请重新选择\n");
			break;
		}
		}

	}while(input);
	return 0;
}

上述代码中涉及game()函数,因而在text.c(游戏的测试逻辑)这个文件中要进行定义。

根据对该游戏的分析和设计,知,game()中要创建两个数组来存放布置好的雷,和排查出雷的信息。

char mine[ROWS][COLS];//存放布置好的雷
char show[ROWS][COLS];//存放排查出雷的信息

初始化棋盘

text.c

数组是11*11,所需棋盘是9*9

//初始化棋盘	,11*11数组
InitBoard(show, ROWS, COLS, '*');//show数组最开始全是‘*’
InitBoard(mine, ROWS, COLS, '0');//mine数组最开始全是‘0’

game.c

//初始化棋盘
void InitBoard(char board[ROWS][COLS],  int rows, int cols, char set)
{
	for (int i = 0; i < rows; i++)
	{
		for (int j = 1; j < cols; j++)//j若初始化为0,后面排查雷时,输入的坐标在棋盘上输出的坐标会不一样

		{
			board[i][j] = set;
		}
	}
}

game.h

void InitBoard(char board[ROWS][COLS], int rows, int cols, char set);//初始化棋盘

运行示例图

保姆级别的扫雷游戏_第1张图片

打印棋盘

text.c

show数组是11*11,但传过去的参数ROW,COL定义为9,因此打印的棋盘是9*9

//打印棋盘
PlayBoard(show, ROW, COL);
//PlayBoard(mine, ROW, COL);//检查‘0’是否设置好

game.h

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

game.c

//打印棋盘
void PlayBoard(char board[ROWS][COLS], int row, int  col)
{
	printf("------扫雷游戏-------\n");
	for (int i = 0; i <= col; i++)//打印列号0-9
	{
		printf("%d|", i);
	}
	printf("\n");
	for (int i = 1; i <= row; i++)
	{
		printf("%d|", i);//打印行号1-9
		
			for (int j = 1; j <= col; j++)
			{
				printf("%c ", board[i][j]);
			}
			printf("\n");
	}
}

运行示例图

保姆级别的扫雷游戏_第2张图片


布置雷

text.c

由于布置雷时需要产生随机数,就要用到rand函数。又因为调用rand函数之前要先调用srand函数,所以在该文件的main函数中使用srand函数,

srand((unsigned int)time(NULL));
//布置雷
SetMine(mine, ROW, COL);
//PlayBoard(mine, ROW, COL);//检查是否成功设置雷

game.h

#include//srand,rand的头文件
#include//time的头文件
void SetMine(char board[ROWS][COLS], int row, int col);//布置雷

game.c

//布置雷
void SetMine(char board[ROWS][COLS], int row, int col)
{
	int x = 0, y = 0;
	int count = EASY_COUNT;
	while (count)
	{
		x=rand() % row + 1;//生成1-9的随机数
		y=rand() % row + 1;//生成1-9的随机数
		if (board[x][y] == '0')//判断该坐标是否是雷,防止重设置,导致雷的个数少于10
		{
			board[x][y] = '1';
			count--;//每设置一个雷,count-1。直到10个雷设置完成,count=0,跳出while循环
		}
	}
}

运行实例,显示雷的位置需要把text.c文件中的PlayBoard取消注销 

保姆级别的扫雷游戏_第3张图片

排雷

text.c

FindMine(show, mine, ROW, COL);

game.h

void FindMine(char show[ROWS][COLS], char[ROWS][COLS], int row, int col);//排雷

 game.c

//排雷
//如果位置不是雷,就显示周围有几个雷
//如果位置是雷,就炸死,游戏结束
//把十个雷之外的所有雷都找出来,排雷成功,游戏结束
void FindMine(char show[ROWS][COLS], char mine[ROWS][COLS], int row, int col)
{
	int x = 0, y = 0;	
	int win = 0;//排查次数
	while (win < row*col-EASY_COUNT)//确保win=71之后,不再继续,因为之后排查的一定是炸弹
	{    
        printf("请输入你要排查的坐标\n");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= 9 && y >= 1 && y <= 9)
		{
			if (mine[x][y] == '1')
			{
				printf("很遗憾,你被炸死了\n");
				PlayBoard(mine, row, col);
				break;
			}
			else
			{
				int count = GetMineCount(mine, x, y);//统计雷坐标周围雷的个数
				show[x][y] = count + '0';
				PlayBoard(show, row, col);
                win ++;
			}
		}
		else
		{
			printf("坐标非法,请重新输入\n");
		}
		
	}
	if (win == col * row - EASY_COUNT)
	{
		printf("恭喜你,排雷成功\n");
		PlayBoard(mine, row, col);
	}
	printf("是否继续游戏?\n");
}

计算周围雷的个数 

//计算周围雷的个数
int GetMineCount(char mine[ROWS][COLS], int x, int y)
{
	int i = 0;
	int j = 0;
	int count = 0;
	for (i = x - 1; i <= x + 1; i++)
	{
		for (j = y - 1; j <= y + 1; j++)
		{
			count += (mine[x][y] - '0');//mine[x][y]-'0'得到的是整数
		}
	}
	return count;
}

 mine数组里面的元素是字符型,‘0’也是字符,两个字符相减,得到的是整型数字。

完整代码

text.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
void menu()
{
	printf("*******************\n");
	printf("******1.paly*******\n");
	printf("******0.exit*******\n");
	printf("*******************\n");
}
void game()
{
	char show[ROWS][COLS] = { 0 };//全部设为‘*’
	char mine[ROWS][COLS] = { 0 };//全部设为‘0’
	//初始化棋盘
	InitBoard(show, ROWS, COLS, '*');
	InitBoard(mine, ROWS, COLS, '0');
	//打印棋盘
	PlayBoard(show, ROW, COL);
	//PlayBoard(mine, ROW, COL);
	//布置雷‘1'为雷,‘0’非雷
	SetMine(mine, ROW, COL);
	//PlayBoard(mine, ROW, COL);//检查是否成功设置雷
	//排雷
	FindMine(show, mine, ROW, COL);
}
int main()
{
	int input = 0;
	srand((unsigned int)time(NULL));
	do
	{
		menu();
		printf("请选择:>\n");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
		{
			game();
			break;
		}
		case 0:
		{
			printf("退出游戏\n");
			break;
		}
		default:
		{
			printf("请重新选择\n");
			break;
		}
		}

	}while(input);
	return 0;
}

game.h

#include
#include//srand,rand的头文件
#include//time的头文件


#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
#define EASY_COUNT 10//10个雷

void InitBoard(char board[ROWS][COLS], int rows, int cols, char set);//初始化棋盘
void PlayBoard(char board[ROWS][COLS], int row, int col);//打印棋盘
void SetMine(char board[ROWS][COLS], int row, int col);//布置雷
void FindMine(char show[ROWS][COLS], char[ROWS][COLS], int row, int col);//排雷

game.c

#include"game.h"

//初始化棋盘
void InitBoard(char board[ROWS][COLS],  int rows, int cols, char set)
{
	for (int i = 0; i < rows; i++)
	{
		for (int j = 0; j < cols; j++)
		{
			board[i][j] = set;
		}
	}
}
//打印棋盘
void PlayBoard(char board[ROWS][COLS], int row, int  col)
{
	printf("------扫雷游戏-------\n");
	for (int i = 0; i <= col; i++)//打印列号0-10
	{
		printf("%d|", i);
	}
	printf("\n");
	for (int i = 1; i <= row; i++)
	{
		printf("%d|", i);//打印行号1-9
		
			for (int j = 1; j <= col; j++)//j若初始化为0,棋盘就是9*10,而非9*9
			{
				printf("%c ", board[i][j]);
			}
			printf("\n");
	}
}
//布置雷
void SetMine(char board[ROWS][COLS], int row, int col)
{
	int x = 0, y = 0;
	int count = EASY_COUNT;
	while (count)
	{
		x=rand() % row + 1;//生成1-9的随机数
		y=rand() % row + 1;//生成1-9的随机数
		if (board[x][y] == '0')//判断该坐标是否是雷,防止重设置,导致雷的个数少于10
		{
			board[x][y] = '1';
			count--;//每设置一个雷,count-1。直到10个雷设置完成,count=0,跳出while循环
		}
	}
}
//排雷
//如果位置不是雷,就显示周围有几个雷
//如果位置是雷,就炸死,游戏结束
//把十个雷之外的所有雷都找出来,排雷成功,游戏结束
int GetMineCount(char mine[ROWS][COLS], int x, int y)
{
	int i = 0;
	int j = 0;
	int count = 0;
	for (i = x - 1; i <= x + 1; i++)
	{
		for (j = y - 1; j <= y + 1; j++)
		{
			count += (mine[x][y] - '0');
		}
	}
	return count;
}
void FindMine(char show[ROWS][COLS], char mine[ROWS][COLS], int row, int col)
{
	int x = 0, y = 0;	
	int win = 0;
	while (win < row*col-EASY_COUNT)
	{
		printf("请输入你要排查的坐标\n");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= 9 && y >= 1 && y <= 9)
		{
			if (mine[x][y] == '1')
			{
				printf("很遗憾,你被炸死了\n");
				PlayBoard(mine, row, col);
				break;
			}
			else
			{
				int count = GetMineCount(mine, x, y);//统计雷的坐标
				show[x][y] = count + '0';
				PlayBoard(show, row, col);
				win++;
			}
		}
		else
		{
			printf("坐标非法,请重新输入\n");
		}
		
	}
	if (win == col * row - EASY_COUNT)
	{
		printf("恭喜你,排雷成功\n");
		PlayBoard(mine, row, col);
	}
	printf("是否继续游戏?\n");
}

运行示例

保姆级别的扫雷游戏_第4张图片

小tip 

1

保姆级别的扫雷游戏_第5张图片

这个是因为打印棋盘时,game.c文件中,第三个for循环里,j初始化为0,导致输入(4,5)坐标,得到(4,6)坐标,所以,要注意自己变量赋值。(并且这个是9*10棋盘,不知道当时怎么没看出来,哈哈)

2

 show,mine数组是11*11,但传过去的参数ROW,COL定义为9,因此打印的棋盘是9*9

3

建议写完一个模块,运行一个,好纠错。

​​​​​​​

欢迎斧正!!!

(听说公主,王子们都有一个好习惯,那就是

你可能感兴趣的:(C语言,c语言,游戏)