扫雷游戏(数组和函数实现)

一、前导

想必大家都玩过扫雷游戏吧!不管怎样,我们看一下扫雷游戏的基本规则:

  • 游戏目标:找出所有的地雷! 更准确地说是——在避免踩到地雷的情况下探索所有的格子。 扫雷游戏胜利的条件并不是标记处所有包含地雷的格子,而是 揭示所有不包含地雷的格子 。
  • 如何避免踩雷:利用安全格子提供的信息,我们可以推断一个格子附近的格子有没有雷。
  • 安全格子的类型: 数字:表示它 周围八个格子 中地雷的数量。
    在这里插入图片描述
    在这里插入图片描述
    这是一个简易的网页版扫雷,我们今天就用C语言的数组和函数知识来实现这样一个扫雷游戏。

二、分析与思路

棋盘

由上图我们发现,游戏有一个9*9的棋盘,棋盘中包含着数字信息,雷的位置信息等。由此我们想到用二维数组来完成棋盘的制作。

雷的布置

  • 我们决定用二维数组来制作棋盘,那么二维数组的每个元素可以用来表示每个区域,区域分为有雷区和无雷区。两种雷区意味着需要两种元素来分别表示,那么我们选择什么元素来表示呢?
    有和无,我们容易想到C语言中的 01 ,0表示无雷区,1表示有雷区。这样,一个由1和0组成的二维数组就产生了。注意,这个二维数组不能打印在屏幕上,不能泄露天机呀!
  • 在9*9棋盘上随机放置n(下面代码放10个)个雷,需要产生随机数,我们需要调用rand函数、srand函数、time函数,这就需要头文件stdlib.h、time.h

数字的显示

  • 数字表示它 周围八个格子 中地雷的数量。这个数字要计算出并显示出来,且第一个二维数组记录了雷区情况,所以我们需要另一个二维数组
  • 在我们排雷并显示数字前,屏幕上总得显示点什么吧,不妨就用 字符* 来初始化第二个数组。
  • 还有一点:
    在这里插入图片描述
    如果排棋盘边缘的区域,会出现数组越界访问的问题。我们考虑将棋盘扩大一圈,但是游戏区域仍然是9*9的区域。
    为了使两个数组元素下标一一对应,我们规定它们都是char[11][11]类型,规定同类型方便函数的使用。

三、代码实现

我们用多个文件的形式对函数进行声明和定义,来实现扫雷游戏:

1. test.c //记录游戏的测试逻辑 
2. game.c //记录游戏中函数的实现等
3. game.h //记录游戏需要的数据类型和函数声明等

game.c

#pragma once

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

//采用这样的方式便于修改,调整游戏难度
# define ROW 9//棋盘的行
# define COL 9//棋盘的列
# define ROWS ROW+2
# define COLS COL+2
# define COUNT_MINE 10//雷的数量

//初始化场地
void Initarray(char arr[ROWS][COLS], int row, int col, char ch);

//查看打印场地
void Showarray(char arr[ROWS][COLS], int row, int col);

//布置雷区
void Layoutmine(char arr[ROWS][COLS], int row, int col);

//扫雷
void Findmine(char arr1[ROWS][COLS], char arr2[ROWS][COLS],int row,int col);

game.c

#include"Mine.h"

//初始化
void Initarray(char arr[ROWS][COLS], int row, int col, char ch)
{
	int i = 0;
	int j = 0;
	for (i = 0; i < row; i++)
	{
		for (j = 0; j < col; j++)
		{
			arr[i][j] = ch;
		}
	}
}

//查看打印场地,只打印中间游戏部分
void Showarray(char arr[ROWS][COLS], int row, int col)
{
	int i = 0;
	int j = 0;
	printf("---------------------------------------\n");//类似的场地布置随意发挥
	
	//打印行标号,便于观察坐标
	for (i = 0; i <= ROW; i++)
	{
		printf("%d ", i);
	}
	printf("\n");
	printf("____________________\n");
	
	//打印游戏棋盘
	for (i = 1; i < row - 1; i++)
	{
		printf("%d|", i);//穿插打印列标号,‘|’ 将标号和棋盘分隔开

		for (j = 1; j < col - 1; j++)
		{
			printf("%c ", arr[i][j]);
		}
		printf("\n");
	}
}

//布置雷
void Layoutmine(char arr[ROWS][COLS], int row, int col)
{
	int count = COUNT_MINE;
	while (count)
	{
		int x = rand() % 9 + 1;//产生随机数x(1~9)
		int y = rand() % 9 + 1;//产生随机数y(1~9)

		if (arr[x][y] == '0')//字符0代表无雷区
		{
			arr[x][y] = '1';//无雷区布置一个雷
			count--;
		}
	}
}

//计算周围雷的数量
int Tip(char arr[ROWS][COLS],int x,int y)
{
	return arr[x][y + 1] + arr[x + 1][y + 1] +
		arr[x + 1][y] + arr[x + 1][y - 1] +
		arr[x][y - 1] + arr[x - 1][y - 1] +
		arr[x - 1][y] + arr[x - 1][y + 1] - 8 * '0';//字符数字转化为数字,用字符数字减去字符0,周围有几个雷,就返回数字几
}

//扫雷
void Findmine(char arr1[ROWS][COLS], char arr2[ROWS][COLS],int row,int col)
{
	int x = 0;
	int y = 0;
	int z = 0;//结束标志,记录扫出的无雷区数量
	while (z<(row*col- COUNT_MINE))
	{
		printf("请输入要查询的坐标->:");
		scanf("%d %d", &x, &y);
		if (((x > 0) && (x <= row)) && ((y > 0) && (y <= col)))
		{
			if (arr1[x][y] == '1')
			{
				printf("你被炸飞了,扫雷失败!\n本局游戏雷分布状况:\n");
				Showarray(arr1, ROWS, COLS);
				break;
			}
			else if (arr2[x][y] != '*')
				{
				printf("这个坐标已经查询过了,请重新输入要查询的坐标\n");
				}
			else
			{
				int count = Tip(arr1,x,y);
				arr2[x][y] = count+'0';//整数化为字符数
				Showarray(arr2, ROWS, COLS);
				z++;
			}
		}
		else
		{
			printf("输入的坐标非法,请重新输入!\n");
		}

	}
	if(z == (row * col - COUNT_MINE))
	{
	    printf("恭喜你过关!扫雷大师就是你!\n");
	    Showarray(arr1, ROWS, COLS);
	}
}

test.c

#include"Mine.h"

//打印菜单
void menu()
{
	printf("-----------扫雷游戏-----------\n");
	printf("******************************\n");
	printf("**********  1.开始  **********\n");
	printf("**********  0.退出  **********\n");
	printf("******************************\n");
	printf("请选择->:");
}

//游戏实现的核心
void Game()
{
	char mine[ROWS][COLS] = { 0 };//用于布置雷的数组,也就是上述的第一个数组
	char show[ROWS][COLS] = { 0 };//用于打印的数组,也就是上述的第二个数组
	Initarray(mine, ROWS, COLS, '0');
	Initarray(show, ROWS, COLS, '*');
	//Showarray(mine, ROWS, COLS);  这里打印场地是为了在书写代码时检验初始化函数的正确性
	//Showarray(show, ROWS, COLS);
	Layoutmine(mine, ROW, COLS);
	//Showarray(mine, ROWS, COLS);  检查布置雷的效果
	Showarray(show, ROWS, COLS);
	Findmine(mine, show,ROW,COL);
}

//主函数
int main()
{
	srand((unsigned int)time(NULL));//rnad函数产生伪随机数,用时间戳实现真随机数
	int input = 0;//用户根据菜单选择输入
	do
	{
		menu();
		scanf("%d", &input);
		switch (input)
		{
		case 1:Game();
			break;
		case 0:printf("游戏结束");
			break;
		default:printf("输入非法,请重新输入\n");
			break;
		}
	} while (input);
	return 0;
}

代码完成:
在这里插入图片描述
代码已经测试过了,未发现bug,如果有,期待你的指正。如果有哪里不太明白,我很乐意为大家服务!
赶紧动手试一试吧。

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值