保姆级教学—扫雷游戏的实现

扫雷的目录

  • 扫雷
    • 游戏选择
    • 初始化棋盘
    • 布置雷
    • 打印棋盘
    • 排查雷
    • 完整代码呈现
  • 结尾

扫雷

整个游戏的实现分为五个部分:

  • 游戏选择
  • 初始化棋盘
  • 布置雷
  • 打印棋盘
  • 排查雷

在文章的最后会有完整的代码呈现

游戏选择

首先是游戏选择部分,你可以在此选择是否开始游戏

且每当结束一把对局,也会回到该界面,再次进行选择

void menu()
{
	printf("                           \n");
	printf("          1.paly           \n");
	printf("          0.exit           \n");
	printf("                           \n");

}

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

	return 0;
}

这里我们用do…while语句配合switch…case语句,实现游戏选择的基本功能

如果对方输入“1”,那么我们将开始游戏,但在此之前会初始化棋盘、并将其打印的

初始化棋盘

我们以一个9×9的棋盘为例,这对应的就是一个9行9列的二维数组

我们都知道扫雷游戏的玩法:点开一个格子,会显示其周围一圈八个格子存在雷的数量。

但倘若我们点的格子恰好在边缘上,这时候再判断周围八个格子是否是雷时会有几个坐标在棋盘外部,这时再通过遍历这八个坐标判断时,会发生数组越界

为了避免这种麻烦,我们再定义一个11×11的二维数组,专门用于判断,并且在超过9×9的地方都赋值0,这样在判断时也不会将其判定为雷

综上

我们需要设计两个二维数组,一个数组(show)9×9(尽管初始化时我将show初始化成11×11的数组,但实际上只用到了中间的9×9),专门用于存放被排查出的雷的信息,并呈现给玩家;另一个数组(mine)11×11,专门用于判断周围是否有雷,并将排查出来的信息传递给show数组

对于初始化

mine数组初始化为全’0’,被埋雷的地方则改为’1’;show数组初始化为’*‘,被排查的地方则显示器周围相应的雷的数量,如’2’

代码实现:

#define ROW 9
#define COL 9

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

void init_board(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 < cols; j++)
		{
			board[i][j] = set;
		}
	}
}

void game()
{
  //定义两个数组
    char mine[ROWS][COLS];
	  char show[ROWS][COLS];
	
	//初始化数组
	  init_board(mine, ROWS, COLS, '0');
	  init_board(show, ROWS, COLS, '*');
}

尽管我们设计了两个数组,但在打印时只会打印show数组,mine数组是不打印的,其存在目的只是为了使show数组能够显示每个格子周围雷的信息

打印结果展示:

保姆级教学—扫雷游戏的实现_第1张图片

看到上面的打印结果或许有人要问:这个行和列旁边的0~9是什么意思啊?

不急,这就涉及到后面内容-棋盘打印了,在文章后续会讲

下面我们先看雷的布置

布置雷

在初始化棋盘完成后,就需要布置雷了

雷的布置要满足随机的要求,所以就要用到随机数rand和srand(注意头文件的引用)

我们提前在main函数中初始化一个随机数发生器srand((unsigned int)time(NULL));,便于生成随机数

因为雷的布置玩家是不知道的,所以只需要在mine数组中布置即可,即将mine数组中的’0’变成’1’

代码实现:

//设置雷的个数
#define easy_count 10

void set_mine(char board[ROWS][COLS], int row, int col)
{
	int count = easy_count;
	//布置easy_count个雷,每布置一个就减少1
	while (count)
	{
		int x = rand() % row + 1;
		int y = rand() % col + 1;
		//该坐标要确定没被布置过雷
		if (board[x][y] == '0')
		{
			board[x][y] = '1';
			count--;
		}
	}
}

这里的int x = rand() % row + 1和int y = rand() % col + 1是保证布置的雷不会超出9×9的范围

打印棋盘

在布置完雷后,就可以进行打印棋盘供玩家开始排查雷了

所打印的棋盘是不能让玩家知道雷是怎么布置的所以,mine数组不能打印,只需打印show数组即可

代码实现:

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

为了使玩家在排查雷时方便输入坐标,我们在棋盘的上侧和左侧标上列号和行号,即在初始化棋盘时见到的那样

排查雷

棋盘被成功打印后就要开始真正的“扫雷”了

玩家在输入一个坐标后,我们需要在mine数组上的该坐标周围8个坐标判断有没有雷,有几颗雷,并将这个数据传给show数组进行显示

同时我们也要给出游戏结束的条件:踩雷了或者非雷的坐标都排查完毕

代码实现:

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

void find_mine(char board1[ROWS][COLS], char board2[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	int win = 0;
	while (win< row * col - easy_count)
	{
		printf("请输入坐标:");
		scanf("%d%d", &x, &y);
		//首先判断输入的坐标是否符合棋盘大小规定
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			//再判断这个坐标是否已经排查过了
			if (board2[x][y] == '*')
			{
				if (board1[x][y] == '1')
				{
					printf("很遗憾,你被炸死了!\n");
					dispaly_board(board1, ROW, COL);
					break;
				}
				else
				{
					//用来接收该坐标周围的雷数
					int count = get_mine_count(board1, x, y);
					//因为我们在show数组中都是字符数字,所以也要让count变成字符数字,所以这里+上了'0'
					board2[x][y] = count + '0';
					//进行屏幕清空
					system("cls");
					dispaly_board(board2, ROW, COL);
					//每成功扫一个雷就win++
					win++;
				}
			}
			else
			{
				printf("坐标已被排查,请重新输入:");
			}
		}
		else
		{
			printf("坐标非法,请重新输入:");
		}
	}
	if (win == row * col - easy_count)
	{
		printf("恭喜你,扫雷成功\n");
		dispaly_board(board1, ROW, COL);

	}
}

具体排查过程各位可以看代码,是比较好理解的

值得一提的是,在提取坐标周围雷的信息时,我们是将这八个坐标遍历,将这8个字符加起来-8*‘0’,这样就可以得到雷的个数

因为’0’对应的ASCII码值为48,'1’对应49,倘若周围没有雷,则8个48相加减去8乘48等于0,即没有雷,符合要求

完整代码呈现

我写这个游戏时是多文件工程,所以我也就分文件给大家呈现了

main.c

#include"game.h"
void menu()
{
	printf("                           \n");
	printf("          1.paly           \n");
	printf("          0.exit           \n");
	printf("                           \n");

}

void game()
{
	//定义两个数组
    char mine[ROWS][COLS];
	char show[ROWS][COLS];
	
	//初始化数组
	init_board(mine, ROWS, COLS, '0');
	init_board(show, ROWS, COLS, '*');

	//布置雷
	set_mine(mine, ROW, COL);
	
	//打印最初的棋盘
	dispaly_board(show, ROW, COL);

	//排查雷
	find_mine(mine, show, ROW, COL);

}

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

	return 0;
}

game.h

#pragma once
#include
#include
#include
#include

#define ROW 9
#define COL 9

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

//设置雷的个数
#define easy_count 10


//初始化数组
void init_board(char board[ROWS][COLS], int rows, int cols, char set);

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

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

//排查雷
void find_mine(char board[ROWS][COLS], int rows, int cols);

game.c

#include"game.h"

//初始化数组
void init_board(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 < cols; j++)
		{
			board[i][j] = set;
		}
	}
}

//打印棋盘
//这里只需要打印中间9*9的棋盘就可以了
void dispaly_board(char board[ROWS][COLS], int row, int col)
{
	int i = 0;
	int j = 0;
	for (j = 0; j <= col; j++)
	{
		printf("%d ", j);
	}
	printf("\n");
	for (i = 1; i <= row; i++)
	{
		printf("%d ", i);
		for (j = 1; j <= col; j++)
		{
			printf("%c ", board[i][j]);
		}
		printf("\n");
	}
}


//布置雷
//这里只需要在中间9*9的棋盘布置即可,将mine数组中'0'变成'1'
//因为要在棋盘中随机布置雷,所以要用到随机数
void set_mine(char board[ROWS][COLS], int row, int col)
{
	int count = easy_count;
	//布置easy_count个雷,每布置一个就减少1
	while (count)
	{
		int x = rand() % row + 1;
		int y = rand() % col + 1;
		//该坐标要确定没被布置过雷
		if (board[x][y] == '0')
		{
			board[x][y] = '1';
			count--;
		}
	}
}



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


//排查雷
//玩家在选定一个坐标后,我们需要在mine数组上的该坐标周围8个坐标判断有没有雷,有几颗雷,并将这个数据传给show数组进行显示
void find_mine(char board1[ROWS][COLS], char board2[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	int win = 0;
	while (win< row * col - easy_count)
	{
		printf("请输入坐标:");
		scanf("%d%d", &x, &y);
		//首先判断输入的坐标是否符合棋盘大小规定
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			//再判断这个坐标是否已经排查过了
			if (board2[x][y] == '*')
			{
				if (board1[x][y] == '1')
				{
					printf("很遗憾,你被炸死了!\n");
					dispaly_board(board1, ROW, COL);
					break;
				}
				else
				{
					//用来接收该坐标周围的雷数
					int count = get_mine_count(board1, x, y);
					//因为我们在show数组中都是字符数字,所以也要让count变成字符数字,所以这里+上了'0'
					board2[x][y] = count + '0';
					//进行屏幕清空
					system("cls");
					dispaly_board(board2, ROW, COL);
					//每成功扫一个雷就win++
					win++;
				}
			}
			else
			{
				printf("坐标已被排查,请重新输入:");
			}
		}
		else
		{
			printf("坐标非法,请重新输入:");
		}
	}
	if (win == row * col - easy_count)
	{
		printf("恭喜你,扫雷成功\n");
		dispaly_board(board1, ROW, COL);

	}
}

结尾

到这里,扫雷游戏就算是实现了,不过这里的游戏也存在缺陷

我写的代码在排查雷时只能一次排查一个,无法做到像网上游戏一样,有时候可以一次排查一片

其他若有写的不对、不好、不严谨的地方欢迎各位指正

感谢各位的阅读观看,谢谢大家!

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