C语言扫雷初步实现、思路

这篇文章我会简要分析扫雷的实现办法

扫雷需要对数组和函数有灵活的运用,会利用循环和分支实现扫雷判定,同时要学会用分支语句、断点调试去细化规则,防止bug的出现,这对我们的代码理解有很大的帮助,同时也能进一步规范我们的代码习惯,学会合理使用.c和.h文件,训练我们用有限的知识来实现目标的能力。

1.创建3个文件

在进行这种较大项目时,我们要用到很多函数将大问题细化,如果写到一个文件里,会导致代码可读性下降,因此创建三个文件test.c、game.c和game.h。其中test.c负责游戏主干,game.c负责游戏主要功能的实现,game.h负责函数的声明

小技巧:函数声明,引入库函数可以集中在自己创建的.h文件中,这样test.c和game.c只需要引用game.h就可以同时引入多个库函数头文件,很方便

#define _CRT_SECURE_NO_WARNINGS 1

#define ROW 9

#define COL 9

#include <stdlib.h>

#include <stdio.h>

#include <time.h>

#include <windows.h>


void GameMain();


int choose();

2.写出游戏主干

实现游戏的第一步,是将一些必要的但简单的框架敲出来,让游戏有一个基本逻辑

首先打印菜单,其次选择是否游戏,如果是则开始游戏,否就退出游戏

写代码的过程多用函数简化,使得代码更易读

写函数应先确定函数名和参数,在写完框架后在具体考虑如何实现


#include "game.h"

int main()
{
	srand((unsigned)time(NULL));//时间种子

	do
	{
		int choice = 0;

		menu();//打印菜单(void)

		choice = choose();//选择是否开始游戏(int),函数返回值决定去向

		system("cls");

		if (choice == 1)

			GameMain();//开始游戏,进入游戏主函数(void)
		
		else if (choice == 0)
		{
			printf("你已退出游戏\n");
			break;//跳出循环,结束游戏

		}
		else
			printf("请重新选择\n");

	} while (1);//一轮游戏完成后重复该过程或break跳出循环
	


	return 0;
}

其中,时间种子是我后加上去的,开始的时候可以不管它。最重要的是do while循环,下面是我menu和choice函数的实现,比较简单


void menu()//打印菜单
{
	printf("*****************************\n");
	printf("****     1.开始游戏      ****\n");
	printf("****     0.退出游戏      ****\n");
	printf("*****************************\n");

}

int choose()//选择是否开始游戏
{
	int i = 0;
	scanf("%d", &i);
	return i;
}

3.游戏主函数的实现

在进入游戏主函数之后,我们需要知道

(1)扫雷需要两个棋盘,一个用于展示,另一个需要储存信息。

(2)扫雷需要将数组进行初始化,并使它们各司其职

(3)扫雷在选定一个坐标后需要对该格子做出判定,如果踩雷则退出,没踩雷需要对周围8个格子雷的个数进行计算并把信息展示出来,最后要对扫雷成功做出判定。

4.创建棋盘

兼顾(1)(3)要防止判定越界问题,即在边角对周围8个格子统计雷的个数时,不能超出数组的范围,所以在9*9的棋盘上游戏时,我们需要11*11的数组,隐藏最外层

布置雷要使用rand函数,在mian函数下布下时间种子,产生随机数用于产生雷

游戏主函数逻辑如下


void GameMain()
{
	
	int count = 81;//共81个格子,根据格子剩余数判定输赢
	char arr_show[ROW + 2][COL + 2] = { 0 };//该数组用于展示,不储存雷的信息
	int arr_me[ROW + 2][COL + 2] = { 0 };//该数组用于储存雷的信息,不展示
	mine(arr_me);//布置十颗雷
	init(arr_show);//将用于展示的数组初始化
	while (1)//进入游戏循环
	{
		int ret = 0;//接收输赢信息
	
		Boardprint(arr_show);//打印棋盘
		ret = Gather(arr_me, arr_show,count);//收集判定信息
	
		if (ret == 82)//游戏输了
		{
			
			break;
		}
		if (ret == 10)//剩下10颗都是雷
		{
			printf("你赢了\n");
			break;
		}

	}
	
}

布置雷函数实现如下


void mine(int arr_me[ROW + 2][COL + 2])//布置十颗雷
{
	int a = 0;
	int	b = 0;
	int i = 0;
	
	for (i = 10; i >= 1;)
	{
		a = (rand() % ROW) + 1;
		b = (rand() % COL) + 1;

		if (arr_me[a][b] != 1)
		{
			arr_me[a][b] = 1;
			i--;
		}

	}
	

}

初始化展示的棋盘对应的函数表示如下


void init(char arr_show[ROW + 2][COL + 2])//将展示出来的数组标上'*'
{
	int i = 0;

	for (i = 1; i <= ROW; i++)
	{
		int j = 0;

		for (j = 1; j <= COL; j++)
		{
			arr_show[i][j] = '*';
		}
    }


}

 

5.打印展示出来的数组

从数组的第二行第二列作为展示的第一行第一列打印出来,同时要标出坐标方便选择


void Boardprint(char arr_show[ROW + 2][COL + 2])//打印每步操作后的数组
{
	int i = 0;
	int j = 0;

	system("cls");
	
	for (i = 0; i <= ROW; i++)
	{
		printf("%d ", i);

	}
	printf("\n");
	for (j = 1; j <= COL; j++)
	{
		int k = 0;
		printf("%d ", j);
		for (k = 1; k <= COL; k++)
		{
			printf("%c ",arr_show[j][k]);

		}
		printf("\n");
		
	}


}

最终效果如下

ee3a1aaa6f0d4beea28867e2b230350e.png

6.实现判定


int Gather(int arr_me[ROW + 2][COL + 2], char arr_show[ROW + 2][COL + 2], int count)//用于收集坐标、判定是否被炸死、是否能赢
{
	int a = 0;
	int b = 0;
	int i = 0;

	printf("请输入坐标,中间用空格分开\n");

	scanf("%d %d", &a, &b);

	if (arr_me[a][b] == 1)
	{

		printf("你被炸死了\n");//被炸死
	
		return 82;
	}

	else
	{


		//点开一个格子显示周围有几颗雷
		i = arr_me[a + 1][b + 1] + arr_me[a + 1][b] + arr_me[a + 1][b - 1] + arr_me[a][b + 1] + arr_me[a][b] + 
			
			arr_me[a][b - 1] + arr_me[a - 1][b + 1] + arr_me[a - 1][b] + arr_me[a - 1][b - 1];

		arr_show[a][b] = i + '0';//将这个整型值转为字符赋给char数组

		
		return --count;//每点开一个格子剩余格子-1,用于最后判断赢
	
	}

}

其中,因为只有81个格子,所以在被雷炸死时,我返回82,在没被雷炸死时,我以剩余格子数为信息返回,再由游戏主函数的分支语句判定是break还是继续循环,在arr_me和arr_show进行转换时,注意字符和数字要用'0'来转化,如'9' == 9 + '0',同样地,4 == '4' - '0'。

于是,游戏已经实现了,但其中有的易错点需注意,在初始化数组时,千万不要图方便将arr_show[ROW + 2][COL + 2]传过去,因为我们需要传的是数组首元素地址,而这种表示形式是函数中间的一个元素,会报错,我就是在这里被卡了4天

mine(arr_me[ROW + 2][COL + 2]);//err

init(arr_show[ROW + 2][COL + 2]);//err

完整代码我储存在了Gitee上:链接为

仅练习/test_2023_10_30(扫雷)/test_2023_10_30 · SGlow/C语言学习记录 - 码云 - 开源中国 (gitee.com)

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值