写个扫雷游戏,拆分精解,约200行代码

游戏可以通过菜单实现继续玩或者退出游戏
• 扫雷的棋盘是9*9的格⼦
• 默认随机布置10个雷
• 可以排查雷
◦ 如果位置不是雷,就显⽰周围有⼏个雷
◦ 如果位置是雷,就炸死游戏结束
◦ 把除10个雷之外的所有雷都找出来,排雷成功,游戏结束

1.扫雷游戏的基本框架与逻辑

笔者新建了一个头文件:gane.h,两个源文件:game.c ; test.c
game.h里面用来定义变量和声明函数
game.c里存放具体函数
test.c里运行游戏,是正文
写个扫雷游戏,拆分精解,约200行代码_第1张图片
首先在test.c源文件中写出基本游戏运行框架
无非就一个循环

#include
#include"game.h"
int main()
{
	int choice = 0;//用来读取用户的选择
	do
	{
		menu();//打印菜单
		
		scanf("%d",&choice);
		switch (choice)
		{
		case 1:
		{	printf("开始游戏\n");
		    game();//这里是还未创建的函数


		break;
		}
		case 0:
			printf("退出游戏\n");
			break;
		default :
			printf("输入错误,重新输入\n");
			break;
		}
	} while (choice);
	return 0;
}

可以直接在源文件中创建menu函数,因为它的可引用范围比较小
添加菜单:

#define _CRT_SECURE_NO_WARNINGS 1
#include
#include"game.h"
void menu()
{
	printf(
		"****************\n"
		"***请选择:>*****\n"
		"****1.play******\n"
		"****0.exit******\n"
		"****************\n"
	);
}
int main()
{
	int choice = 0;//用来读取用户的选择
	do
	{
		menu();//打印菜单
		
		scanf("%d",&choice);
		switch (choice)
		{
		case 1:
		{	printf("开始游戏\n");
		    game();//这里是还未创建的函数


		break;
		}
		case 0:
			printf("退出游戏\n");
			break;
		default :
			printf("输入错误,重新输入\n");
			break;
		}
	} while (choice);
	return 0;
}

2.(重点)写game函数

从游戏逻辑来看
game函数中包括:初始化棋盘,打印棋盘,随机布置雷,显示周围雷的个数

2.1初始化棋盘

写个扫雷游戏,拆分精解,约200行代码_第2张图片
这是一个布满雷的棋盘
问题是:如果排雷时访问到边缘,会越界,破环数组
所以这时候我们给行和列各自在9的基础上+2
写个扫雷游戏,拆分精解,约200行代码_第3张图片
多加一圈防止越界,这一圈我们可以不打印,不设雷

这里需要两个数组,一组是初始化后设雷用的,不显示,一组是给用户排雷用的,显示周围雷数

在这里插入图片描述
在这里插入图片描述
为了方便,这里直接在game.h里定义声明变量
然后要在test.c中包含:
#include“game.h"

下一步,把invisible全部元素初始化成字符类型的0
把visible全部元素初始化成字符类型的*
写个扫雷游戏,拆分精解,约200行代码_第4张图片

转到game.c里写Initial_Board()函数
写个扫雷游戏,拆分精解,约200行代码_第5张图片

2.2打印棋盘

写个扫雷游戏,拆分精解,约200行代码_第6张图片
写函数:Initial_Board()
注意:这里传给函数的行和列分别是 ROW,COL
因为要打印9*9就够了,自己给加的两行不打印

基本模型:写个扫雷游戏,拆分精解,约200行代码_第7张图片
运行结果:写个扫雷游戏,拆分精解,约200行代码_第8张图片
现在,给每一行每一列加上标号,便于判断坐标

void Printf_Board(char board[ROW][COL], int row, int col)
{
	int i = 0;
	int j = 0;
	for (i = 1;i <= 9;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");
	}
}

看运行结果:
写个扫雷游戏,拆分精解,约200行代码_第9张图片
把invisible打印棋盘注释掉,成功隐藏(这步放哪都行)
写个扫雷游戏,拆分精解,约200行代码_第10张图片

2.3布置雷

随机布置,仍然沿用上次猜数字游戏中的格式

//布置雷
void Set_Mine(char board[ROWS][COLS], int row, int col)
{
	int x = rand() % row + 1;
	int y = rand() % col + 1;
	int count = EASY_COUNT;
	while (count)
	{
		if (board[x][y] == '0')
		{
			board[x][y] = '1';
			
		}
		count--;
	}

}

game.c中的函数

写个扫雷游戏,拆分精解,约200行代码_第11张图片
在test.c里加入srand,这个语句调用一次就可以了,不需要循环调用

注意:记得在game.h里包含头文件
还有,声明函数和变量
在这里插入图片描述

2.4(重头戏)排雷

思路:
1.多次排雷,用while循环,那循环条件呢?初始化一个变量win,如果win小于棋盘元素总数减去设雷数,那么正常进入循环
2.输入坐标排雷,所以要循环的scanf()
3.第一个选择:输入在棋盘元素范围内:
a.排到雷–炸死–循环结束
b.未排到雷–输出周围雷的个数–继续循环输入
输入不在范围内:
打印“非法,重输”

//排雷
void Find_Mine(char invisible[ROWS][COLS],char visible[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	int win = 1;
	
	while (win < row * col - EASY_COUNT)
	{
		printf("请输入要排查的坐标:>\n");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			if (invisible[x][y] == '1')
			{
				printf("很遗憾,你被炸死了\n");
				Printf_Board(invisible, ROW, COL);
				break;
			}
			else
			{
				int num=Count_Mine(invisible, x, y);
				visible[x][y] = num+'0';
				Printf_Board(visible, ROW, COL);
				win++;
			}

			
		}

		else
			printf("非法输入,重新输入\n");
	}

	if (win == row * col - EASY_COUNT)
		printf("太棒啦,扫雷成功\n");

}

注意事项:1.在创建函数时,一定要两个函数都读取
2.在test.c中给函数传参时,一定要传ROWS,COLS(1111的),接受的时候,数组[ ]里也要是ROWS,COLS(1111的),因为排雷操作不能越界,而且自己加的两行不会打印,没有影响,但一定会影响行号列号,也就是影响坐标

2.5计算周围雷的数量

上面在排雷函数中嵌套了一个叫Count_Mine()的函数
计算invisible棋盘上某元素周围雷的个数的
巧妙运用了ASCII码值
‘0’–48
‘1’–49
‘2’–50
‘3’–51
所以,计算方法可以是周围一圈字符代表的ASCII值相加减去8个‘0’的ASCII值
写个扫雷游戏,拆分精解,约200行代码_第12张图片

int Count_Mine(char invisible[ROW][COL], int x, int y)
{
	return( invisible[x][y - 1] + invisible[x][y + 1] + invisible[x - 1][y - 1] + invisible[x - 1][y + 1] + invisible[x - 1][y]
		+ invisible[x + 1][y - 1] + invisible[x + 1][y] + invisible[x - 1][y + 1] - 8 * '0');

}

好,完工

3.最终代码呈现

3.1game.h

#define _CRT_SECURE_NO_WARNINGS 1
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
#define EASY_COUNT 10
#include
#include
void Initial_Board(char board[ROWS][COLS], int rows, int cols, char set);
void Printf_Board(char board[ROWS][COLS], int row, int col);
void Set_Mine(char board[ROWS][COLS], int row, int col);
int Count_Mine(char invisible[ROW][COL], int x, int y);

3.2game.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
#include
//初始化棋盘
void Initial_Board(char board[ROWS][COLS], int rows, int cols, char set)
{
	int i = 0;
	for (i = 0;i < rows;i++)
	{
		int j = 0;
		for (j = 0;j<cols;j++)
			board[i][j] = set;

	}
}
//打印棋盘
void Printf_Board(char board[ROWS][COLS], int row, int col)
{
	int i = 0;
	int j = 0;
	printf("-----------扫雷开始-----------\n");
	for (i = 1;i <= 9;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 board[ROWS][COLS], int row, int col)
{
	int x = rand() % row + 1;
	int y = rand() % col + 1;
	int count = EASY_COUNT;
	while (count)
	{
		if (board[x][y] == '0')
		{
			board[x][y] = '1';
			
		}
		count--;
	}

}

//排雷
void Find_Mine(char invisible[ROWS][COLS],char visible[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	int win = 1;
	
	while (win < row * col - EASY_COUNT)
	{
		printf("请输入要排查的坐标:>\n");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			if (invisible[x][y] == '1')
			{
				printf("很遗憾,你被炸死了\n");
				Printf_Board(invisible, ROW, COL);
				break;
			}
			else
			{
				int num=Count_Mine(invisible, x, y);
				visible[x][y] = num+'0';
				Printf_Board(visible, ROW, COL);
				win++;
			}

			
		}

		else
			printf("非法输入,重新输入\n");
	}

	if (win == row * col - EASY_COUNT)
		printf("太棒啦,扫雷成功\n");

}

int Count_Mine(char invisible[ROW][COL], int x, int y)
{
	return( invisible[x][y - 1] + invisible[x][y + 1] + invisible[x - 1][y - 1] + invisible[x - 1][y + 1] + invisible[x - 1][y]
		+ invisible[x + 1][y - 1] + invisible[x + 1][y] + invisible[x - 1][y + 1] - 8 * '0');

}

3.3test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include
#include"game.h"
void menu()
{
	printf(
		"****************\n"
		"***请选择:>*****\n"
		"****1.play******\n"
		"****0.exit******\n"
		"****************\n"
	);
}

void game()
{
	char invisible[ROWS][COLS];
	char visible[ROWS][COLS];
	//初始化棋盘
	Initial_Board(invisible,ROWS,COLS,'0');
	Initial_Board(visible, ROWS, COLS, '*');
	//打印棋盘
	Printf_Board(visible, ROW, COL);
	//Printf_Board(invisible, ROW, COL);
	//布置雷
	Set_Mine(invisible, ROW, COL);
	//排雷
	Find_Mine(invisible, visible, ROWS, COLS);	
}

int main()
{
	int choice = 0;//用来读取用户的选择
	do
	{
		menu();//打印菜单
		srand((unsigned int)time(NULL));
		scanf("%d",&choice);
		switch (choice)
		{
		case 1:
		{	printf("开始游戏\n");
		    game();

		break;
		}
		case 0:
			printf("退出游戏\n");
			break;
		default :
			printf("输入错误,重新输入\n");
			break;
		}
	} while (choice);
	return 0;
}

写个扫雷游戏,拆分精解,约200行代码_第13张图片
部分运行成果

你可能感兴趣的:(游戏,c语言,学习方法,笔记)