C语言手把手教你敲小项目-扫雷详解(0基础也能会)

提示:此扫雷只是简易版,完善了基本的功能,需要什么拓展功能请留言,我以后会出。源码我放在我主页我分享的文件里,需要自取。


扫雷的基本逻辑

提示:首先编写扫列游戏前我们必须弄懂这个游戏怎么玩,怎么判断输赢以及一些运行逻辑:

在这里插入图片描述
如图所示,我们从中可以得到信息:
1,扫雷界面是由一个 长 * 宽得到的格子的集合
2,点击方块,方块会得到一个数字,这个数字表示在此坐标的周围8个坐标中有一个雷。
3,输赢条件:踩到雷输,假设这个棋盘埋了10个雷,那么只要棋盘上只存在10个坐标的时候就赢
注意:但是在c语言中我们现在不采用这种界面,我们输出棋盘的样式主要是由‘*’代表没排雷前的坐标样式用Printf输出。


一、创建项目以及文件

1,创建项目Saolei
2,在头文件中创建 game.h文件,主要用来进行符号的定义,以及函数的声明
3,在源文件中创建text.c文件,主要用来编写main函数进行游戏测试运行。
4,在源文件中创建game.h文件,主要用于函数的封装,函数的主体部分的编写。
在这里插入图片描述

二、编写程序

main函数及菜单打印函数

main函数主体代码:

int main() {
	int input = 0;
	do {
	
		menu();  //游戏菜单打印函数
		printf("请选择:--->\n");
		scanf("%d",&input);
		switch (input) {
		case 1:
			game();  //游戏的运行逻辑函数
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("选择错误\n");
			break;
		}

	} while (input);
	return 0;
}

讲解:
1,menu,函数是游戏菜单函数,用来打印游戏界面
2,scanf输入的值好让玩家进行选择所以用循环控制,当玩家选择为非0时条件为真,执行循环;当玩家选择为0时条件为假,退出循环。
3,因为游戏菜单至少要打印一次,所以这里选择的是do…while…语句

menu函数:(注意menu函数和main函数在同一个文件里)

void menu() {
	printf("******************************************\n");
	printf("************     1. PLAY       ***********\n");
	printf("************     0. EXIT       ***********\n");
	printf("******************************************\n");
}

1.游戏逻辑部分编写

在上面,我们虽然实现了游戏菜单的功能,但是游戏的逻辑部分我们还没完成,接下来我们看游戏逻辑应该怎么设置:

void game() {
	//初始化棋盘
	
	//显示打印棋盘
	
	//布置雷
	
	//排查雷
}

以上就是我们要实现的4个游戏逻辑

初始化棋盘函数

注意:接下来的函数我们都在game.c文件里进行函数主体部分的编写,并且要在头文件game.进行声明

棋盘的逻辑及InitBoard(初始化棋盘函数)

我们要初始化棋盘,就必须得现有棋盘,为了减小代码的工作量,我们这里就用设置两个二维数组,设置两个棋盘,
一个是mine棋盘,用来存放埋雷的信息
一个是show棋盘用来存放玩家排雷的信息


void game() {
	char mine[ROWS][COLS] = {0};
	char show[ROWS][COLS] = {0};
	//初始化棋盘
	InitBoard(mine,ROWS,COLS,'0');//初始化字符为‘0’;
	InitBoard(show,ROWS,COLS,'*');//初始化字符为‘*’;
	//显示打印棋盘

	//布置雷
;
	//排查雷
}

这里为什么要初始化字符为字符0和字符*
1,初始化mine 数字为字符 0 ,是因为我们用字符 0 代表这个坐标没有雷,用字符1在mine数组代表有雷,方便我们后面进行排查雷之后显示该位置周围有几个雷的判断。
2,初始化show数组为字符*,是因为在这里我们把棋盘看成是用组成的棋盘所以这里用
棋盘这里定义的是符号,如图下在头文件声明:

#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
#define EAY_COUNT 10(这里下一个函数会用到这个符号)

InitBoard函数体:

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


}

显示打印棋盘函数Displayboard()

//打印棋盘
void Displayboard(char board[ROWS][COLS], int row, int col) {
	int i = 0;
	int j = 0;
	printf("=======扫雷========\n");
	for (j = 0; j <= col;j++) {  //行数坐标
		printf("%d ",j);
	}
	printf("\n");//打印完之后换行
	for (i = 1; i <= row;i++) {
		printf("%d ", i);    //列数坐标
		for (j = 1; j <= col;j++) {
			printf("%c ",board[i][j]);  
		}
		printf("\n"); //打印完换行
	}

这里需要注意的就是:
1,要打印行数来观察坐标,使游戏更容易上手
2,列数坐标也需要打印

布置雷函数SetMine()

void SetMine(char mine[ROWS][COLS], int row, int col) {
	int count = EAY_COUNT;  //埋雷的数量为10个,也就是EAY_COUNT符号定义所代表的数字
	//每次埋雷减少一个知道count为假
	while (count) {
		int x = rand() % row + 1;
		int y = rand() % col + 1;  //相当于膜上9,余数的取值范围为0-8,在加上1取值范围就变成了1-9
		if (mine[x][y] == '0') {
			mine[x][y] = '1';
			count--;
		}


	}


}

1,时间戳库函数的调用要引用头文件,不然会报错
2,rand()函数调用之后,要设置srand函数
3,之后给x,y设置随机的数,然后在棋盘随机位置埋下10个雷也就是我们定义的外部符号EAY_COUNT = 10 =count变量

排查雷函数FindMine()

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 - EAY_COUNT) {
		printf("请输入要排查的坐标:--->");
		scanf("%d %d",&x,&y);
		//判断坐标是否合法
		if (x >= 1 && x <= row && y >= 1 && y <= col) {
			if (show[x][y] == '*') { //判断坐标是否已经被排查
				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");
			}
		}
		else {
			printf("排查的坐标非法,请重新输入:--->\n");
		}
	}
	//成功之后提示
	if (win == row * col - EAY_COUNT) {
		printf("恭喜你,排雷成功了!!\n");
	}

}

这里需要注意的是:
1,判断条件和循环嵌套容易出错

统计坐标周围雷的数量函数 GetMineCount

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][y + 1] +
		mine[x + 1][y] +
		mine[x + 1][y + 1] +
		mine[x][y + 1] +
		mine[x - 1][y + 1] - 8 * '0');

}

//因为之前定义埋雷数组的值为字符1和字符0.1表示有雷,0表示没雷,所以想要得到一个坐标周围8个坐标雷的数量
//就应该把所有字符相加在减去8个字符0,就可以得到数据了,因为字符0-数字0等于数字0,所以得到的就全是有雷的数量的数据
//坐标一定要输对,,这里容易写漏或者写错

总结(编写项目时的注意事项,以及容易发生的错误)

1,写项目时在Text.c文件中,text函数里调用的函数要在头文件game.h中进行声明。
2,在game.h声明的函数要在game.c中进行创建
3,注意函数的返回值类型,以及实参和形参的类型定义是否相同
4,一定要写注释,增强代码的可读性,方便调试,不易出错。
5,注意scanf()里绑定变量前面要加取地址符号&

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值