🚀个人主页:BabyZZの秘密日记
📖收入专栏:C语言
🌍文章目入
C语言实现扫雷游戏:从零开始的编程实践
在编程学习的过程中,实现一个经典的游戏是一个非常有趣且富有挑战性的项目。今天,我们将通过C语言来实现一个简单的扫雷游戏,并详细解析代码的实现过程。这个项目不仅涵盖了数组、函数、随机数生成等基础知识,还展示了如何通过模块化设计来构建一个完整的游戏程序。
一、扫雷游戏简介
扫雷是一款经典的单人游戏,目标是在不触发地雷的情况下,清除所有未被标记为地雷的方格。游戏开始时,玩家看到的是一个由若干行和列组成的网格,每个方格初始状态为隐藏。地雷随机分布在网格中,玩家通过点击方格来揭示其内容。如果方格内有地雷,则游戏失败;如果没有地雷,则会显示该方格周围(包括上下左右及对角线方向)地雷的数量。玩家可以根据这些提示,推断出哪些方格可能有地雷,并避开它们。
二、代码结构与模块化设计
我们的扫雷游戏代码由三个主要文件组成:game.h
、game.c
和 test.c
。这种模块化设计有助于代码的组织和维护。
(一)game.h
:头文件
头文件是C语言中用于声明函数和宏定义的地方,它为其他文件提供了接口。在我们的项目中,game.h
文件定义了游戏的基本参数(如网格的行数和列数、地雷数量等),并声明了实现游戏功能的函数。
#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 Eayscountmine 10 // 地雷数量
// 声明函数原型
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
:游戏逻辑实现
game.c
文件包含了游戏的核心逻辑,包括初始化棋盘、设置地雷、显示棋盘以及玩家寻找地雷的过程。
1. 初始化棋盘
Initboard
函数用于初始化棋盘,将每个方格设置为指定的字符(如 '0'
或 '*'
)。这个函数通过两层嵌套循环遍历整个棋盘数组,并为每个方格赋值。
void Initboard(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; // 将每个位置设置为指定字符
}
}
}
功能解析:
board
是一个二维字符数组,用于存储棋盘的状态。rows
和cols
分别表示棋盘的行数和列数。set
是要初始化的字符,例如'0'
表示无地雷,'*'
表示隐藏状态。
2. 显示棋盘
Displayboard
函数负责将棋盘以友好的格式显示给玩家。它在棋盘的顶部和左侧添加了坐标标记,方便玩家输入坐标。
void Displayboard(char board[ROWS][COLS], int row, int col)
{
printf("========扫雷========\n");
for (int i = 0; i <= col; 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");
}
printf("\n");
}
功能解析:
- 顶部的数字表示列的编号,左侧的数字表示行的编号。
- 每个方格的内容通过
board[i][j]
获取并打印。
3. 设置地雷
Setmine
函数通过随机数生成器在棋盘上随机放置地雷。为了避免重复放置地雷,它会检查目标位置是否已经被设置过地雷。
void Setmine(char board[ROWS][COLS], int row, int col)
{
int count = Eayscountmine; // 地雷数量
while (count) // 直到所有地雷设置完成
{
int x = rand() % row + 1; // 随机生成行坐标
int y = rand() % col + 1; // 随机生成列坐标
if (board[x][y] == '0') // 如果该位置尚未设置地雷
{
board[x][y] = '1'; // 设置地雷
count--; // 地雷数量减1
}
}
}
功能解析:
- 使用
rand()
函数生成随机坐标。 - 检查
board[x][y]
是否为'0'
,以确保不会重复设置地雷。
4. 寻找地雷
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 - Eayscountmine) // 直到清除所有非地雷方格
{
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++; // 清除方格数量加1
}
}
else
{
printf("输入不在范围:x(1~9), y(1~9)\n");
}
}
if (win == row * col - Eayscountmine) // 如果清除所有非地雷方格
{
printf("恭喜你,扫雷成功\n");
Displayboard(mine, ROW, COL); // 显示地雷分布
}
}
功能解析:
mine
数组存储地雷的实际分布,show
数组存储显示给玩家的内容。- 玩家输入坐标后,程序会检查该位置是否有地雷。
- 如果没有地雷,程序会计算该位置周围的地雷数量,并更新
show
数组。
5. 计算周围地雷数量
getminecount
函数用于计算指定位置周围的地雷数量。它通过遍历周围 8 个方向的方格来实现。
int getminecount(char mine[ROWS][COLS], int x, int y)
{
int count = 0;
for (int i = -1; i <= 1; i++) // 遍历周围行
{
for (int j = -1; j <= 1; j++) // 遍历周围列
{
count += (mine[x + i][y + j] - '0'); // 累加周围地雷数量
}
}
return count;
}
功能解析:
- 通过
mine[x + i][y + j]
访问周围方格。 - 使用
(mine[x + i][y + j] - '0')
将字符转换为数字。
(三)test.c
:游戏入口与菜单
test.c
文件是游戏的入口,它负责初始化随机数种子、显示菜单并根据用户选择调用游戏函数。
#define _CRT_SECURE_NO_WARNINGS 1 // 禁用安全警告
#include "game.h"
// 显示菜单
void menu()
{
printf("#####################\n");
printf("#### 1. play ####\n");
printf("#### 0. exit ####\n");
printf("#####################\n");
}
// 游戏主函数
void game()
{
char mine[ROWS][COLS] = { 0 }; // 用于存储地雷分布
char show[ROWS][COLS] = { 0 }; // 用于显示给玩家的棋盘
Initboard(mine, ROWS, COLS, '0'); // 初始化地雷棋盘
Initboard(show, ROWS, COLS, '*'); // 初始化显示棋盘
Displayboard(show, ROW, COL); // 显示初始棋盘
Setmine(mine, ROW, COL); // 随机设置地雷
Findmine(mine, show, ROW, COL); // 玩家寻找地雷
}
// 主测试函数
void test()
{
srand((unsigned int)time(NULL)); // 初始化随机数种子
int input = 0; // 用户输入
do
{
menu(); // 显示菜单
printf("请选择是否开始游戏:");
scanf("%d", &input); // 获取用户输入
switch (input)
{
case 1: // 开始游戏
game();
break;
case 0: // 退出游戏
printf("你选择退出\n");
break;
default: // 无效输入
printf("输入不在范围,请重新输入\n");
break;
}
} while (input); // 循环直到用户选择退出
}
// 主函数
int main()
{
test(); // 调用测试函数
return 0;
}
功能解析:
menu
函数显示游戏菜单,提供开始游戏和退出的选项。game
函数初始化棋盘,设置地雷,并调用寻找地雷的函数。test
函数循环显示菜单并处理用户输入。
三、运行与体验
编译并运行程序后,玩家将看到一个简单的菜单,可以选择开始游戏或退出。游戏开始后,玩家会看到一个由 *
组成的棋盘,表示所有方格都处于隐藏状态。通过输入坐标,玩家可以揭示方格内容。如果揭示的方格有地雷,游戏失败;否则,会显示该方格周围的地雷数量。玩家可以根据这些提示继续寻找地雷,直到清除所有无地雷的方格,或者触发地雷导致游戏失败。
四、总结
通过这个简单的扫雷游戏项目,我们学习了如何使用C语言实现一个完整的程序,包括模块化设计、函数的定义与调用、数组的使用以及随机数生成等知识。虽然这个版本的扫雷游戏功能较为基础,但它为我们提供了一个很好的起点,可以在此基础上进行扩展和优化。例如,我们可以增加标记地雷的功能、调整地雷数量和棋盘大小、优化用户界面等。通过不断改进和扩展,我们可以逐步提升自己的编程能力和对游戏开发的理解。
希望这个项目能激发你对编程的兴趣,同时也为你提供了一个实践和学习的平台。如果你对这个项目有任何疑问或建议,欢迎随时交流和讨论。让我们一起在编程的世界中不断探索和进步!