C语言基础:扫雷游戏的C语言实现(超详图解+源码)

友友们好,今天和大家一起做一个简单的C语言小游戏——扫雷小游戏。

  游戏规则如下:

       扫雷的规则很简单。盘面上有许多方格,方格中随机分布着一些雷。你的目标是避开雷,打开其他所有格子。一个非雷格中的数字表示其相邻8格中的雷数,你可以利用这个信息推导出安全格和雷的位置。打开所有安全格将被判定为胜利,打开雷将被判定为失败。


目录

实现思路

一、制作一个游戏菜单

二、构建游戏的基本逻辑结构

三、进入游戏的制作

1、定义两个一样的数组

​编辑

2、初始化数组

3、打印盘面

4、布置雷

5、排查雷

·这个坐标不是雷,提示周围有几个雷

·这个坐标是雷,游戏结束   

·所有非雷位置都找到了,游戏胜利

6、game函数的实现

四、扫雷游戏的实现


实现思路

       首先,制作一个游戏菜单,而后构建整个游戏的基本逻辑结构,然后进入游戏的制作。首先要在盘面上随机给出10个雷的位置; 然后玩家需要在盘面的合法位置排雷,如果在非法位置,应给出相应提示;在排雷的同时要判断游戏是否结束,如果结束需要判断胜负。

       接下来我们就以这个基本思路来进行代码的实现。


一、制作一个游戏菜单

首先,我们要制作一个游戏菜单。我们用一个简易的函数来实现他。

void menu()
{
	printf("*********************************\n");
	printf("*******   扫雷小游戏    *********\n");
	printf("*******     1、play     *********\n");
	printf("*******     0、exit     *********\n");
	printf("*********************************\n");
}

我们在主函数中可以调用这个函数来实现打印菜单的目的。


二、构建游戏的基本逻辑结构

制作完菜单后,我们需要构建这个游戏的基本逻辑结构。

首先需要明确我们的需求: 1、我们可以通过输入 1 / 0 来选择开始或结束游戏

                                            2、如果一把玩完不过瘾,我们可以通过选择来再玩一把

· 我们运用分支语句的知识来实现第一个需求。

       在这里我使用switch语句,定义一个整型来存放输入的数字,如果输入的数字是 1 ,则提示“开始游戏”;如果输入的数字是 0 ,则提示“结束游戏”;如果输入了 1/0 以外的数字,则我们提醒他输错了,重新输入。

· 我们通过循环来实现第二个需求。

       在这里使用do... while() 循环,将定义的整型放在() 里作为判断条件。当我们输入 1 ,为非0,判断为真,游戏继续;当我们输入 0 ,判断为假,游戏结束;当我们输入 1/0  以外的数字,为非0,判断为真,可以继续循环让我们重新判断。

int main()
{
	int input;
	//先输入一个input判断要不要进入游戏,将其也设为循环的判断条件

	do {
		menu();
		printf("请输入->");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			printf("开始游戏\n");
			game();
			//如果输入1,说明要玩游戏,封装一个game函数来包含游戏内容
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("输错啦,请重新输入\n");
			break;
		}
	} while (input);
 
	return 0;
}


从代码运行结果来看,满足了我们提出的两点需求。


三、进入游戏的制作

1、定义两个一样的数组

两个数组,一个展示,一个放雷

  所以我们需要定义两个 11*11的数组,一个用来存放雷的数据,一个用来显示。

 为了后期调试的方便,我们可以将数组参数使用#define标识符替换列表中的参数。

#include<stdio.h>
#include<stdlib.h>   //srand函数的头文件
#include<time.h>     //time函数的头文件

#define ROW 9    //实际使用的行
#define COL 9    //实际使用的列

#define ROWS 11    //数组使用的行
#define COLS 11    //数组使用的列

#define COUNT_EASY 10
//简单版本有10个雷

2、初始化数组

       首先我们封装一个game函数,将实现游戏的内容都放在game函数中。定义两个字符型的二维数组,将二者初始化。

//初始化数组

void InitBoard(char board[ROWS][COLS], int rows, int cols, char ret)
{
	int x = 0;
	int y = 0;
	for (x = 0; x < rows; x++)
	{
		for (y = 0; y < cols; y++)
		{
			board[x][y] = ret;
		}
	}
}


void game()
{
	//为了方便,把两个数组定义成完全一样的
	char mine[ROWS][COLS] = { 0 };
	char show[ROWS][COLS] = { 0 };

    //初始化两个数组,传对应的参数进去
    //将雷盘先全都定义为0
    //将显示盘定义为*
    InitBoard(mine, ROWS, COLS, '0');
	InitBoard(show, ROWS, COLS, '*');

}

3、打印盘面

我们先清楚盘面的格式为:11 * 11 的正方形;其中只需打印中间的9*9,所以我们传ROW与COL进去即可;为了格式好看与查找方便,我们还可以添加一些表头与分隔。

            

//打印棋盘
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	printf("--------扫雷---------\n");
	for (x = 0; x <= row; x++)
	{
		printf(" %d", x);    //打印坐标提示行
	}
	printf("\n");
	for (x = 1; x <= row; x++)
	{
		printf(" %d", x);    //打印坐标提示列
		for (y = 1; y <= col; y++)
		{
			printf(" %c", board[x][y]);
		}
		printf("\n");
	}
	printf("---------------------\n");
}



//打印的时候传过去的数组还是11*11的,数组是不会变的,不会因为你想打印的是9*9的就变成9*9的数组
//因为我们只想打印出9*9的格子,所以传过去的是ROW和COL

4、布置雷

       简易版的9*9盘面内有10个雷,我们可以用rand函数来生成随机值来作为雷生成的坐标。生成雷时需要注意,雷的坐标需要是一个合法坐标,我们可以将生成坐标的过程放进循环里,当雷的坐标为合法坐标时跳出循环。注意将坐标适当处理。我们封装一个函数,在game函数中调用来实现该功能。

//布置雷
void Setmine(char board[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	int count = COUNT_EASY;  //雷的数量
	while (count)//当没布置完雷之前都继续循环
	{
		x = rand() % row + 1;     //生成数%row后范围是0~8 我们需要的是1~9
		y = rand() % col + 1;
		if (board[x][y] == '0')
		{
			board[x][y] = '1';
			count--;
		}
	}
}

  注意:

       C语言中提供了一个rand函数可以帮我们生成随机数,返回值为int 整型,返回的值就是一个随机数。但rand函数生成的是伪随机数,返回的随机值并不完全随机。

                        

       rand函数在生成随机数之前,要使用srand函数设置随机数的生成器。srand()括号中放置类似于生成随机数的种子,种子固定了生成的随机数也是固定的。所以我们要使括号中的值为随机变化的,才能使产生的数值为随机值。

       在我们的计算机中,时间是时刻在发生变化的,如果能将时间传入srand中,那么就可以实现真正的随机。这个时候我们可以使用time函数来解决这个问题。

   

       time函数可以返回一个时间戳,时间戳是一串数字, 是随着时间在不断变化的 。在使用时我们需要调用二者的头文件。time函数的返回类型是time_t,在srand中要使用他需要强制类型转换为(unsigned int)

所以在主函数中:

//记得引用头文件
#include<stdio.h>
#include<stdlib.h>   //srand函数的头文件
#include<time.h>     //time函数的头文件

int main()
{
	srand((unsigned int)time(NULL));
	int input = 0;
	do {
		menu();
		printf("请输入->");
		scanf("%d", &input);

		switch (input)
		{
		case 1:
			printf("开始游戏\n");
			game();
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("输错了,请重新输入\n");
			break;
		}
	} while (input);
	return 0;
}

这样就能实现随机布置雷:

     

5、排查雷

       首先玩家排查雷需要在盘面中的合法位置,如果排查位置在盘外或者排查的位置已被占用,我们需要给出相应的提示。然后玩家给出的是盘面的坐标位置,因为我们盘面坐标刚好和数组位置对应,所以可以不用再进行操作。我们封装一个函数,在game函数中调用来实现该功能。

       并且在排查的过程中,可能出现以下几种情况:1、这个坐标不是雷,提示周围有几个雷

                                                                                   2、这个坐标是雷,游戏结束   

                                                                                   3、所有非雷位置都找到了,游戏胜利

       如果找到的坐标位置为非雷,那么我们就需要继续排查,所以我们将排查过程放到循环中进行,踩到雷或者排查结束才跳出循环。

·这个坐标不是雷,提示周围有几个雷

所以我们可以通过以下代码来实现功以上功能:

//数周围有几个雷
int GetMineCount(char mine[ROWS][COLS], int x, int y)
{
	return  (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] +
		mine[x - 1][y]) - (8 * '0');
}

       然后在game函数中调用,实现函数功能。

·这个坐标是雷,游戏结束   

       当踩到雷时,我们给出相应提示后直接跳出循环结束游戏即可。

·所有非雷位置都找到了,游戏胜利

       我们可以设置一个整型变量,其大小为非雷的位置个数。如果成功排除一个雷就将其减一,将他作为循环的判断条件,当他减为0时刚好也能跳出循环,并给出相应提示表示排雷成功。

//排查雷
void Findmine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	int win = row * col - COUNT_EASY;
	while (win )
	{
		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 if (show[x][y] != '*')
			{
				printf("排查过该坐标,请重新输入\n");
			}
			else if (mine[x][y] == '0')
			{
				int ret = 0;
				ret = GetMineCount(mine, x, y);
				show[x][y] = ret + '0';

				DisplayBoard(show, ROW, COL);
				win--;
			}
		}
		else
		{
			printf("输入坐标非法,请重新输入\n");
		}
	}
    //跳出循环有两种可能,一个是踩雷退出,一个是排雷完成退出
    //需要判断是不是排雷成功,然后给出提示
	if(win==0)
		printf("恭喜你,排雷成功! \n");
}
    
	

6、game函数的实现

void game()
{
	//为了方便,把两个数组定义成完全一样的
	char mine[ROWS][COLS] = { 0 };
	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);
	//DisplayBoard(mine, ROW, COL);

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


四、扫雷游戏的实现

将上面的代码汇总成一个完整的扫雷游戏:

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

#define ROW 9
#define COL 9
#define ROWS 11
#define COLS 11

#define COUNT_EASY 10
//简单版本有10个雷

void menu()
{
	printf("*********************************\n");
	printf("*******   扫雷小游戏    *********\n");
	printf("*******     1、play     *********\n");
	printf("*******     0、exit     *********\n");
	printf("*********************************\n");
}


//初始化数组
void InitBoard(char board[ROWS][COLS], int rows, int cols, char ret)
{
	int x = 0;
	int y = 0;
	for (x = 0; x < rows; x++)
	{
		for (y = 0; y < cols; y++)
		{
			board[x][y] = ret;
		}
	}
}


//打印棋盘
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	printf("--------扫雷---------\n");
	for (x = 0; x <= row; x++)
	{
		printf(" %d", x);
	}
	printf("\n");
	for (x = 1; x <= row; x++)
	{
		printf(" %d", x);
		for (y = 1; y <= col; y++)
		{
			printf(" %c", board[x][y]);
		}
		printf("\n");
	}
	printf("---------------------\n");
}


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


//数周围有几个雷
int GetMineCount(char mine[ROWS][COLS], int x, int y)
{
	return  (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] +
		mine[x - 1][y]) - (8 * '0');
}



//排查雷
void Findmine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	int win = row * col - COUNT_EASY;
	while (win )
	{
		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 if (show[x][y] != '*')
			{
				printf("排查过该坐标,请重新输入\n");
			}
			else if (mine[x][y] == '0')
			{
				int ret = 0;
				ret = GetMineCount(mine, x, y);
				show[x][y] = ret + '0';

				DisplayBoard(show, ROW, COL);
				win--;
			}
		}
		else
		{
			printf("输入坐标非法,请重新输入\n");
		}
	}
	if(win==0)
		printf("恭喜你,排雷成功! \n");
}




void game()
{
	//为了方便,把两个数组定义成完全一样的
	char mine[ROWS][COLS] = { 0 };
	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);
	//DisplayBoard(mine, ROW, COL);

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


int main()
{
	srand((unsigned int)time(NULL));
	int input = 0;
	do {
		menu();
		printf("请输入->");
		scanf("%d", &input);

		switch (input)
		{
		case 1:
			printf("开始游戏\n");
			game();
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("输错了,请重新输入\n");
			break;
		}
	} while (input);
	return 0;
}

大家也可以将其封装为多个文件看上去更简洁明了,我这里为了表达方便将其放在一个文件里。


以上就是  C语言基础:扫雷游戏的C语言实现(超详图解+源码)的全部内容啦,希望能对你有所帮助!

  • 31
    点赞
  • 81
    收藏
    觉得还不错? 一键收藏
  • 19
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值