C语言 —— 简单的扫雷游戏

在学了数组、函数和分支循环语句后,这次我们来写一个简易的扫雷游戏

1.扫雷游戏的功能

  • 使用简易的菜单实现经典的扫雷游戏
  • 游戏可以通过菜单实现继续玩或者退出游戏
  • 扫雷的棋盘是9*9的格子
  • 默认随机布置10个雷
  • 可以排查雷
    • 如果位置不是雷,就显示周围有几个雷
    • 如果位置是雷,就炸死游戏结束
    • 把除10个雷之外的所有非雷都找出来,排雷成功,游戏结束

2.简易菜单

  • 这个菜单的代码可以参考上一篇的菜单,这里就略过了(链接在这里
  • 这里有为了让代码看起来能更结构化,
  • 把文件中写游戏的测试逻辑放在test.c中,
  • 把文件中写游戏需要的数据类型和函数声明等放在game.h头文件中,
  • 把文件中的游戏函数等放在game.c中
  • 这样所有的申明都可以放在game.h中,
  • 在test.c中只要引入game.h这个头文件就可以使用所有需要的函数了

在这里插入图片描述

  • 下面是菜单的代码
  • 因为这里需要在三个文件中编辑,所以我在每段代码的第一行会表明在哪个文件
#include "game.h"		//test.c文件

int main()
{
	int flag = 0;
	srand((unsigned int)time(NULL));	//设置随机数的种子

	do
	{
		printf("**************************\n");
		printf("*********开始游戏:1*******\n");
		printf("*********退出游戏:0*******\n");
		printf("**************************\n");
		printf("是否开始游戏(0/1):");
		scanf("%d", &flag);

		switch (flag)
		{
		case 1:
			game();
			break;
		case 0:
			printf("您已退出游戏\n");
			break;
		default:
			printf("输入错误,请重新输入\n");
			break;
		}

	} while (flag);

	return 0;
}

3.游戏的实现

3.1 游戏的分析和设计

  • 扫雷的过程中,布置的雷和排查出的雷的信息都需要存储,所以我们需要⼀定的数据结构来存储这些信息,
  • 因为我们需要在9 * 9的棋盘上布置雷的信息和排查雷,我们首先想到的就是创建⼀个9 * 9的数组来存放信息,
  • 然后把有雷的地方储存记为1,没有雷的地方记为0,如下图:

在这里插入图片描述

  • 但当我们写排雷代码的时候发现,排雷需要计算周围8个格子的信息,
  • 当我们在9*9边界排雷的时候发现就会越界了,所以我们打算把数组的范围再往外扩大一格,这样就解决了越界的问题,如下图:

在这里插入图片描述

  • 我们接着分析,如果我们输入坐标为(3,6)的位置进行排雷,
  • 此时周围有一个雷,那么我们该怎么把这个雷的个数 1 储存起来呢,直接打印在这个棋盘上吗?
  • 如果这样的话,那么这个 1 到底是原来随机生成的呢,还是我们排雷后代表周围雷的个数呢,就会产生歧义了,
  • 此时我们可以再定义一个数组,让一个数组来存储随机生成的雷,另外一个显示周围雷的个数,
  • 并且为了保持神秘性,显示周围雷的那个数组一开始全都为“ * ”,
  • 此时就可以定义两个字符数组开始敲代码了

3.2 初始化数组

#pragma once		//game.c文件
#include <stdio.h>

#define ROW 9
#define COL 9	//9*9的棋盘
#define ROWS ROW+2
#define COLS COL+2	//定义11*11的数组
#define NUM 10	//定义雷的个数

//game.c文件
void chushihua(char arr[ROWS][COLS], int row, int col, char s)
{
	for (int i = 0; i < row; i++)
	{
		for (int j = 0; j < col; j++)
		{
			arr[i][j] = s;
		}
	} 
}
  • 这里用了宏定义是为了方便之后改参数,比如你想玩20 * 20的棋盘了,你就直接把#define后的参数改了就行

3.3 布雷

void bulei(char arr[ROWS][COLS], int row, int col) 	 //game.c文件
{
	int n = NUM;

	while (n != 0)
	{
		int a1 = rand() % row + 1;
		int a2 = rand() % row + 1;

		if (arr[a1][a2] == '0')
		{
			arr[a1][a2] = '1';
			n--;
		}
	}
}
  • 这里如果赋值随机数的时候发现之前赋值过了,就要重新赋值,所以这个循环的执行次数大于等于10

3.4 计算周围雷的个数

void jisuan(char arr1[ROWS][COLS], char arr2[ROWS][COLS], int a, int b)  //game.c文件
{
	int sum = 0;

	for (int i = a - 1; i <= a + 1; i++)
	{
		for (int j = b - 1; j <= b + 1; j++)
		{
			sum += arr2[i][j] - '0';
		}
	}

	arr1[a][b] = (char)(sum + '0');
}

3.5 打印排雷后的数组

void print(char arr[ROWS][COLS], int row, int col)		//game.c文件
{
	for (int i = 0; i <= col; i++)
	{
		printf("%2d ", i);
	}

	printf("\n");

	for (int i = 1; i <= row; i++)
	{
		printf("%2d ", i);

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

		printf("\n");
	}

	printf("\n");
}

  • 这里在printf函数中规定了打印2个字符
  • 是为了防止当这不是9 * 9,而是20 * 20的棋盘的时候
  • 保证整个棋盘是对齐的

在这里插入图片描述

  • 加了 2 之后的是这样的

在这里插入图片描述

3.6 标记功能

  • 通过输入坐标后再输入一个数(0,1,-1)实现对坐标处的探雷,标记,解除标记
int biaoji(char arr1[ROWS][COLS], int a, int b, int c)		//game.c文件
{
	if (c == 0)
	{
		return 1;
	}
	else if (c == 1)
	{
		if (arr1[a][b] == '*')
		{
			arr1[a][b] = '$';
			print(arr1, ROW, COL);
			return 0;
		}
		else
		{
			printf("这个位置已经排过雷了,请重新输入\n");
			return 0;
		}
	}
	else if (c == -1)
	{
		if (arr1[a][b] == '$')
		{
			arr1[a][b] = '*';
			print(arr1, ROW, COL);
			return 0;
		}
		else
		{
			printf("此处未被标记\n");
			return 0;
		}
	}
	else
	{
		printf("请选择是否要标记,标记则在坐标后加1,否则加0\n");
		return 0;
	}
}

3.7 排雷

最核心的还是排雷的代码,可以调用之前的函数来实现功能

void pailei(char arr1[ROWS][COLS], char arr2[ROWS][COLS], int row, int col)//game.c文件
{
	int n = row * row - NUM;
	
	while (n > 0)
	{
		int a, b;
		int c;
		printf("请输入排雷的坐标以及是否要标记(标记为1,否则为0, 撤回标记为-1,输入的三个数用空格隔开):");
		scanf("%d %d %d", &a, &b, &c);

		if (biaoji(arr1, a, b, c) == 1)
		{
			if (a >= 1 && a <= ROW && b >= 1 && b <= COL)
			{
				if (arr1[a][b] == '*')
				{
					if (arr2[a][b] == '1')
					{
						printf("您被炸死了,雷的分布图为:\n");
						print(arr2, ROW, COL);
						break;
					}
					else
					{
						jisuan(arr1, arr2, a, b);	//计算坐标周围八格的雷数
						n--;
						print(arr1, row, col);		//打印数组
						//print(arr2, row, col);	//排雷后打印雷的位置
					}
				}
				else
				{
					printf("您已探测过此处了,请重新输入\n");
				}
			}
			else
			{
				printf("输入坐标超出范围,请重新输入\n");
			}
				
		}
	}

	if (n == 0)
	{
		printf("恭喜你,排掉了所有的雷\n");
		print(arr2, ROW, COL);
	}
}

3.8 整合代码

void game()			//game.c文件
{
	printf("<————开始游戏————>\n");
	printf("共有%d个雷\n", NUM);
	char arr1[ROWS][COLS];
	char arr2[ROWS][COLS];
	chushihua(arr1, ROWS, COLS, '*');
	chushihua(arr2, ROWS, COLS, '0');		//初始化数组
	print(arr1, ROW, COL);		
	bulei(arr2, ROW, COL);    //11*11的范围布NUM个9*9的随机雷
	pailei(arr1, arr2, ROW, COL);
}
  • 最后将这些函数整合起来实现扫雷的功能
  • 别忘了在game.h文件里把所有的函数都申明了
void dayin(char arr[ROWS][COLS], int row, int col);   //game.h文件
void chushihua(char arr[ROWS][COLS], int row, int col, char s);
void print(char arr[ROWS][COLS], int row, int col);
void bulei(char arr[ROWS][COLS], int row, int col);
void jisuan(char arr1[ROWS][COLS], char arr2[ROWS][COLS], int a, int b);
void pailei(char arr1[ROWS][COLS], char arr2[ROWS][COLS], int row, int col);
int biaoji(char arr1[ROWS][COLS], int a, int b, int c);
void game();
  • 后续对扫雷游戏的改进想要源代码同学的请自行领取(git

最后,
如果上述代码或表述有问题,
欢迎一起讨论

  • 23
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

看落日的YT

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值