C语言-扫雷游戏

本文详细介绍了扫雷游戏的规则,以及如何通过代码实现游戏逻辑,包括棋盘初始化、雷的布置、玩家操作(排查雷)和游戏菜单设计。展示了从游戏界面到核心算法的全过程。
摘要由CSDN通过智能技术生成

扫雷游戏是一款经典的单人益智游戏,通过在雷区中排查出所有的非雷方块来获得胜利。它的规则简单,但是需要一定的策略和运气才能成功。

在扫雷游戏中,玩家需要点击方块来揭开它们,方块上会显示数字或者空白。数字表示该方块周围的雷的数量,空白表示周围没有雷。玩家需要根据这些数字来推测雷的位置,并标记出雷的位置。如果玩家揭开的方块是雷,游戏结束;如果玩家成功排查出所有的非雷方块,游戏胜利。

为了更好地理解扫雷游戏的实现过程,我将通过代码来展示扫雷游戏的逻辑。

在此之前我们需要简单的了解扫雷游戏的规则

扫雷游戏规则

扫雷游戏的目标是在最短的时间内根据点击格子出现的数字找出所有非雷格子,同时避免踩到地雷。游戏的基本操作包括左键单击、右键单击和双击三种。具体规则如下:

  1. 玩家逐个翻开方块,以找出所有地雷为最终游戏目标。如果玩家翻开的方块有地雷,则游戏结束。
  2. 游戏主区域由很多个方格组成。选择一个方格,方格即被打开并显示出方格中的数字;方格中数字则表示其周围的8个方格隐藏了几颗雷。如果点开的格子为空白格,即其周围有0颗雷,则其周围格子自动打开;如果其周围还有空白格,则会引发连锁反应;在你认为有雷的格子上,点击右键即可标记雷;如果一个已打开格子周围所有的雷已经正确标出,则可以在此格上同时点击鼠标左右键以打开其周围剩余的无雷格。
  3. 左下角代表游戏时间,右下角代表剩余雷的数量。
  4. 开始游戏时,玩家不知道哪里是雷,需要任意选择一个方格。一般可以从四个角落开始。
  5. 游戏中的数字代表周围八个方向雷的数量。例如,数字1表示周围的空格已经全部打开,只剩下一个方格,那么这一个肯定就是雷了。
  6. 玩家需要根据周围的数字去判断最有可能的是哪一个方块有雷。
  7. 如果确定该方块为空,可以左键点击一下;如果认为是雷可以右键点击一下插上小旗;右击两次代表不确认。

扫雷游戏的代码逻辑过程

1.首先,我们需要创建游戏的源文件和头文件。源文件包括test.c和game.c,头文件为game.h。

test.c是游戏的测试逻辑,其中包含了游戏的主函数和测试函数。在主函数中,我们通过调用测试函数来开始游戏。测试函数中,我们使用do-while循环来显示游戏菜单,并根据用户的选择来执行相应的操作。选择1将进入游戏,选择0将结束游戏。

game.h是游戏的逻辑实现,其中包含了游戏所需的函数声明。game.c是游戏逻辑的具体实现,包括棋盘的初始化、打印棋盘、布置雷和排查雷等功能。

2.扫雷游戏有菜单,选择1就继续游戏,选择0就结束游戏,选择其他则选择错误,这个菜单的功能我们用do-while函数实现,写在test函数中,所以我们则在函数中打印菜单,创建menu函数,此时menu函数仅仅作为提示用户选择1或0继续和结束游戏的提示,所以在menu函数中使用printf函数

void menu()
{
	//扫雷游戏菜单
	printf("****************\n");
	printf("***1. Play******\n");
	printf("***2. Exit******\n");
	printf("****************\n");
}

3.使用menu函数输出提示1或0选择之后,我们需要在主函数中使用scanf函数接收用户选择的信息,定义input为用户选择的信息名,然后在do-while函数中使用switch函数根据用户的选择给出对应的回应,对于do-while函数中while后面的限制条件填写input,因为如果用户输入0,即结束游戏结束do-while函数,输入1或其他非0的数,则为真,则玩完一局后会继续游戏

void test()
{
	//用户选择1或0的接受值
	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);
}

4.在switch函数中选择1,即进入case 1,在case 1中进行游戏,所以定义一个game函数,在函数内部完成扫雷游戏

void game()
{
	//完成扫雷游戏
	//mine数组中存放布置雷的信息
	char mine[ROWS][COLS] = { 0 };//数组全部初始化为字符0

	//show数组中存放排查出的雷的信息
	char show[ROWS][COLS] = { 0 };//数组全部初始化为*
	//初始化数组
	InitBoard(mine, ROWS, COLS, '0');
	InitBoard(show, ROWS, COLS, '*');

	//打印棋盘
	//DisplayBoard(mine, ROW, COL);
	DisplayBoard(show, ROW, COL);

	//布置雷
	//在九*九的棋盘中
	SetMine(mine, ROW, COL);

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

5.在game函数中我们就需要常见一个99的棋盘作为扫雷界面(跟大的棋盘也可以,这里以99为例),所以使用二维数组,

#define ROW 9
#define COL 9

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

//声明函数

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

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

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

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

6.在棋盘内,我们需要设置雷,所以我们用1表示雷,用0表示没有雷,但是用户输入其中一个位置后,该位置会计算该附近8个位置的雷的个数,并在该位置表示出来,但是可能出现越界的情况,比如排查(8,6)这个坐标位置,我们访问周围的一圈8个黄色位置,
统计雷的个数,最下面的三个坐标就会越界,为了防止越界,我们在实际的时候,给数组扩大一圈,雷还是布置在中间的99的坐标上,周围一圈不去布置雷就行了,这样就可以解决越界问题,所以我们将错放数据的数组创建为11*11的比较合适

void InitBoard(char arr[ROWS][COLS], int rows, int cols,char set)
{
	int i = 0;
	for (int i = 0; i < rows; i++) {
		int j = 0;
		for (int j = 0; j < cols; j++) {
			arr[i][j] = set;
		}
	}
}

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

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

7.刚刚我们我们用1表示雷,用0表示没有雷,但是用户输入其中一个位置后,该位置会计算该附近8个位置的雷的个数,并在该位置表示出来,,但是如果某个位置附近只有一个雷,那么就会显示1,但是这个1并不表示雷,所以与1表示雷冲突了,所以我们需要再建立一个数组棋盘表示排查出雷的信息,之前建立的表示雷的信息

static int GetMineCount(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 FindMine(char mine[ROWS][COLS], char show[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 (mine[x][y] == '1') {
					printf("很遗憾,你被炸死了\n");
					DisplayBoard(mine, ROW, COL);
					break;
				}
				else
				{
					//该坐标有几个雷,就得统计周围有几个雷
					int count = GetMineCount(mine, x, y);
					show[x][y] = count + '0';
					DisplayBoard(show, ROW, COL);
					win++;
				}
			}
			else
			{
				printf("坐标非法,请重新输入\n");
			}
		}
		if(win == row * col- EASY_COUNT)
			{
				printf("恭喜你,排雷成功\n");
				DisplayBoard(mine,ROW,COL);
			}
	}

8.将以上代码分别放入对应的文件中,然后在test.c中包含game.h的include头文件,然后在main函数中调用test函数。

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include "game.h"
void menu()
{
	//扫雷游戏菜单
	printf("****************\n");
	printf("***1. Play******\n");
	printf("***2. Exit******\n");
	printf("****************\n");
}
void game()
{
	//完成扫雷游戏
	//mine数组中存放布置雷的信息
	char mine[ROWS][COLS] = { 0 };//数组全部初始化为字符0

	//show数组中存放排查出的雷的信息
	char show[ROWS][COLS] = { 0 };//数组全部初始化为*
	//初始化数组
	InitBoard(mine, ROWS, COLS, '0');
	InitBoard(show, ROWS, COLS, '*');

	//打印棋盘
	//DisplayBoard(mine, ROW, COL);
	DisplayBoard(show, ROW, COL);

	//布置雷
	//在九*九的棋盘中
	SetMine(mine, ROW, COL);

	//排查雷
	FindMine(mine, show, ROW, COL);
}
void test()
{
	//用户选择1或0的接受值
	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);
}
int main() {
	test();

	return 0;
}

扫雷游戏的逻辑过程总结

9.在游戏逻辑中,我们定义了一个9x9的棋盘,并使用二维数组来表示棋盘上每个方块的状态。我们用字符数组mine来存放雷的位置信息,用字符数组show来存放排查出的雷的信息。初始时,所有方块都是未揭开的状态,用字符’0’表示没有雷的方块,用字符’*'表示未揭开的方块。

在游戏开始时,我们调用InitBoard函数来初始化棋盘,将所有方块的状态设置为未揭开状态。然后,通过调用DisplayBoard函数来打印棋盘,让玩家看到游戏界面。

接下来,我们使用SetMine函数来布置雷。在9x9的棋盘中,我们将随机选择10个位置来布置雷,用字符’1’表示雷的位置。注意,在实际操作中,我们扩大了棋盘的大小,添加了一圈边界,以防止越界访问。

在排查雷的过程中,玩家需要输入要排查的坐标。我们使用GetMineCount函数来统计该位置周围的雷的数量,并将该数量显示在棋盘上。如果玩家揭开的方块是雷,游戏失败;如果玩家成功排查出所有的非雷方块,游戏胜利。

最后,我们在游戏结束时,根据游戏的结果来显示相应的信息。

通过以上的代码实现和逻辑介绍,我们可以看到扫雷游戏的基本实现过程。玩家需要不断地推测雷的位置,并根据推测的结果来揭开方块。通过合理的推理和策略,玩家可以成功排查出所有的非雷方块,获得游戏的胜利。

总结

  1. game.h文件中定义了一些宏和函数的声明,包括棋盘初始化函数InitBoard()、打印棋盘函数DisplayBoard()、布置雷函数SetMine()和排查雷函数FindMine()。

  2. game.c文件中包含了game.h头文件,并实现了game.h中声明的函数。

  3. InitBoard()函数用于将棋盘数组arr全部初始化为字符set。

  4. DisplayBoard()函数用于打印棋盘数组arr。首先打印列号,然后遍历数组arr,打印每个格子的内容。

  5. SetMine()函数用于在棋盘数组arr中随机布置雷。使用count变量来记录还需要布置的雷的数量,通过rand()函数生成随机的x和y坐标,判断该坐标是否已经有雷,如果没有,则在该坐标上布置雷,count减一。

  6. GetMineCount()函数用于计算指定坐标周围的雷的数量。通过查看该坐标上、下、左、右、斜上、斜下的8个方向的坐标上是否有雷,来计算雷的数量。

  7. FindMine()函数用于排查雷。使用while循环,当排查的雷数小于总雷数时,接收用户输入的坐标,并判断坐标的合法性。如果该坐标上有雷,游戏失败,打印出所有的雷的位置。否则,通过GetMineCount()函数计算该坐标周围的雷的数量,并将该数量显示在show数组中。同时打印出show数组。当排查的雷数等于总雷数时,表示排雷成功,打印出所有的雷的位置。

  8. test()函数用于实现游戏的菜单和用户选择。首先使用srand()函数设置随机数种子,然后使用do-while循环,根据用户输入的选择进行相应的操作。选择1则进入游戏,选择0则退出游戏,其他选择则提示重新选择。

  9. main()函数调用test()函数来运行游戏。

  • 23
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值