C语言实战——扫雷游戏

文章目录

  • 前言
  • 游戏规则
    • 游戏目标
    • 操作方法
  • 实现思路
    • 扫雷数组设计
    • 显示数组设计
    • 扫雷数组与显示数组初始化
    • 主函数实现
    • 游戏实现过程
  • 扫雷游戏代码实现
    • 使用工具
    • 文件结构设计
    • 主函数实现
    • game.h文件
    • game.c文件
  • 结果测试
  • 总结

前言

该文章将用C语言实现扫雷游戏的基本功能,其中用到的知识有:数组,函数,条件选择语句,循环语句等。通过实现一个简单的小游戏,来对这些知识进行巩固。

游戏规则

游戏目标

玩家要在一定时间内找到所有安全的方块,避免踩到地雷。

操作方法

键盘输入要探测的坐标位置后按回车键,如果探测的位置是地雷,则游戏结束;若探测的位置不是地雷,则该方格会显示一个数字,该数字表示周围的8个方格中含有的地雷数。当所有安全方块都被翻开后,游戏胜利;否则,游戏失败。

实现思路

扫雷数组设计

在进行扫雷的过程中,需要定义一个数据结构存储雷的信息,我们可以想到用一个二维数组mine来存储雷的信息,1表示所在的位置有雷,0表示所在的位置无雷。如下图所示:
C语言实战——扫雷游戏_第1张图片

但是在这个过程中存在一个问题,在对边界位置进行探测时,如果没有雷,那么显示的是周围5个方格中含有的地雷数,这时如果对数组进行相应的操作,可能会造成数组越界的问题;例如,我们要对9*9区域中的(9,7)所在位置进行探测,可能会造成数组越界的问题。如下图所示:
C语言实战——扫雷游戏_第2张图片

为了解决此问题,我们可以在整要探测区域扩大一圈,即增加两行和两列,将所增加的区域全部设置为0。如下图所示:

这样就可以避免数组越界的问题,同时这样还有一个好处:由于二维数组的行和列下标都是从0开始的,而实际的扫雷区域下标是从1开始的,如果不对扫雷区域进行扩大一圈,那么实际要探测的坐标位置与数组对应的坐标位置不一样,还要对两个坐标位置进行转换。而扩大一圈后,实际要探测的坐标位置与数组对应的坐标位置一样,不用进行坐标转换。例如,要对扫雷区域(2,3)位置进行探测,如果不进行扩大一圈,那么对应数组的位置为(1,2),如果进行扩大一圈,对应数组的位置为(2,3)。
C语言实战——扫雷游戏_第3张图片

显示数组设计

当我们在区域中布置了雷,假设我们排查了一个位置后,这个坐标不是雷,我们需要将周围雷的个数进行打印,作为排雷的重要参考信息。如果将这个信息保存在mine数组中,雷的信息和周围雷个数的信息就会产生混淆,因此我们要再定义一个二维数组show,用来存放拍出雷的信息,show数组的大小与mine数组一样。

扫雷数组与显示数组初始化

当我们将扫雷数组与显示数组设计完成后,要考虑初始化的问题。对于扫雷数组来说,我们应该先将数组中的元素都初始化为0,表示目前整个扫雷区域没有雷,然后根据要生成雷的个数,在棋盘上随机生成雷。对于显示数组来说,由于一开始所有区域未探索,用字符“表示当前位置为被探索,并将显示数组中所有元素初始化为“”。

主函数实现

主函数主要功能就是显示菜单,并循环接收用户的输入,当用户选择开始游戏时,开始扫雷游戏;若用户选择退出时,程序结束。

游戏实现过程

进入游戏后,先打印显示数组,并让用户输入要探测的位置,若用户探测到雷,提示“很遗憾,游戏失败”后返回菜单,若用户没有探测到雷,则更新显示数组,并将其打印,继续让用户输入探测的位置,依次类推,若用户将所有安全位置都找到后,提示“恭喜你,排出了所有的雷”后返回菜单。

扫雷游戏代码实现

使用工具

VS2022

文件结构设计

main.c // 主程序文件
game.h // 文件中写需要声明的变量和函数等
game.c // 文件中写需要实现的函数等

主函数实现

主函数主要是实现菜单显示,以及接收用户输入
主函数的实现如下:

#define _CRT_SECURE_NO_WARNINGS 1 
#include "game.h"

void Menu() {
	printf("************************\n");
	printf("*******1、开始游戏******\n");
	printf("*******0、退出    ******\n");
	printf("************************\n");

}

void game() {
	char mine[ROWS][COLS];//存放布置好的雷,'1'表示对应位置有雷,'0'表示对应位置无雷
	char show[ROWS][COLS];//显示怕查出雷的信息,'*'表示对应位置没有被探索,如果被探索,显示周围雷的个数

	//初始化数组
	InitBoard(mine, ROWS, COLS, '0');
	InitBoard(show, ROWS, COLS, '*');

	//DisplayBoard(mine, ROW, COL);
	//DisplayBoard(show, ROW, COL);

	//布置雷
	SetMine(mine, ROW, COL);
	//DisplayBoard(mine, ROW, COL);

	//排查雷
	FindMine(mine, show, ROW, COL);

}

int main() {

	srand((unsigned int)time(NULL));
	int input;
	do
	{
		Menu();
		printf("请输入选项>");
		scanf("%d", &input);
		switch (input) {
		case 1:
			system("cls");
			game();
			system("pause");
			system("cls");
			break;
		case 0:
			break;
		default:
			printf("输入选项非法,请重新输入\n");
			system("pause");
			system("cls");
			break;
		}
	} while (input);
}

game.h文件

game.h文件中写需要声明的变量和函数等
文件代码如下:

#define _CRT_SECURE_NO_WARNINGS 1 

#define ROW 9	//扫雷游戏数组的行数
#define COL 9	//扫雷游戏数组的列数
#define ROWS ROW + 2	//扫雷游戏数组扩大一圈后的行数

#define COLS COL + 2	//扫雷游戏数组扩大一圈后的列数
#define MINE_COUNT 80	//需要布置的雷的个数

#include 
#include 
#include 
void InitBoard(char board[][COLS], int rows, int cols, char set);

void DisplayBoard(char board[][COLS], int row, int col);

void SetMine(char board[][COLS], int row, int col);

void FindMine(char mine[][COLS], char show[][COLS], int row, int col);

game.c文件

game.c文件主要对game.h文件中声明的函数进行实现,文件代码如下:

#define _CRT_SECURE_NO_WARNINGS 1 
#include "game.h"

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

//打印数组的部分内容
void DisplayBoard(char board[][COLS], int row, int col)
{
	printf("----- 扫雷游戏 -----\n");
	for (int i = 0; i <= row; i++) {
		printf("%d ", i);
	}

	printf("\n");

	for (int i = 1; i <= row; i++) {
		printf("%d ", i);
		for (int j = 1; j <= col; j++) {
			printf("%c ", board[i][j]);
		}
		printf("\n");
	}
}

//设置雷
void SetMine(char board[][COLS], int row, int col)
{
	int count = MINE_COUNT;
	while (count) {
		int mine_row = rand() % row + 1;
		int mine_col = rand() % col + 1;
		if (board[mine_row][mine_col] == '0') {
			board[mine_row][mine_col] = '1';
			count--;
		}
	}
}

//返回探索区域周围雷的个数
int GetCount(char mine[][COLS],int x,int y) {
	return mine[x - 1][y - 1] + mine[x - 1][y] + mine[x - 1][y + 1]
		+ mine[x][y - 1] + mine[x][y + 1] + mine[x + 1][y - 1]
		+ mine[x + 1][y] + mine[x + 1][y + 1] - 8 * '0';
}

//排查类
void FindMine(char mine[][COLS], char show[][COLS], int row, int col)
{
	int find_count = 0;
	while (find_count < row * col - MINE_COUNT) {
		int x;
		int y;
		DisplayBoard(show, row, col);
		DisplayBoard(mine, row, col);
		printf("请输入要探测的位置坐标>");
		scanf("%d%d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col && show[x][y] == '*') {
			if (mine[x][y] == '1') {
				printf("很遗憾,踩到地雷,游戏结束\n");
				break;
			}
			else
			{
				show[x][y] = GetCount(mine, x, y) + '0';
				//printf("%d\n", GetCount(mine, x, y));
				find_count++;
				system("cls");
			}
		}
		else if (x >= 1 && x <= row && y >= 1 && y <= col && show[x][y] != '*') {
			printf("该位置已被探索,请重新输入坐标\n");
			system("pause");
			system("cls");
		}
		else {
			printf("输入的坐标位置非法,请重新输入坐标位置\n");
			system("pause");
			system("cls");
		}
		
		if (find_count == row * col - MINE_COUNT) {
			printf("恭喜你,排除了所有的雷\n");
			DisplayBoard(mine, ROW, COL);
		}
	}
}

结果测试

菜单界面测试:
C语言实战——扫雷游戏_第4张图片
游戏功能测试
C语言实战——扫雷游戏_第5张图片
C语言实战——扫雷游戏_第6张图片
C语言实战——扫雷游戏_第7张图片
C语言实战——扫雷游戏_第8张图片
由于成功排雷花费时间较长,我在测试前将地雷的数量设置为80,并打印mine数组,这样在测试前就可以知道雷的位置。
C语言实战——扫雷游戏_第9张图片
C语言实战——扫雷游戏_第10张图片
退出游戏
C语言实战——扫雷游戏_第11张图片

总结

至此,用C语言实现简单的扫雷游戏基本结束,完整代码可见gitee链接: link

本文章只实现了扫雷游戏基本的功能,还有很功能没有实现,日后若有时间将继续完善。当然,设计过程中可能存在不足之处,还请各位大佬指正。

你可能感兴趣的:(c语言,游戏)