C语言——扫雷小游戏简易版(数组与函数的实践)

引言:在我们已经学习了前两篇内容(数组和函数)的情况下,我们也可以尝试写一些小游戏来对我们学习的知识予以运用。接下来我们就来请出这次的“lucky dog”——扫雷。

目录

一、扫雷游戏的分析

二、游戏所需文件(多文件形式)

1.test.c(主测试文件)

2.game.c和game.h(游戏逻辑)

三、游戏核心内容实现

1.简要问题概述

2.棋盘的打印及初始化

3.布置雷

4.排查雷

5.确定雷的个数 

四、三个文件的总列出

一、扫雷游戏的分析

游戏说明:游戏可以通过菜单实现继续玩或者退出游戏,扫雷游戏的基础版本是9×9的格子,默认随机布置10个雷。玩家需要对雷的位置进行排查,如果所排查的位置不是雷,就会显示周围有几个雷;如果排查的位置是雷,就会被炸死从而游戏结束。当然游戏结束的情况有两种可能:一就是前面说的被炸死结束游戏,二就是把除10个雷之外的所有非雷都找出来,则排雷成功,游戏结束。

这是扫雷游戏的基础版本:

二、游戏所需文件(多文件形式)

1.test.c(主测试文件)
2.game.c和game.h(游戏逻辑)

仔细观察游戏说明发现:游戏肯定不止玩一次;游戏肯定要有菜单以及游戏内容,那么这菜单以及游戏内容肯定需要函数来封装吧,是不是感觉有那么一点熟悉,没错,就是我们前面所介绍的猜数字游戏,里面有大同小异之处,感兴趣的可跳转:C语言——猜数字游戏与关机程序(详细版)_c语言 猜数游戏-CSDN博客

三、游戏核心内容实现

1.简要问题概述

那么开始我们的第一步:主测试文件的大体框架

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>


void menu()
{
	printf("****************************\n");
	printf("********   1.play   ********\n");
	printf("********   0.exit   ********\n");
	printf("****************************\n");

}


void game()
{
	printf("扫雷\n");
}



int main()
{
	int input = 0;
	do
	{
		menu(input);
		printf("请选择你的数字:");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			game();//玩游戏的逻辑与内容
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("输入错误,就俩数,重新输入\n");
		}
	} while (input);

	return 0;
}

初始运行结果如下:

接下来第二步我们就需要在game函数里完善扫雷游戏的代码

void game()
{
	//完善扫雷游戏内容
}

那么我们应该如何完成这个游戏内容呢?

扫雷扫雷,我们首先需要做的是什么?是不是布置雷?布置完后是不是还要将其存储起来,那么我们就可以使用二维数组来对其进行存储。那么我们应该如何区分是雷和不是雷呢?我们可以定义“1”是雷,“0”不是雷。

注:这里的0和1皆为字符0和字符1。

两个数组皆为字符数组。

但是这样又会存在一个问题,这里的“1”究竟是雷的个数是1,还是说就是这个位置是雷呢?这样会产生歧义。所以为了让我们更加容易辨认,我们应该使用两个数组来进行区分。

这个用来部署雷的信息:

这个用来部署排查的雷的信息:

但是当我们排查时会发现一个问题:越界。

所以9×9的格子已经无法满足,我们需要加以改进:引用11×11的格子。这样在排查如图所示的两个位置时就不会出现越界了。

2.棋盘的打印及初始化

我们专门给一个棋盘(对应一个数组mine)用来存放给布置好的雷的信息,给另一个棋盘(对应一个数组show)用来存放排查出的雷的信息。

test.c
//打印棋盘
DisplayBoard(mine, row, col);//我们真正需要的是中间的9*9格子
DisplayBoard(show, row, col);

接下来要做的就是打印这两个棋盘,观察有无错误。

game.c
void DisplayBoard(char board[rows][cols], int r, int c)
{
	int i = 0;
	printf("-------扫雷-------\n");
	//打印列号
	for (i = 0;i <= c;i++)
	{
		printf("%d ", i);
	}
	printf("\n");
	for (i = 1;i <= r;i++)
	{
		int j = 0;
		printf("%d ", i);
		for (j = 1;j <= c;j++)
		{
			printf("%c ", board[i][j]);
		}
		printf("\n");
	}
}

随后进行棋盘的初始化:

test.c
//棋盘初始化
//mine数组初始化为全'0',表示还没有布置雷
//show数组初始化全为'*',表示所有位置都没有被排查
InitBoard(mine, rows, cols,'0');
InitBoard(show, rows, cols,'*');
game.c
#include "game.h"//自定义函数头文件用双引号
void InitBoard(char board[rows][cols], int r, int c,char set)
{
	int i = 0;
	for (i = 0;i < r;i++)
	{
		int j = 0;
		for (j = 0;j < c;j++)
		{
			board[i][j] = set;
		}
	}
}
3.布置雷
test.c

	//布置雷
	SetMine(mine, row, col);

game.c
void SetMine(char mine[rows][cols], int r, int c)
{
	//随机布置10个雷
	int count = EASY_COUNT;
	while (count)
	{
		//随机生成坐标
		//x,y的范围是都是1~9
		int x = rand() % r + 1;
		int y = rand() % c + 1;
		if (mine[x][y] == '0')
		{
			mine[x][y] = '1';
			count--;
		}


	}
}

4.排查雷
test.c
//排查雷
FindMine(mine, show, row, col);
game.c
void FindMine(char mine[rows][cols], char show[rows][cols], int r, int c)
{
	int x = 0;
	int y = 0;
	int win = 0;
	while (win<r*c-EASY_COUNT)
	{
		printf("请输入要排查的坐标:");
		scanf("%d %d", &x, &y);
		//判断坐标的合法性
		if (x >= 1 && x <= r && y >= 1 && y <= c)
		{
			//判断是否为雷
			if (mine[x][y] == '1')
			{
				printf("sorry,你被炸死了\n");
				DisplayBoard(mine, r, c);
				break;
			}
			else
			{
				if (show[x][y] == '*')
				{
					//统计mine数组中,x,y坐标周围有几个雷
					int c = GetMineCount(mine, x, y);
					show[x][y] = c + '0';
					DisplayBoard(show, row, col);
					win++;
				}
				else
				{
					printf("该坐标已经被排查,请重新输入坐标:\n");
				}
				
			}
		}
		else
		{
			printf("输入的坐标非法,请重新输入\n");
		}
	}
	if (win = r * c - EASY_COUNT)
	{
		printf("恭喜你,排雷成功\n");
		DisplayBoard(show, r, c);
	}
}
5.确定雷的个数 
game.c
int GetMineCount(char mine[rows][cols],int x,int y)
{
	// 法一:return mine[x][y+1]+mine[x-1][y+1]+minr[x-1][y]+mine[x-1][y-1]+mine[x][y-1]+mine[x+1][y-1]+mine[x+1][y]+mine[x+1][y+1]-8*'0';
	int i = 0;
	int j = 0;
	int c = 0;
	for (i = -1;i <= 1;i++)
	{
		for (j = -1;j <= 1;j++)
		{
			if (mine[x + i][y + j] == '1')
				c++;
		}
	}
	return c;

这里的法一原理如下图所示:

如图所示,我们想要知道箭头所指之处周围有几个雷应该怎么办呢?我们将其设为x,y,故周围参数依次得出。那么我们只需要将其求和(字符求和)减去8*'0'就可以得到雷的个数了。

法二本质上就是把法一写成两个循环。

四、三个文件的总列出

接下来我会将三个总文件(一些问题均以在代码中进行标注)逐个列出:

test.c:

#define _CRT_SECURE_NO_WARNINGS
#include "game.h"


void menu()
{
	printf("****************************\n");
	printf("********   1.play   ********\n");
	printf("********   0.exit   ********\n");
	printf("****************************\n");

}


void game()
{
	//完善扫雷游戏内容
	char mine[rows][cols] = { 0 };//存放布置好的雷的信息
	char show[rows][cols] = { 0 };//存放排查出的雷的信息
	//棋盘初始化
	//mine数组初始化为全'0',表示还没有布置雷
	//show数组初始化全为'*',表示所有位置都没有被排查
	InitBoard(mine, rows, cols,'0');
	InitBoard(show, rows, cols,'*');

	//布置雷
	SetMine(mine, row, col);
	//打印棋盘
	DisplayBoard(mine, row, col);//我们真正需要的是中间的9*9格子
	DisplayBoard(show, row, col);
	//排查雷
	FindMine(mine, show, row, col);
} 



int main()
{
	int input = 0;
	srand((unsigned int)time(NULL));//game.c中的随机布置雷
	do
	{
		menu(input);
		printf("请选择你的数字:");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			game();//玩游戏的逻辑与内容
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("输入错误,就俩数,重新输入\n");
		}
	} while (input);

	return 0;
}

game.c:

#define _CRT_SECURE_NO_WARNINGS



#include "game.h"//自定义函数头文件用双引号
void InitBoard(char board[rows][cols], int r, int c,char set)
{
	int i = 0;
	for (i = 0;i < r;i++)
	{
		int j = 0;
		for (j = 0;j < c;j++)
		{
			board[i][j] = set;
		}
	}
}

void DisplayBoard(char board[rows][cols], int r, int c)
{
	int i = 0;
	printf("-------扫雷-------\n");
	//打印列号
	for (i = 0;i <= c;i++)
	{
		printf("%d ", i);
	}
	printf("\n");
	for (i = 1;i <= r;i++)
	{
		int j = 0;
		printf("%d ", i);
		for (j = 1;j <= c;j++)
		{
			printf("%c ", board[i][j]);
		}
		printf("\n");
	}
}
void SetMine(char mine[rows][cols], int r, int c)
{
	//随机布置10个雷
	int count = EASY_COUNT;
	while (count)
	{
		//随机生成坐标
		//x,y的范围是都是1~9
		int x = rand() % r + 1;
		int y = rand() % c + 1;
		if (mine[x][y] == '0')
		{
			mine[x][y] = '1';
			count--;
		}


	}
}

int GetMineCount(char mine[rows][cols],int x,int y)
{
	// 法一:return mine[x][y+1]+mine[x-1][y+1]+minr[x-1][y]+mine[x-1][y-1]+mine[x][y-1]+mine[x+1][y-1]+mine[x+1][y]+mine[x+1][y+1]-8*'0';
	int i = 0;
	int j = 0;
	int c = 0;
	for (i = -1;i <= 1;i++)
	{
		for (j = -1;j <= 1;j++)
		{
			if (mine[x + i][y + j] == '1')
				c++;
		}
	}
	return c;
}






void FindMine(char mine[rows][cols], char show[rows][cols], int r, int c)
{
	int x = 0;
	int y = 0;
	int win = 0;
	while (win<r*c-EASY_COUNT)
	{
		printf("请输入要排查的坐标:");
		scanf("%d %d", &x, &y);
		//判断坐标的合法性
		if (x >= 1 && x <= r && y >= 1 && y <= c)
		{
			//判断是否为雷
			if (mine[x][y] == '1')
			{
				printf("sorry,你被炸死了\n");
				DisplayBoard(mine, r, c);
				break;
			}
			else
			{
				if (show[x][y] == '*')
				{
					//统计mine数组中,x,y坐标周围有几个雷
					int c = GetMineCount(mine, x, y);
					show[x][y] = c + '0';
					DisplayBoard(show, row, col);
					win++;
				}
				else
				{
					printf("该坐标已经被排查,请重新输入坐标:\n");
				}
				
			}
		}
		else
		{
			printf("输入的坐标非法,请重新输入\n");
		}
	}
	if (win = r * c - EASY_COUNT)
	{
		printf("恭喜你,排雷成功\n");
		DisplayBoard(show, r, c);
	}
}

game.h:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
//定义常量的符号
#
#define row 9
#define col 9
#define rows row+2
#define cols col+2

#define EASY_COUNT 10

//函数声明
//初始化棋盘
void InitBoard(char board[rows][cols], int r, int c,char set);
//打印棋盘信息
void DisplayBoard(char board[rows][cols],int r,int c);//实际上打印的是11*11的棋盘
//布置雷
void SetMine(char mine[rows][cols], int r, int c);
//排查雷
void FindMine(char mine[rows][cols], char show[rows][cols], int r, int c);

结语:以上就是本次扫雷游戏的流程代码以及总代码,希望可以对你有所帮助,提升学习C语言的兴趣。 后续会接着为大家更新相关内容。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值