入门C语言第三话:数组之实战篇——带你从0到1实现扫雷(简易版),还不快进来学,文末附带整套代码。

前言

每日鸡汤

我们到底为什么学习?
 核心观点学习的目的,是为了获取竞争优势,增加选择机会,提升认知水平。人生就是一个不断学习的过程,终究有一天,我们会感谢现在努力学习的自己,加油吧!少年,将来的你终究会感谢努力学习的自己!

基本思路

在这里插入图片描述

一.框架与打印菜单

 当你打印菜单过后,会面临的选项,你要进行输入所对应功能的选项,时进行对应的功能,所以开始的框架必不可少,好的开始是成功的一半,接下来让我们实现它吧!

1.实现功能的分装

实现逻辑在一个源文件中,运行逻辑在另一个源文件中,可以更好地让我们的思路更加的清晰,而实现逻辑的函数声明与所需要的define与include(包含的c语言的头文件)等预处理要放在头文件中,因为这个头文件是驾起两个源文件的桥梁,并且方便数据的修改也可以起到化繁为简的作用。
如图:
在这里插入图片描述
代码的实现:

#define _CRT_SECURE_NO_WARNINGS 1
#include"mine.h"//包含的
int main()
{
	int judge = 0;
	do
	{
		menu();
		scanf("%d", &judge);
		switch (judge)
		{
		case 1:
			printf("扫雷开始\n");//这里是扫雷的实现逻辑
			break;
		case 2:
			printf("成功退出扫雷\n");
			break;
		default:
			printf("输入错误,请重新输入!\n");
			break;
		}
	}while(judge!=2);
	return 0;
}

2.菜单

下面这是实现逻辑的源文件放的函数。

void menu()
{
	printf("**************************\n");
	printf("******  1.开始扫雷 *******\n");
	printf("******  2.退出扫雷 *******\n");
	printf("**************************\n");
}

在头文件放函数的声明以及所需的头文件

#include<stdio.h>//这里如果两个源文件都要使用,只需包含项目头文件mine.h即可
void menu();

二.设置雷盘(11*11)

我们先看一下雷盘
在这里插入图片描述
这是9*9的雷盘,但你是否会想到当进行扫雷的时候,排查雷的时候如果是边上的雷和中间的雷有什么区别呢?
当边上的雷我们只会排查它周围的几个雷,而中间的则会排查周围的八个雷,试想一下,倘若这是个11 11的数组时,再进行我们再来检查一下
在这里插入图片描述
当你再在原来的棋盘(蓝色的部分)进行排查,周围的白色部分,都没有雷,这时,结果是不是还跟原来一样?结果不变,当我们只使用中间的9
9时,输入坐标是不是跟我们平常的一样(想一下数组下标的规则)?那这是不是一石二鸟?,so我们看一下实现思路,这里为了方便我们使用两个数组,一个是打印信息的数组,一个是存放雷的数组。
代码实现:
头文件

#define _CRT_SECURE_NO_WARNINGS 1
#define ROW 9//打印的行
#define COL 9//打印的列
#define ROWS (ROW+2)//实际的行
#define COLS (COL+2)//实际的列
#include<stdio.h>
//函数的声明
void menu();
void Initboard(char board[ROWS][COLS],int rows ,int cols , char letter);

实现逻辑的文件

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

运行逻辑的文件

#define _CRT_SECURE_NO_WARNINGS 1
#include"mine.h"
void game()
{
	char mine[ROWS][COLS] = { 0 };
	char show[ROWS][COLS] = { 0 };
	//初始化雷盘
	Initboard(mine ,ROWS,COLS,'0');//这是里设置第四个参数是为了更好的体现函数的兼容性
	Initboard(show, ROWS, COLS, '*');

}
int main()
{
	int judge = 0;
	do
	{
		menu();
		scanf("%d", &judge);
		switch (judge)
		{
		case 1:
			game();//这里是扫雷的实现逻辑
			break;
		case 2:
			printf("成功退出\n");
			break;
		default:
			printf("输入错误,请重新输入!\n");
			break;
		}
	}while(judge!=2);
	return 0;
}

三.打印雷盘(9*9)

我们只需打印出9*9的雷盘即可。
实现代码
头文件

#define _CRT_SECURE_NO_WARNINGS 1
#define ROW 9
#define COL 9
#define ROWS (ROW+2)
#define COLS (COL+2)
#include<stdio.h>
void menu();
void Initboard(char board[ROWS][COLS],int rows ,int cols , char letter);
void Showboard(char board[ROWS][COLS], int row, int col);

实现逻辑的文件

#define _CRT_SECURE_NO_WARNINGS 1
#include"mine.h"
void menu()
{
	printf("**************************\n");
	printf("******  1.开始扫雷 *******\n");
	printf("******  2.退出扫雷 *******\n");
	printf("**************************\n");
}
void Initboard(char board[ROWS][COLS], int rows, int cols, char letter)
{
	int i = 0;
	int j = 0;
	for (i = 0; i < rows; i++)
	{
		for (j = 0; j < cols; j++)
		{
			board[i][j] = letter;
		}
	}
}
void Showboard(char board[ROWS][COLS], int row, int col)
{
	int i = 0;
	int j = 0;
	for (i = 1; i <=row; i++)
	{
		for (j = 1; j <= col; j++)
		{
			printf("%c ", board[i][j]);
		}
		printf("\n");
	}
}

运行逻辑的文件

#define _CRT_SECURE_NO_WARNINGS 1
#include"mine.h"
void game()
{
	char mine[ROWS][COLS] = { 0 };
	char show[ROWS][COLS] = { 0 };
	//初始化雷盘
	Initboard(mine ,ROWS,COLS,'0');
	Initboard(show, ROWS, COLS, '*');
	//打印雷盘
	Showboard(mine, ROW, COL);
	Showboard(show, ROW, COL);
}
int main()
{
	int judge = 0;
	do
	{
		menu();
		scanf("%d", &judge);
		switch (judge)
		{
		case 1:
			game();//这里是扫雷的实现逻辑
			break;
		case 2:
			printf("成功退出\n");
			break;
		default:
			printf("输入错误,请重新输入!\n");
			break;
		}
	}while(judge!=2);
	return 0;
}

看一下效果:
在这里插入图片描述
这里我们会发现,这里的会有一点瑕疵,就是当你输入坐标排查雷的时候,会出现坐标不清楚的时候,而且打印棋盘中间没有空隙,会比较不好看,为了解决以上的缺点,我们做一个优化,打印分割行与坐标。
效果:
在这里插入图片描述

代码:

void Showboard(char board[ROWS][COLS], int row, int col)
{
	printf("----------扫雷---------\n");//打印分割行
	int i = 0;
	int j = 0;
	printf("  ");//与雷盘进行对齐
	for (i = 1; i <= row; i++)
	{
		printf("%d ",i);//打印列数
	}
	printf("\n");//打印过后要换行
	for (i = 1; i <=row; i++)
	{
		printf("%d ", i);//打印行数
		for (j = 1; j <= col; j++)
		{
			printf("%c ", board[i][j]);
		}
		printf("\n");
	}
}

三.放置雷(10颗)

1.生成随机数

涉及的函数(头文件都为stdio.h)
函数1:srand()——类型为unsigned int
功能:设置随机数种子,设置一次即可
函数2:time()——类型为time_t
功能:生成从1970 年 1 月 1 日 00:00 小时(即当前 unix 时间戳)以来的秒数。
函数3:rand()
功能:生成0到32767的随机数,但并不是真的生成随机数,需要设置随机数种子。
代码实现:
运行逻辑的函数

int main()
{
	srand((unsigned int)time(NULL));//生成随机数种子
	int judge = 0;
	do
	{
		menu();
		scanf("%d", &judge);
		switch (judge)
		{
		case 1:
			game();//这里是扫雷的实现逻辑
			break;
		case 2:
			printf("成功退出\n");
			break;
		default:
			printf("输入错误,请重新输入!\n");
			break;
		}
	}while(judge!=2);
	return 0;
}

注意:
1.time不知道设什么值时,设为NULL
2.srand()里面的类型为unsigned int ,因此time的返回类型要强制类型转换为srand的返回类型。

2.生成随机坐标

int x = rand()%9+1;//生成1到9的随机数作为横坐标
int y = rand()%9*1;//生成1到9的随机数作为纵坐标

3.布置10颗雷

在布置雷时,若新生成的坐标与原来坐标相等,则要再生成一次,因此要满足条件再布置。
头文件:

#define _CRT_SECURE_NO_WARNINGS 1
#define ROW 9//打印的行
#define COL 9//打印的列
#define ROWS (ROW+2)//实际的行
#define COLS (COL+2)//实际的列
#define MINE  10//雷
#include<stdio.h>
//函数的声明
void menu();
void Initboard(char board[ROWS][COLS], int rows, int cols, char letter);
void Showboard(char board[ROWS][COLS], int row, int col);
void Setmine(char board[ROWS][COLS]);

代码实现:

void Setmine(char board[ROWS][COLS])
{
	int count = 0;
	while (count < MINE)
	{
		int x = rand() % 9 + 1;
		int y = rand() % 9 + 1;
		if (board[x][y] == '0')
		{
			board[x][y] = '1';
			count++;
		}
	}
}

四.排查雷

1.具体思路

当我们输入的坐标满足情况时才可排查。
1.输入的坐标在雷盘范围
2.第二次输入的坐标不能与原坐标保持相同
3.查找的坐标不是雷
如果满足以上情况
查找坐标范围内的雷,并将其赋为周围的雷数,并打印雷盘。
查完雷或者被雷炸死跳出循环。

2.代码实现

//查找雷的个数
static int find(char board[ROWS][COLS],int x,int y)
{
	int i = 0;
	int j = 0;
	int count = 0;
	for (i = x-1; i <= x+1; i++)
	{
		for (j = y - 1; j <= y + 1;j++)
		{
			if (board[i][j] == '1')
			{
				count++;
			}
		}
	}
	return count;
}
static void is_win(int count)
{
	if (count == ROW * COL - MINE)
	{
		printf("恭喜您取得游戏胜利!\n");
	}
	else
	{
		printf("游戏失败,很遗憾您被炸死了!\n");
	}
}
void Findmine(char mineboard[ROWS][COLS], char showboard[ROWS][COLS], int row, int col)
{
	int count = 0;
	while (count<ROW*COL-MINE)//
	{
		int x = 0;
		int y = 0;
		printf("请输入坐标:");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= 9 && y >= 1 && y <= 9)
		{
			if (showboard[x][y] != '*')
			{
				printf("该坐标已被排查过了,请重新输入!\n");
				continue;
			}
			if (mineboard[x][y] == '0')
			{
				int ret = find(mineboard, x, y);//查找雷的个数
				showboard[x][y] = '0' + ret;
				Showboard(showboard, ROW, COL);
				count++;
			}
			else if (mineboard[x][y] == '1')
			{
				break;
			}
		}
		else
		{
			printf("坐标非法,请重新输入!\n");
		}
	}
	//循环终止或结束时跳到这里。
	//1.赢的话count等于棋盘数减去雷的个数
	//2.除了赢就是输
	is_win(count);//判断输赢
}

尾序

头文件:mine.h

#define _CRT_SECURE_NO_WARNINGS 1
#define ROW 9//打印的行
#define COL 9//打印的列
#define ROWS (ROW+2)//实际的行
#define COLS (COL+2)//实际的列
#define MINE  10
#include<stdio.h>
//函数的声明
void menu();
void Initboard(char board[ROWS][COLS], int rows, int cols, char letter);
void Showboard(char board[ROWS][COLS], int row, int col);
void Setmine(char board[ROWS][COLS]);
void Findmine(char mineboard[ROWS][COLS],char showboard[ROWS][COLS] ,int row, int col);

运行逻辑的源文件:源.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"mine.h"
void game()
{
	char mine[ROWS][COLS] = { 0 };
	char show[ROWS][COLS] = { 0 };
	//初始化雷盘
	Initboard(mine ,ROWS,COLS,'0');
	Initboard(show, ROWS, COLS, '*');
	//布置雷
	Setmine(mine);
	//打印雷盘
	Showboard(mine, ROW, COL);
	Showboard(show, ROW, COL);
	//排查雷
	Findmine(mine, show, ROW, COL);

}
int main()
{
	srand((unsigned int)time(NULL));//生成随机数种子
	int judge = 0;
	do
	{
		menu();
		scanf("%d", &judge);
		switch (judge)
		{
		case 1:
			game();//这里是扫雷的实现逻辑
			break;
		case 2:
			printf("成功退出\n");
			break;
		default:
			printf("输入错误,请重新输入!\n");
			break;
		}
	}while(judge!=2);
	return 0;
}

实现逻辑的源文件:mine.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"mine.h"
static int find(char board[ROWS][COLS],int x,int y)
{
	int i = 0;
	int j = 0;
	int count = 0;
	for (i = x-1; i <= x+1; i++)
	{
		for (j = y - 1; j <= y + 1;j++)
		{
			if (board[i][j] == '1')
			{
				count++;
			}
		}
	}
	return count;


}
static void is_win(int count)
{
	if (count == ROW * COL - MINE)
	{
		printf("恭喜您取得游戏胜利!\n");
	}
	else
	{
		printf("游戏失败,很遗憾您被炸死了!\n");
	}
}
void menu()
{
	printf("**************************\n");
	printf("******  1.开始扫雷 *******\n");
	printf("******  2.退出扫雷 *******\n");
	printf("**************************\n");
}
void Initboard(char board[ROWS][COLS], int rows, int cols, char letter)
{
	int i = 0;
	int j = 0;
	for (i = 0; i < rows; i++)
	{
		for (j = 0; j < cols; j++)
		{
			board[i][j] = letter;
		}
	}
}

void Showboard(char board[ROWS][COLS], int row, int col)
{
	printf("----------扫雷---------\n");
	int i = 0;
	int j = 0;
	printf("  ");
	for (i = 1; i <= row; i++)
	{
		printf("%d ",i);
	}
	printf("\n");
	for (i = 1; i <=row; i++)
	{
		printf("%d ", i);
		for (j = 1; j <= col; j++)
		{
			printf("%c ", board[i][j]);
		}
		printf("\n");
	}
}
void Setmine(char board[ROWS][COLS])
{
	int count = 0;
	while (count < MINE)
	{
		int x = rand() % 9 + 1;
		int y = rand() % 9 + 1;


		if (board[x][y] == '0')
		{
			board[x][y] = '1';
			count++;
		}
	}
}
void Findmine(char mineboard[ROWS][COLS], char showboard[ROWS][COLS], int row, int col)
{
	int count = 0;
	while (count<ROW*COL-MINE)
	{
		int x = 0;
		int y = 0;
		printf("请输入坐标:");
		scanf("%d %d", &x, &y);

		if (x >= 1 && x <= 9 && y >= 1 && y <= 9)
		{
			if (showboard[x][y] != '*')
			{
				printf("该坐标已被排查过了,请重新输入!\n");
				continue;
			}
			if (mineboard[x][y] == '0')
			{
				int ret = find(mineboard, x, y);
				showboard[x][y] = '0' + ret;
				Showboard(showboard, ROW, COL);
				count++;
			}
			else if (mineboard[x][y] == '1')
			{
				break;
			}
		}
		else
		{
			printf("坐标非法,请重新输入!\n");
		}
	}
	is_win(count);
}

总结

如果能认真看到这里,我坚信你能收获很多很多!也希望这篇文章能帮助到你,如果觉得不错,请点击一下不要钱的赞,如果有误请温柔的指出,在这里感谢大家了!

下一篇我将会将扫雷进行以下优化:

  1. 能够展开一片的操作
  2. 标记和取消雷
  3. 显示剩余雷的个数
  4. 图形化界面
  • 17
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 16
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值