C语言 | 扫雷小游戏【超详细,看完必会!】

本文详细介绍了如何使用C语言编写一个简单的扫雷游戏,包括游戏设计、代码实现、数据结构(二维数组)的应用以及关键函数如初始化棋盘、布置雷和排查雷的逻辑。
摘要由CSDN通过智能技术生成

扫雷游戏

在这里插入图片描述
扫雷是一个非常经典的小游戏,想必大家都玩过,那么如何用C语言来写出一个扫雷小游戏呢?跟着我一起往下看吧~

1、扫雷游戏的设计和分析

扫雷小游戏的说明:

  • 使用控制台来实现小游戏。
  • 有必要的菜单,游戏可以通过菜单来选择是继续游戏,还是退出游戏。
  • 扫雷是一个 9 × 9 的棋盘,并且要在这个 9 × 9 的棋盘中随机布置 10 个雷。
  • 开始扫雷:
    • 如果位置不是雷,则显示这个位置周围有几个雷。
    • 如果这个位置是雷,则游戏失败,重新选择继续或者退出游戏。
    • 直到成功找出隐藏的 10 个雷,则排雷成功,游戏结束。

2、代码的实现

首先,我们需要一个打印菜单的函数:

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

主函数:
首先一定是打印菜单,再选择开始游戏1. play或者退出游戏0. exit,此时我们自然而然就会想到switch...case语句,switch...case语句上一篇文章已经详细介绍过,这里不再赘述。

主函数代码:

int main()
{
	int input = 0;
	srand((unsigned int)time(NULL));
	do
	{
		menu();//打印菜单
		printf("请选择:>");
		scanf("%d", &input);
		switch (input)
			case 1:
				game();//开始游戏
				break;
			case 0:
				printf("退出游戏\n");
				break;
			default:
				printf("选择错误,请重新选择\n");
				break;
	}while(input)
	return 0;
}

游戏结构的分析:
显然,扫雷游戏的棋盘需要借助二维数组来实现。

在这里插入图片描述
如图,如果我们选择 绿色 的格子,若该格子不是雷,则会计算该格子周围 8 个格子中雷的个数;

如果我们选择 黄色 的格子,若该格子不是雷,则也会计算该格子周围 8 个格子中雷的个数,虽然黄色格子下方已经超出了棋盘范围,但依旧会进行计算,此时就发生了数组越界,可能会造成计算结果的错误。

为了有效的解决这一问题:
我们可以将 9 × 9 的棋盘扩展成为 11 × 11 的棋盘,这样就不会发生数组越界访问的问题了,如下图所示:
在这里插入图片描述
我们用 1 来表示已经布置的雷,用 0 表示未布置雷,但为了防止布置雷使用的数字 1 与某点计算出雷的个数的数字 1 冲突,这里我们就使用字符 '1' 来表示已经布置的雷,同理,使用字符 '0' 来表示未布置雷的地方。

我们把雷布置到mine数组,在mine数组中排查雷,排查出的数据存放在show数组,并且打印show数组的信息给后期排查参考。

对应的数组应该是:

char mine[11][11] = {0}; //⽤来存放布置好的雷的信息

char show[11][11] = {0}; //⽤来存放排查出的雷的个数信息

同时为了保持神秘,show数组开始时初始化为字符 '*',为了保持两个数组的类型一致,可以使用同一套函数处理,mine数组最开始也初始化为字符'0',布置雷改成'1'。如下图:

show数组输出初始化的状态:

show数组输出初始化的状态
我们设计三个文件

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

game.h文件中,首先我们要进行一些定义:

#define EASY_COUNT 10//布置雷的个数是10个
#define ROW 9//9*9的棋盘
#define COL 9
#define ROWS ROW+2//11*11的棋盘
#define COLS COL+2

game函数:
1.初始化棋盘:mine数组最开始全是'0'show数组最开始全是'*'
2.打印棋盘:1)布置雷 2)排查雷

void game()
{
	char mine[ROWS][COLS];//存放布置好的雷
	char show[ROWS][COLS];//存放排查出的雷的信息
	
	//初始化棋盘
	//1.mine数组最开始全是'0'
	//2.show数组最开始全是'*'
	InitBoard(mine, ROWS, COLS, '0');
	InitBoard(show, ROWS, COLS, '*');
	
	//打印棋盘
	//DisplayBoard(mine, ROW, COL);
	DisplayBoard(show, ROW, COL);
	//1.布置雷
	SetMine(mine, ROW, COL);
	//DisplayBoard(mine, ROW, COL);
	//2.排查雷
	FindMine(mine, show, ROW, COL);
}

对于InitBoard函数,首先将数组、行数、列数以及数组初试化的符号传到函数中,就如上文所描述的,mine数组就全部初始化为'0',而show数组就全部初始化为'*',代码如下:

void InitBoard(char board[ROWS][COLS], int rows, int cols, char set)
{
	int i = 0;
	for (i = 0; i < rows; i++)
	{
		for (int j = 0; i < cols; j++)
		{
			board[i][j] = set;//棋盘初始化
		}
	}
}

DisplayBoard函数,在 9 × 9 的棋盘周围打印行号和列号

void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
	int i = 0;
	printf("--------扫雷游戏-------\n");
	for (i = 0; i <= col; i++)
	{
		printf("%d ", i);
	}
	printf("\n");
	for (i = 1; i <= row; i++)
	{
		printf("%d ", i);
		int j = 0;
		for (j = 1; j <= col; j++)
		{
			printf("%c ", board[i][j]);
		}
		printf("\n");
	}
}

SetMine函数,随机生成 10 个雷布置在 9 × 9 的棋盘中,判断如果这个位置为'0',就允许布置雷,避免在同一个位置重复布置雷

void SetMine(char board[ROWS][COLS], int row, int col)
{
	//布置10个雷
	//生成随机的坐标,布置雷
	int count = EASY_COUNT;
	while (count)
	{
		int x = rand() % row + 1;
		int y = rand() % col + 1;
		if (board[x][y] == '0')
		{
			board[x][y] = '1';
			count--;
		}
	}
}

GetMineCount函数,计算该位置周围的雷的数量,如图所示:
在这里插入图片描述

int GetMineCount(char mine[ROWS][COLS], int x, int y)
{
	return (mine[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] + mine[x][y + 1] + mine[x - 1][y + 1] - 8 * '0');
}

注: 计算结果最后边 - 8 x ' 0 ' 的原因是,将字符'0'转化为数字 0

FindMine函数,输入坐标,进行排雷!

void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	int win = 0;
	while (win < row * col - EASY_COUNT)
	{
		printf("请输入要排查的坐标:>");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			if (mine[x][y] == '1')
			{
				printf("很遗憾,你被炸死了\n");
				DisplayBoard(mine, ROW, COL);
				break;
			}
			else
			{
				//该位置不是雷,就统计这个坐标周围有几个雷
				int count = GetMineCount(mine, x, y);
				show[x][y] = count + '0';
				DisplayBoard(show, ROW, COL);
				win++;
			}
		}
		else
		{
			printf("坐标非法,重新输入\n");
		}
	}
	if (win == row * col - EASY_COUNT)
	{
		printf("恭喜你,排雷成功\n");
		DisplayBoard(mine, ROW, COL);
	}
}

代码总结
一、game.h文件中

#pragma once

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

#define EASY_COUNT 10

#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 board[ROWS][COLS], int row, int col);

//布置雷
void SetMine(char board[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"

void InitBoard(char board[ROWS][COLS], int rows, int cols, char set)
{
	int i = 0;
	for (i = 0; i < rows; i++)
	{
		for (int j = 0; i < cols; j++)
		{
			board[i][j] = set;//棋盘初始化
		}
	}
}

void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
	int i = 0;
	printf("--------扫雷游戏-------\n");
	for (i = 0; i <= col; i++)
	{
		printf("%d ", i);
	}
	printf("\n");
	for (i = 1; i <= row; i++)
	{
		printf("%d ", i);
		int j = 0;
		for (j = 1; j <= col; j++)
		{
			printf("%c ", board[i][j]);
		}
		printf("\n");
	}
}

void SetMine(char board[ROWS][COLS], int row, int col)
{
	//布置10个雷
	//生成随机的坐标,布置雷
	int count = EASY_COUNT;
	while (count)
	{
		int x = rand() % row + 1;
		int y = rand() % col + 1;
		if (board[x][y] == '0')
		{
			board[x][y] = '1';
			count--;
		}
	}
}


int GetMineCount(char mine[ROWS][COLS], int x, int y)
{
	return (mine[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] + mine[x][y + 1] + mine[x - 1][y + 1] - 8 * '0');
}


void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	int win = 0;
	while (win < row * col - EASY_COUNT)
	{
		printf("请输入要排查的坐标:>");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			if (mine[x][y] == '1')
			{
				printf("很遗憾,你被炸死了\n");
				DisplayBoard(mine, ROW, COL);
				break;
			}
			else
			{
				//该位置不是雷,就统计这个坐标周围有几个雷
				int count = GetMineCount(mine, x, y);
				show[x][y] = count + '0';
				DisplayBoard(show, ROW, COL);
				win++;
			}
		}
		else
		{
			printf("坐标非法,重新输入\n");
		}
	}
	if (win == row * col - EASY_COUNT)
	{
		printf("恭喜你,排雷成功\n");
		DisplayBoard(mine, ROW, COL);
	}
}

三、test.c文件中

#include "game.h"

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

void game()
{
	char mine[ROWS][COLS];//存放布置好的雷
	char show[ROWS][COLS];//存放排查出的雷的信息
	//初始化棋盘
	//1.mine数组最开始全是'0'
	//2.show数组最开始全是'*'
	InitBoard(mine, ROWS, COLS, '0');
	InitBoard(show, ROWS, COLS, '*');
	//打印棋盘
	//DisplayBoard(mine, ROW, COL);
	DisplayBoard(show, ROW, COL);
	//1.布置雷
	SetMine(mine, ROW, COL);
	//DisplayBoard(mine, ROW, COL);
	//2.排查雷
	FindMine(mine, show, ROW, COL);
}

int main()
{
	int input = 0;
	srand((unsigned int)time(NULL));
	do
	{
		menu();//打印菜单
		printf("请选择:>");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			game();//开始游戏
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("选择错误,请重新选择\n");
			break;
		}
	} while (input);
	return 0;
}

OK!扫雷小游戏到这里就暂告一段落了,如有你学会了或者还有一些疑问,欢迎留言!

  • 25
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值