C语言:扫雷游戏(初级简易版)

1.涉及知识

数组,函数(除递归),分支与循环

2.功能

I.可实现的功能

1.输入坐标可判断该坐标是否有雷,以及周围雷的个数

2.仅是简单难度版扫雷(格子9*9, 10雷)

II.无法实现的功能

1.选择难度(仅做出菜单,未实现功能)

2.选择计时器功能(仅做出菜单,未实现功能)

3.输入坐标后若周围没雷会自动向周围散开,直至出现周围有雷的区域。

3.实现扫雷游戏(简单难度)的思路

I.基本逻辑

1.9行9列的格子,每个格子要么是雷,要么不是雷。

2.失败条件:点到雷;胜利条件:不踩雷的情况下点开剩下的71个格子。

3.点到一个非雷的格子,要能够显示周围有多少颗雷。

II.逻辑实现

基本逻辑1:9行9列的格子可以用二维数组实现。对于每个格子,要么是雷,要么不是雷,是不是雷对于游戏很关键,所以可以在创建二维数组的时候,给雷与非雷不同的字符。

基本逻辑2:对于失败条件,需要在游戏过程中使用一个函数:这个函数的功能是通过判断数组的字符,来检测玩家输入的坐标格子是不是雷,是雷就触发失败相应的内容,不是雷就继续;对于胜利条件,我们需要用一个step变量来储存玩家操作次数,如果step=71且最后一次没踩雷,则触发胜利相应的内容。

基本逻辑3:当检测玩家输入的坐标格子为非雷后,还需要一个函数:这个函数的功能是检测周围雷的个数,并且返回相应的数量给到坐标格子显示。

4.逐步实现思路

I.菜单制作

为方便后续添加更多功能,此处菜单将无法实现的功能提前加上了,下面为方便讲解,提前放出主函数文件的所有代码,接下来会一 一讲解:

菜单制作环节,运用了分支与循环的逻辑。让玩家玩完后仍可以继续,故需要用循环时刻检测玩家的状态。这个地方还需要注意玩家可能会输入其它数字,所以要做个default分支来反馈不合法输入。

//主函数文件

#include "game.h"
#include "option.h"

void menu()  //菜单页面
{
	printf("---------------------\n");
	printf("--------1.play-------\n");
	printf("-------2.option------\n");
	printf("--------0.quit--------\n");
	printf("----------------------\n");
}

void game()  //游戏运行函数
{
	//初始化
    char real[ROWS][COLS] = { 0 };
	char show[ROWS][COLS] = { 0 };
	init(real,ROWS,COLS,'0');
	init(show,ROWS,COLS,'*');
	//打印
	print(show, ROW, COL);
	//生成雷
	MineMaker(real,ROW,COL);
	//排雷
	MineFinder(real, show, ROWS, COLS);
}

int main()
{
	srand((unsigned int)time(NULL));  //后续生成雷需要使用随机数,此处先初始化种子
	int start = 0;
	printf("欢迎来到\"扫雷\"游戏!\n");
	do 
	{
		menu();
		printf("请输入数字:");
		scanf("%d", &start);
		system("cls");  //输入数字后清屏,用来优化游戏体验
		switch (start)
		{
		case 1:
		{
			game();
			break;
		}
		case 2:
		{
			option();
			break;
		}
		case 0:
		{
			printf("退出游戏\n");
			break;
		}
		default:
		{
			printf("输入不合法,请重新输入\n");
			break;
		}
		}
	} while (start);
	return 0;
}

II.游戏运行逻辑

1.实现"逻辑实现一"

创建所谓“格子”的二维数组,但需要注意的是,在一开始我们需要向玩家展示的应该是没有差别的未知格子" * ",而我们对于每个格子都要有“雷”与“非雷”两个标签,这其中的差异需要我们创建两个数组:一个叫real意味实际的“格子”,用于我们判断与检测雷;一个叫show意味展示给玩家的“格子”,用于给玩家展示。

PS:在检测雷的时候,我们需要对格子四周进行检测,如果只创建9*9的二维数组会越界报错,所以此处应创建11*11的二维数组,给玩家展示的时候仅需要打印show中间9*9的数组元素。

下面先进行数组的初始化:

#define EasyMine 10
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2

void init(char arr[ROWS][COLS], int r, int c, char set)
{
	for (int i = 0;i < r;i++)
	{
		for (int j = 0;j < c;j++)
		{
			arr[i][j] = set;
		}
	}
}

//创建数组
char real[ROWS][COLS] = { 0 };
char show[ROWS][COLS] = { 0 };
//初始化数组
init(real,ROWS,COLS,'0'); //字符'0'代表非雷,先统一生成'0',后用随机数生成雷
init(show,ROWS,COLS,'*');

初始化完后,需要向玩家展示界面:

#define EasyMine 10
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2

void print(char arr[ROWS][COLS], int r, int c)
{
	for (int i = 0;i <= r;i++)
	{
		printf("%d ", i);
	}
	printf("\n");
	for (int i = 1;i <= r;i++)
	{
		printf("%d ", i);
		for (int j = 1;j <= c;j++)
		{
			printf("%c ", arr[i][j]);
		}
		printf("\n");
	}
}

	print(show, ROW, COL);

下面来随机生成雷:

#define EasyMine 10
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2

//生成雷
void MineMaker(char arr[ROW][COL], int r, int c)
{
	int count = EasyMine;
	while (count)
	{
		int x = rand() % r + 1;
		int y = rand() % c + 1;
		if (arr[x][y] != '1')
		{
			arr[x][y] = '1';
			count--;
		}
	}
}

MineMaker(real,ROW,COL); //生成的雷应该在9*9范围内,故传的两个参数都为9

2.实现“逻辑实现2”

#define EasyMine 10
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2

void MineFinder(char arr1[ROWS][COLS], char arr2[ROWS][COLS], int r, int c)
{
	int step = 0;
	while (step <= ROW * COL - 10)
	{
		int output = 0;
		int input_x = 0;
		int input_y = 0;
		printf("请输入坐标:");
		int num = scanf("%d%d", &input_x, &input_y);
		if (num != 2) {                     // 未成功读取两个整数
			printf("输入不合法,请重新输入\n");
			// 清空缓冲区直到换行符
			while (getchar() != '\n');
			continue;                       // 跳过本次循环后续操作
		}
		if (input_x >= 1 && input_x <= ROW && input_y >= 1 && input_y <= COL)
		{
			switch (arr1[input_x][input_y] - 48)
			{
			case 1:
			{
				printf("你被炸死了\n\n");
				print(arr1, ROW, COL);
				printf("\n即将返回到主菜单");
				Sleep(7000);
				system("cls");
				return;
			}
			case 0:
			{
				check_mine(arr1[ROWS][COLS], arr2[ROWS][COLS], input_x, input_y, step);
			}
			}
		}
		else
		{
			printf("输入不合法,请重新输入\n");
			Sleep(1000);
		}
		system("cls");
		print(arr2, ROW, COL);
	}
		printf("恭喜你扫雷成功!\n");
		print(arr1, ROW, COL);
}

	MineFinder(real, show, ROWS, COLS);

这段代码较为复杂,下面进行讲解:

1.需要统计step来判断是否胜利,故创建个step变量,并且找雷动作需要在游戏过程中反复执行,故需要step<=71作为while循环条件

2.游戏过程中,玩家需要输入坐标来排雷,故需要接收接受玩家输入的坐标,此处用input_xinput_y接收。为防止用户乱输入字符存入缓存区,scanf无法读取导致死循环,需要引入num在每次输入后检测输入的是否为数字,若不是则清除缓存重新输入。

3.为防止玩家输入的数字超过9*9范围引发越界等问题,也需要检查玩家输入的数字是否合法,合法则进行相应判断,不合法也得重新输入。

4.用户输入合法后,我们需要判断是不是雷。由于初始化时用的是字符'0'与'1',此处switch判断需要减去'0'的ASCII码48。是雷就触发相应的失败内容,不是雷就对检测周围的雷数。

5.若玩家71步下来均未踩雷,则触发相应胜利内容。

3.实现"逻辑实现3"

#define EasyMine 10
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2

void check_mine(char arr1[ROWS][COLS],char arr2[ROWS][COLS],int x,int y,int step)
{
	int output = 0;
    //检测周围八个格子
	for (int i = -1;i <= 1;i++)
	{
		for (int j = -1;j <= 1;j++)
			output += arr1[x + i][y + j];
	}
	output -= 432; //如果周围都不是雷,则9个'0'的ASCII码和为432
	arr2[x][y] = output + '0';
	step++;
}

5.分文件管理

将“play”相应的代码放到game.c中,将"option"相应的代码放到option.c中,另加相应头文件声明。用到的库函数头文件如下:

#include <time.h>
#include <stdlib.h>
#include <stdio.h>
#include <Windows.h>

6.源代码分享

 附上我gitee上的源代码: 7.31 · whitedoor/作业 - 码云 - 开源中国

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值