C语言小游戏之——扫雷(含递归)

本文介绍了一个使用C语言编写的扫雷游戏。游戏分为3个文件:test.c、game.c、game.h。test.c负责游戏界面和框架,game.c实现游戏功能,game.h包含函数声明和头文件。游戏流程包括初始化棋盘、设置雷区、排查雷区等步骤,通过用户输入进行交互。代码中还包含了打印棋盘、布局雷区、查找周围雷数等功能的实现。
摘要由CSDN通过智能技术生成

首先我们将这个小游戏分成了3个文件来写,分别是test.c、game.c、game.h

test.c内部主要是进入游戏的界面和呈现一个总体的框架

game.c内部主要进行在test.c内game函数里出现的各种函数功能的具体实现。

game.h内部主要进行对test.c内game函数里出现的各种函数进行声明,以及main函数所需要的头文件也一并包括在内,这样在main函数所在的文件里,只需要引进一个game.h就可以了。

我们给出代码,再结合代码进行说明:

test.c文件:

#include "game.h"
void game()
{
	char mine[ROWS][COLS] = { 0 };//雷信息'0'
	char show[ROWS][COLS] = { 0 };//棋盘信息 '*'
	//初始化棋盘
	InitBoard(mine, ROWS, COLS, '0');
	InitBoard(show, ROWS, COLS, '*');
	//显示棋盘
	DisplayBoard(show, ROW, COL);
	//布置雷
	SetMine(mine, ROW, COL);
	//排查雷
	FindMine(mine, show, ROW, COL);
	
}
void menu()
{
	printf("******************************************************\n");
	printf("**1.Start                                0.Exit  *****\n");
	printf("******************************************************\n");
}
void test()
{
	int input = 0;
	do
	{
		menu();
		printf("请选择;>");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			game();
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("输入错误,请重新选择!\n");
			break;
		}
	} while (input);
	

}
int main()
{
	srand((unsigned int)time(NULL));
	test();
	return 0;
}

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
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set);
void DisplayBoard(char show[ROWS][COLS], int row, int col);
void SetMine(char mine[ROWS][COLS], int row, int col);
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);

game.c文件:

#include "game.h"
#define EASY_COUNT 10
void Open(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y)
{
	if (x > 0 && x <= ROW && y > 0 && y <= COL)
	{
		if (0 == GetMine(mine, x, y))
		{
			if (show[x][y] != ' ')
			{
				show[x][y] = ' ';
				int i = 0;
				int j = 0;
				for (i = x - 1; i <= x + 1; i++)
				{
					for (j = y - 1; j <= y + 1; j++)
					{
						Open(mine, show, i, j);
					}
				}
			}
		}
		else
		{
			show[x][y] = GetMine(mine, x, y) + '0';
			return;
		}
	}
}
int GetMine(char mine[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 (mine[i][j] == '1')
			{
				count++;
			}
		}
	}
	return count;
}
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;
		}
	}
}
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
	int i = 0;
	int j = 0;
	printf("-----------------------------------------------|\n");
	for (i = 0; i <= 9; 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");
	}
	printf("-----------------------------------------------|\n");
}
void SetMine(char mine[ROWS][COLS], int row, int col)
{
	int count = EASY_COUNT;
	while (count > 0)
	{
		int x = rand() % 9 + 1;
		int y = rand() % 9 + 1;
		if (mine[x][y] == '0')
		{
			mine[x][y] = '1';
			count--;
		}
	}
}

void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	int win = 0;
	while (1)
	{
		printf("请输入要排查的坐标:>");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= 9 && y >= 1 && y <= 9)
		{
			if (show[x][y] != '*')
			{
				printf("你已经排查过该坐标了\n");
			}
			if (mine[x][y] == '1')
			{
				printf("很遗憾,被炸死了!\n");
				DisplayBoard(mine, ROW, COL);
				break;
			}
			else
			{
				Open(mine, show, x, y);
				DisplayBoard(show, row, col);
			}
			//用来遍历数组来判断雷和空白的位置以判断是否结束游戏。
			int i = 0;
			int j = 0;
			int flag = 0;
			for (i = 1; i <= row; i++)
			{
				for (j = 1; j <= col; j++)
				{
					if ('*' == show[i][j])
					{
						flag++;
					}
				}
			}
			if (EASY_COUNT == flag)
			{
				printf("恭喜你,排雷成功!\n");
				break;
			}
		}
		else
		{
			printf("输入非法,请重新输入!\n");
		}
	}
	
}

首先从main函数进入,main函数内部第一行先不用管,是用来生成随机数的随机起点的,后面会说到。进入test函数,进入do while循环,打印菜单,通过输入数字来进入或退出游戏。

输入1进入game函数,game函数内实现游戏逻辑。

首先我们需要两个二维数组来分别储存游戏中呈现的棋盘信息和”雷“的信息。

为了区分,分别取名为"show"和”mine“。

我们在定义二维数组的行和列时,用了ROWS和COLS,这是考虑到,在将来排查的时候,边缘位置进行周围八个格子排查时会越界访问,所以在9x9的界面内,我们实际上在设计时,设计成11x11的二维数组,给外面围了一圈,这样就可以避免越界访问。

而我们呈现时是以9x9的方式进行呈现的。

所以在game.h内部,用#define宏定义ROW与COL为9,ROWS与COLS为前者的基础上加2,这样无论是9x9还是10x10,都在外面围了一圈来避免越界访问。

然后,我们初始化棋盘,将要展现出来的棋盘show初始化为全是字符' * ',将雷的棋盘全部初始化为字符' 0 ',不过我们只写一个初始化函数,所以我们在传参时,不仅仅要把创建的二维数组传进去,也要把所要初始化的内容传进去。

然后就是在game.h内部进行定义,在game.c内部进行相关函数的实现。

初始化棋盘,把show数组和mine数组分别初始化为字符‘ * ’和字符' 0 '。见InitBoard函数。

打印棋盘,注意,传进去的是我们的show数组,但是打印的时候只是打印9x9的棋盘,所以传的时候传的行和列为ROW和COL,用row和col接收。具体看game.c内的DisplayBoard函数。

布置雷,此时我们传进去的是mine数组,但是在游戏中只有9x9的棋盘,所以我们只在9x9的范围内随机生成10个雷,此时我们就需要用到随机数来生成相应的坐标。所以就有了在开头main函数里用srand来生成随机起点。布置雷的时候要进行判断,若mine数组内该坐标位置为不是字符' 1 ',那么可以将其改为字符' 1 '视为布置了一颗“雷”。每布置成功一次,EASY_COUNT减一,至于设置这样一个宏定义的目的是为了以后雷的数量可以根据需求方便更改。

排查雷:即Findmine函数,我们此时要把show数组和mine数组都传进去,排查的时候,输入要排查的坐标,然后在mine数组里判断是否有“雷”,若没有,因为我们打印的时候打印的是show数组,所以改变的是show数组的内容,mine数组只是用来存储“雷信息”的,用做判断的依据。

输入后要判断合法性,是不是在9x9的范围内。还要判断show数组该位置上是否为‘ * ’,否则意味着已经排查过该坐标了。

然后判断mine数组相应位置上有没有“雷”,有的话,游戏结束,打印mine数组,没有的话,就进入我们的Open函数来实现排除一片的递归操作。

所谓展开一片,就是排查到一个坐标的周围一圈都没有“雷”的时候就展开,然后将无“雷”的地方改为空格,不然会死递归,再去排查这周围的几个坐标有没有符合条件的,有的话重复上述操作。

直到没有,就在该位置上显示周围有几个“雷”。

为此,我们写一个查找周围有几个“雷”的函数,称为GetMine,思路是以输入坐标为中心的9宫格内用循环来统计该区域的mine数组有几个雷,然后将其赋给该坐标的show数组的相应位置即可。注意这个GetMine函数是在game.c里面直接定义使用的,因为这个函数和game函数是没有直接关系的。

判断输赢,即“雷”的数量小于等于show数组中' * '字符的个数,在这里写成了等于符号,所以我们每次排查雷之后就要对棋盘进行一次遍历,来统计“雷”和' * '的数量并进行对比。

这样就大概上实现了功能。

水平有限,欢迎指正。

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值