c语言——扫雷游戏

在基本掌握了分支、循环、数组、函数的前提下,我们基本就可以用c语言来实现一个扫雷游戏的编写了,其中只需要用到一个生疏的知识点——随机数的生成。在这之前我已经发布了一篇关于随机数生成的文章,可前往自取。在掌握了这些知识之后,便可以开始进行扫雷游戏的编写了。
在开始前,为了条理清晰一点,我们先创建一个头文件saolei.h来写游戏需要的数据类型和函数声明,和两个源文件saolei.c、test.c,分别进行游戏实现和写游戏的测试逻辑。
完整代码放在文章最后

1、主体设计及准备

首先我们需要在saolei.c、test.c两个源文件中对saolei.h进行引用,因为大多数据类型和函数声明都将写在saolei.h中
在test.h中引用自己创建的头文件
在saolei.h中引用自己创建的头文件
在saolei.h中需要引用的头文件

#include<stdio.h>
#include<stdlib.h>//随机数生成所需头文件
#include<time.h>//随机数生成所需头文件

这里我们同时也先在test.c中创建一个主体框架,后续进行内容填充

int main()
{
	srand((unsigned int)time(NULL));//生成随机数
	do
	{
		
		caidan();//菜单函数
		scanf("%d", &a);//这里的a定义在saolei.h中,为int a,作为全局变量,方便在排雷失败或者成功后跳出循环
		switch (a)
		{
		case 1:
			saolei();//游戏的主体函数,后续进行填充
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("输入错误,请重新输入\n");
			break;
		}
	} 
	while (a);
}

为了美观和引导游戏进行,在这里我们在test.c中创建一个菜单函数

void caidan()
{
	printf("*********************\n");
	printf("**** 1、开始游戏 ****\n");
	printf("**** 0、退出游戏 ****\n");
	printf("*********************\n");
}

在test.c中的主体框架上面创建一个游戏的主体函数

void saolei()
{
	
}

2、布置棋盘

这里我们做两个99的棋盘,作为进行布置雷和扫雷的场地,但是我们如果只是创建两个99的数组便会面临一个问题
![对一个位置进行扫雷的范围]](https://img-blog.csdnimg.cn/3c2d04c72c914270ba202eb36bfa3cfc.png#pic_center =300x300)
在边缘时便可能超出范围,于是为了编写代码的方便,这里我们创建两个11*11的数组作为棋盘,最外围一圈只让他存在,不进行使用
扩展一圈的效果
为了使代码更灵活,我们在saolei.h中创建`

#define HANG 9//行数
#define LIE 9//列数
#define HANGS HANG+2//行数的扩展
#define LIES LIE+2//列数的扩展
#define M 10//雷的个数

上面的行数、列数、雷的个数均可以自己设置,只需要改变后面的数字即可。
将两个数组在test.c中创建为

char mine[HANGS][LIES];
char show[HANGS][LIES];`

如果想改变棋盘的大小,只需要改变HANG,LIE后面的值便可以了,现在使用9*9的棋盘作为示范。

3、初始化

在创建了棋盘后紧接着便需要棋盘进行初始化,对其中填入内容。其中char mine[HANGS][LIES]中全部填入字符0,为显示雷的不可见的棋盘,内容为字符0的表示没有雷,后续将在char mine[HANGS][LIES]填入雷,而char show[HANGS][LIES]全部填入*,作为展示出来的棋盘。
首先,在游戏的主体函数saolei()中填入初始化函数

chushihua(mine, HANGS, LIES, '0');
chushihua(show, HANGS, LIES, '*');

再在saolei.h头文件里面申明初始化函数

void chushihua(char buzhi[HANGS][LIES], int hangs, int lies, char t);

最后在saolei.c中进行初始化函数的编写:运用两层循环分别将‘0’和‘*’填入数组mine和show

void chushihua(char buzhi[HANGS][LIES], int hangs, int lies, char t)
{
	int i = 0;
	for (int i = 0; i < hangs; i++)
	{
		for (int j = 1; j < lies; j++)
		{
			buzhi[i][j] = t;
		}
	}
}

到这里我们可以分别将两个数组打印出来,查看效果。这里我们又需要创建一个函数void chushi(char buzhi[HANGS][LIES], int hang, int lie)同样也需要在saolei.h头文件里面申明函数。这里同样使用两层循环来打印出来,但是为了美观和后续输入排雷坐标的方便添加了行列的显示

void chushi(char buzhi[HANGS][LIES], int hang, int lie)
{
	for (int i = 0; i <= hang; i++)//打印列数
	{
		printf("%d ", i);
	}
	printf("\n");
	for (int i = 1; i <= hang; i++)
    {
		printf("%d ", i);//打印行数
	    for (int j = 1; j <= lie; j++)
	    {
		    printf("%c ", buzhi[i][j]);
	    }
		printf("\n");
    }
}

最后在游戏主题函数中初始化函数的后面填入chushi(mine, HANG, LIE);chushi(show, HANG, LIE);导入数组和数值进行打印
打印出来效果如下:
这里为了查看效果,两个都打印了出来,到后面数组mine将不会打印,隐藏起来用来填雷。

4、布雷

创建一个函数void setlei(char buzhi[HANGS][LIES], int hang, int lie);用来布置雷,同样也需要在saolei.h头文件里面申明函数。在布雷这个阶段,我们就需要使用到随机数了。

void setlei(char mine[HANGS][LIES], int hang, int lie)
{
	int geshu = M;//将雷的个数赋值给geshu
	while (geshu)//当geshu为0时结束循环
	{
		int x = rand() % hang + 1;//随机生成1到9的数作为布雷位置的行
		int y = rand() % lie + 1;//随机生成1到9的数作为布雷位置的列
		if (mine[x][y] == '0')//这里可以避免重复布雷,只有为‘0’时才会布
		{
			mine[x][y] = '1';//布雷的位置为‘1’
			geshu--;//每布一个雷geshu减1,直到为零跳出循环
		}
	}

}

最后在saolei()游戏主体函数中填入setlei(mine, HANG, LIE);导入数值,即可布雷成功。
这里同样也可以查看布雷效果,只需要在saolei()游戏主体函数中setlei(mine, HANG, LIE); 函数的后面再次引用chushi(mine, HANG, LIE); 即可打印出来,效果如下:
第一次布雷位置
第二次布雷位置

5、排雷

与上面一样,我们又需要创建一个函数void shuru(char mine[HANGS][LIES], char show[HANGS][LIES], int hang, int lie);,同样也需要在saolei.h头文件里面申明函数。每一步的解释附在相应代码后面

void shuru(char mine[HANGS][LIES],char show[HANGS][LIES], int hang, int lie)
{
	int x, y, t;
	int m = 0;
	int n = 0;
	int b = 0;
	int geshu = M;
	while (n<hang*lie-geshu)//hang*lie-geshu表示无雷位置的个数,n表示已经排查了的个数
	{
		printf("请输入你要排雷的坐标\n");
		printf("行:");
		scanf("%d", &x);
		printf("列:");
		scanf("%d", &y);
		if (x <= hang && x >= 1 && y <= lie && y >= 1)//判断输入位置的合理性,合理即进入
		{
			if (show[x][y] != '*')//show数组被排查后的位置会显示附近九宫格的雷的个数,该位置不会为‘*’,防止重复排查产生错误
			{
				printf("该位置已被排查过,请重新选择");
			}
			else if (mine[x][y] == '1')//排查位置在mine数组中为‘1’,即踩到了雷,游戏失败
			{
				printf("踩到雷了,很遗憾失败了\n");
				chushi(mine, HANG, LIE);//游戏失败,显示雷的位置
				caidan1();//为一个菜单函数,进行选择再来一次或者退出游戏
				scanf("%d", &b);
				if (b == 1)
				{
					break;
				}
				else if (b == 0)
				{
					a = 0;//若选择退出游戏,使a=0,跳出这个函数后紧接着跳出游戏主体函数,结束程序运行
					break;
				}
				else
				{
					printf("输入错误,请重新输入\n");
				}
			}
			else//未踩到雷时,通过两层循环算出周围九宫格雷的个数
			{
				m = 0;//m表示周围雷的个数,初始为0
				for (int i = x - 1; i <= x + 1; i++)
				{
					for (int j = y - 1; j <= y + 1; j++)
					{
						if (mine[i][j] == '1')
						{
							m++;//若是雷,m加1
						}
					}
				}
				show[x][y] = m + '0';//m表示的数字加上‘0’,得到字符‘m’,m随上面算出的雷的个数变化而变化
				chushi(show, HANG, LIE);//打印数组show显示周围雷的个数
				n++;//每排查出一个无雷的位置,n加1,直至不符合循环条件,跳出循环
			}
		}
		else
		{
			printf("输入错误,请重新输入\n");//输入不合理,进行提醒
		}
	}
	if (n == hang * lie - geshu)//已经排查的个数与无雷的个数相同,即已经全部排查出了雷,排雷成功
	{
		printf("恭喜你,排雷成功\n");
		chushi(mine, HANG, LIE);//进行提醒:再来一次还是退出游戏
		caidan1();
		scanf("%d", &b);
		if (b == 1)
		{
			;
		}
		else if (b == 0)
		{
			a = 0;
		}
		else
		{
			printf("输入错误,请重新输入\n");
		}
	}
}

上面的菜单函数caidan1()为:

void caidan1()
{
	printf("*********************\n");
	printf("**** 1、再来一次 ****\n");
	printf("**** 0、退出游戏 ****\n");
	printf("*********************\n");
}

最后将shuru(mine,show, HANG, LIE); 填入游戏主体函数中,引入相应的值。效果如下:


到这里扫雷游戏的编写就结束了,最后附上完整代码。

6、完整代码

saolei.h

#pragma once//创建头文件后自带
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define HANG 9
#define LIE 9
#define HANGS HANG+2
#define LIES LIE+2
#define M 10
void chushihua(char buzhi[HANGS][LIES], int hangs, int lies, char t);
void chushi(char buzhi[HANGS][LIES], int hang, int lie);
void setlei(char buzhi[HANGS][LIES], int hang, int lie);
void shuru(char mine[HANGS][LIES], char show[HANGS][LIES], int hang, int lie);
int a;

test.c

#include"saolei.h"
void caidan()
{
	printf("*********************\n");
	printf("**** 1、开始游戏 ****\n");
	printf("**** 0、退出游戏 ****\n");
	printf("*********************\n");
}
void caidan1()
{
	printf("*********************\n");
	printf("**** 1、再来一次 ****\n");
	printf("**** 0、退出游戏 ****\n");
	printf("*********************\n");
}
void saolei()
{
	char mine[HANGS][LIES];
	char show[HANGS][LIES];
	chushihua(mine, HANGS, LIES, '0');
	chushihua(show, HANGS, LIES, '*');
	chushi(show, HANG, LIE);
	setlei(mine, HANG, LIE);
	shuru(mine,show, HANG, LIE);
}
int main()
{
	srand((unsigned int)time(NULL));
	
	do
	{
		
		caidan();
		scanf("%d", &a);
		switch (a)
		{
		case 1:
			saolei();
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("输入错误,请重新输入\n");
			break;
		}
	} 
	while (a);
}

saolei.h

#include"saolei.h"
void chushihua(char buzhi[HANGS][LIES], int hangs, int lies, char t)
{
	int i = 0;
	for (int i = 0; i < hangs; i++)
	{
		for (int j = 1; j < lies; j++)
		{
			buzhi[i][j] = t;
		}
	}
}
void chushi(char buzhi[HANGS][LIES], int hang, int lie)
{
	for (int i = 0; i <= hang; i++)
	{
		printf("%d ", i);
	}
	printf("\n");
	for (int i = 1; i <= hang; i++)
    {
		printf("%d ", i);
	    for (int j = 1; j <= lie; j++)
	    {
		    printf("%c ", buzhi[i][j]);
	    }
		printf("\n");
    }
}
void setlei(char mine[HANGS][LIES], int hang, int lie)
{
	int geshu = M;
	while (geshu)
	{
		int x = rand() % hang + 1;
		int y = rand() % lie + 1;
		if (mine[x][y] == '0')
		{
			mine[x][y] = '1';
			geshu--;
		}
	}

}

void shuru(char mine[HANGS][LIES],char show[HANGS][LIES], int hang, int lie)
{
	int x, y, t;
	int m = 0;
	int n = 0;
	int b = 0;
	int geshu = M;
	while (n<hang*lie-geshu)
	{
		printf("请输入你要排雷的坐标\n");
		printf("行:");
		scanf("%d", &x);
		printf("列:");
		scanf("%d", &y);
		if (x <= hang && x >= 1 && y <= lie && y >= 1)
		{
			if (show[x][y] != '*')
			{
				printf("该位置已被排查过,请重新选择");
			}
			else if (mine[x][y] == '1')
			{
				printf("踩到雷了,很遗憾失败了\n");
				chushi(mine, HANG, LIE);
				caidan1();
				scanf("%d", &b);
				if (b == 1)
				{
					break;
				}
				else if (b == 0)
				{
					a = 0;
					break;
				}
				else
				{
					printf("输入错误,请重新输入\n");
				}
			}
			else
			{
				m = 0;
				for (int i = x - 1; i <= x + 1; i++)
				{
					for (int j = y - 1; j <= y + 1; j++)
					{
						if (mine[i][j] == '1')
						{
							m++;
						}
					}
				}
				show[x][y] = m + '0';
				chushi(show, HANG, LIE);
				/*chushi(mine, HANG, LIE);*/
				n++;
			}
		}
		else
		{
			printf("输入错误,请重新输入\n");
		}
	}
	if (n == hang * lie - geshu)
	{
		printf("恭喜你,排雷成功\n");
		chushi(mine, HANG, LIE);
		caidan1();
		scanf("%d", &b);
		if (b == 1)
		{
			;
		}
		else if (b == 0)
		{
			a = 0;
		}
		else
		{
			printf("输入错误,请重新输入\n");
		}
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值