《从入门到精通:扫雷游戏全解析》

一、引言

扫雷是一款经典的单人电脑游戏,玩家需要根据数字提示在没有地雷的区域揭开方块,同时避免揭开地雷。在这篇文章中,我们将介绍用C语言实现的简单扫雷游戏。


二、扫雷的魅力所在

  1. 策略性:扫雷需要玩家根据已知信息推断未知区域的情况,这种策略性的思考过程是其魅力之一。
  2. 挑战性:扫雷的难度可以根据需求调整,高难度的扫雷可以带来极大的挑战。
  3. 成就感:成功完成扫雷后带来的成就感也是吸引人的重要因

三、代码结构

game.h

头文件和常量定义

我们首先引入了一些必要的库文件,如 ``, ``, ``, 和 ``。接下来,我们定义了游戏棋盘的常量和游戏难度级别。

函数声明

在声明部分,我们列出了所有后续将要实现的函数,包括初始化函数 `class_mine_show`、打印棋盘函数 `display_board`、布置雷函数 `layout_board`、和扫雷函数 `sweep`。

// 头文件
#include // 标准输入输出库
#include // Windows 库
#include // 随机数生成库:srand(unsigned int)
#include // 时间函数库:time(NULL)

// 棋盘格子数
#define ROW 9 // 行数(不包括边界)
#define COL 9 // 列数(不包括边界)
#define ROWS ROW+2 // 实际行数(包括边界)
#define COLS COL+2 // 实际列数(包括边界)

// 游戏难度
#define easy_count 1 // 简单模式雷的数量
#define Difficult_count 20 // 困难模式雷的数量
#define extremely_difficult_count 30 // 极难模式雷的数量

// 声明
void class_mine_show(char board[ROWS][COLS], int rows, int cols, char set); // 初始化棋盘并显示设置字符
void display_board(char board[ROWS][COLS], int row, int col); // 打印棋盘
void layout_board(char board[ROWS][COLS], int row, int col); // 布置雷
void sweep(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col); // 排雷
  • 初始化函数

    `class_mine_show` 函数用于将棋盘的格子全部设置为指定的字符。在这里,我们通过两个嵌套的循环遍历整个棋盘,将每个格子的值设置为传入的字符。

  •  打印棋盘函数

    `display_board` 函数用于在控制台打印当前游戏棋盘的状态。通过两个嵌套的循环,我们遍历整个棋盘并输出每个格子的值。这个函数还包括一些控制台输出的延迟,以提高用户体验。

  •  布置雷函数

    `layout_board` 函数负责在棋盘上随机布置指定数量的雷。通过使用 `rand()` 函数和时间戳来生成随机的坐标,确保雷的位置是随机的且不重复。

  •  获取雷数量函数

    `get_main` 函数用于获取指定格子周围的雷的数量。通过对周围8个格子进行检查,统计其中的地雷数量。

  •  扫雷函数

    `sweep` 函数是整个游戏的核心。玩家通过输入坐标来进行排雷操作。如果玩家揭开的是地雷,游戏结束;否则,揭开的格子会显示周围地雷的数量。


game.c        

#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"

//初始化
void class_mine_show(char board[ROWS][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 display_board(char board[ROWS][COLS], int row, int col) {
	
	for (int i = 0; i <= COL; i++)
	{
		//Sleep(100);
		printf(" %d", i);
	}
	printf("\n");
	for (int i = 1; i <= ROW; i++)//第0行不打印
	{
		printf(" %d", i);
		Sleep(100);
		for (int j = 1; j <= COL ; j++)//第0列不打印
		{
			printf(" %c", board[i][j]);
		}
		printf("\n");
	}
	printf("\n");
};

//布置雷
void layout_board(char board[ROWS][COLS], int row, int col) {
	int count = easy_count;
	while (count)
	{
		int x = rand() % row + 1;//通过时间戳来随机布置雷
		int y = rand() % col + 1;//1-9
		if (board[x][y] == '0')
		{
			board[x][y] = '1';
			count--;
		}
	}
};

get_main(char mine[ROWS][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 sweep(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col) {
	int x = 0;
	int y = 0;
	int win = 0;
	//81-10

	//判断是否合法
	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");
				display_board(mine, row, col);//给玩家看雷的位置
				break;
			}
			//非雷
			else
			{
				int count = get_main(mine, x, y);//这边传x,y

				//排雷的信息
				show[x][y] = count + '0';
				display_board(show, row, col);//打印所有雷的位置
				win++;
			}
		}
		else
		{
			printf("不合法,请重新输入\n");
		}
	}
	if (win == row * col - easy_count)
	{
		printf("恭喜你排雷成功!!\n");
		display_board(mine, row, col);//打印所有雷的位置
	}

}




text.c

#include "game.h" // 包含游戏相关函数的头文件

void game() {
	// 布置雷的信息
	char mine[ROWS][COLS] = { 0 }; // 初始化为11*11的棋盘
	// 排雷的信息
	char show[ROWS][COLS] = { 0 };
	// 初始化:设置mine和show棋盘上所有格子为0和*
	class_mine_show(mine, ROWS, COLS, '0');
	class_mine_show(show, ROWS, COLS, '*');

	// 打印棋盘(当前显示的是排雷信息)
	display_board(show, ROW, COL); // 显示9*9的棋盘

	// 布置雷
	layout_board(mine, ROW, COL); // 在9*9的棋盘上布置雷

	// 打印棋盘(此时是真正的雷区布局,仅用于调试)
	// display_board(mine, ROW, COL);

	// 排雷操作
	sweep(mine, show, ROW, COL);
}

void meun() {
	printf("************************\n");
	printf("****1 开始   0 结束*****\n");
	printf("************************\n");
};

void text() {
	int input = 0;
	srand((unsigned int)time(NULL)); // 利用时间戳初始化随机数生成器

	do {
		meun();
		printf("请选择>");
		scanf("%d", &input);

		switch (input) {
			case 1:
				printf("扫雷开始\n");
				game(); // 进行一次扫雷游戏
				break;
			case 0:
				break; // 退出程序
			default:
				printf("不合法,请重新选择\n");
				break;
		}
	} while (input);
}

int main() {
	text(); // 运行游戏主界面
	return 0;
}

游戏函数

`game` 函数初始化并执行整个游戏流程。首先,初始化地雷和展示的两个棋盘,然后显示展示棋盘,布置地雷,最后执行排雷操作。

  • 菜单函数

`menu` 函数提供开始和结束选项的简单文本菜单。

主函数

在 `text` 函数中,我们通过一个简单的循环展示菜单,根据用户选择执行游戏或结束程序。


:为什么要先初始化11*11?

在扫雷游戏中,通常需要在棋盘的边缘添加一个边界来帮助计算相邻地雷的数量。因此,在实际编程中,我们需要创建一个比实际游戏面板(99)大2的数组(1111),将边界部分标记为特定字符。

这样做的原因是为了简化计算相邻地雷数量的逻辑。例如,当玩家点击棋盘中心的一个格子时,它有8个邻居(上、下、左、右和四个对角线方向)。如果我们直接使用9*9的数组,那么对于边界上的格子来说,它们的邻居可能超出了数组范围。这会导致我们在处理边界格子时需要额外编写特殊逻辑。

而通过使用11*11的数组并用边界包围真实的游戏区域,我们可以确保所有格子都有完整的8个邻居。这样在计算相邻地雷数量时,我们只需要检查周围8个单元格即可,无需担心越界问题。

在代码中,ROWSCOLS分别表示1111的大棋盘大小,而ROWCOL则表示实际游戏区域的大小(99)。初始化时,我们将整个大棋盘都设置为'0'或'',然后在其中的99区域随机布置地雷,并进行后续的操作。


输出效果

《从入门到精通:扫雷游戏全解析》_第1张图片

四、总结

这个简单的扫雷游戏展示了C语言的基本语法和控制台输入输出的应用。通过使用随机数、循环、和条件语句,我们成功地实现了一个可玩的扫雷游戏

你可能感兴趣的:(游戏)