扫雷游戏作为一款经典的益智小游戏,承载了许多人的回忆。它不仅考验玩家的逻辑思维和推理能力,还充满了趣味性和挑战性。在这篇博客中,我们将详细探讨如何使用C语言实现一个简单的扫雷游戏,深入分析代码的各个部分,帮助你理解其中的原理和实现思路。
本扫雷游戏项目采用模块化编程的思想,将不同的功能封装到不同的文件中,这样可以提高代码的可读性、可维护性和可扩展性。整个项目主要由三个文件组成:
game.h
:头文件,用于声明函数和定义常量。game.c
:实现游戏中各个功能的函数。mytext.c
:主程序文件,包含菜单和游戏流程的控制。game.h
文件#pragma once
#include
#include
#include
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
#define EASY_COUNT 10
//棋盘初始化的函数
void InitBoard(char arr[ROWS][COLS], int rows, int cols, char set);
//打印棋盘
void DisplayBoard(char arr[ROWS][COLS], int row, int col);
//布置雷
void SetMine(char arr[ROWS][COLS], int row, int col);
//排查雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
在这个头文件中,我们做了以下几件重要的事情:
stdio.h
用于输入输出操作,stdlib.h
用于动态内存分配和随机数生成,time.h
用于获取当前时间。ROW
和列数 COL
,以及扩展棋盘的行数 ROWS
和列数 COLS
。扩展棋盘的目的是为了方便处理边界情况,避免越界访问。EASY_COUNT
。game.c
文件#include "game.h"
//棋盘初始化的函数
void InitBoard(char arr[ROWS][COLS], int rows, int cols, char set)
{
int i;
for(i = 0; i < rows; i++)
{
int j;
for(j = 0; j < cols; j++)
{
arr[i][j] = set;
}
}
}
//打印棋盘
void DisplayBoard(char arr[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++)
{
int j = 0;
//打印行号
printf("%d ",i);
for(j = 1; j <= col; j++)
{
printf("%c ",arr[i][j]);
}
printf("\n");
}
}
//布置雷
void SetMine(char arr[ROWS][COLS], int row, int col)
{
int count = EASY_COUNT;
while(count)
{
int x = rand() % row + 1;
int y = rand() % col + 1;
if(arr[x][y] == '0')
{
arr[x][y] = '1';
count--;
}
}
}
//统计某坐标周围雷数量
static int GetMineCount(char mine[ROWS][COLS], int x, int y)
{
int i = 0;
int count = 0;
for (i = x - 1; i <= x + 1; i++)
{
int j = 0;
for (j = y - 1; j <= y + 1; j++)
{
count += (mine[i][j] - '0');
}
}
return count;
}
//排查雷
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 >= 0 && x <= row && y >= 0 && y <= col)
{
if(show[x][y] == '*')
{
if(mine[x][y] == '1' )
{
printf("你被炸死了 !\n");
DisplayBoard(show, ROW, COL);
break;
}
else
{
//该坐标不是雷,就得统计坐标周围有几个雷
int count = GetMineCount(mine, x, y);
show[x][y] = count + '0';
DisplayBoard(show, ROW, COL);
win++;
}
}
else
{
printf("该坐标已经被排查了,请重新输入坐标\n");
}
}
else
{
printf("坐标非法,请重新输入 !\n");
}
}
if (win == row * col - EASY_COUNT)
{
printf("恭喜你,排雷成功\n");
DisplayBoard(mine, ROW, COL);
}
}
这个文件实现了游戏中各个核心功能的函数:
InitBoard
函数:该函数用于初始化棋盘,通过两层嵌套的 for
循环遍历棋盘的每一个元素,并将其赋值为指定的字符 set
。这样可以方便地将棋盘初始化为不同的状态,例如将 mine
数组初始化为 '0'
表示没有雷,将 show
数组初始化为 '*'
表示未排查状态。DisplayBoard
函数:此函数用于打印棋盘,首先打印列号,然后逐行打印棋盘的每一行,并在每行的开头打印行号。这样可以让玩家清楚地知道每个格子的坐标,方便输入排查的坐标。SetMine
函数:该函数用于在棋盘上随机布置雷,使用 rand()
函数生成随机的坐标 (x, y)
,并检查该位置是否已经有雷。如果没有雷,则将该位置标记为雷('1'
),并减少剩余需要布置的雷的数量 count
,直到所有的雷都布置完毕。GetMineCount
函数:这是一个静态函数,用于统计指定坐标周围的雷的数量。通过两层嵌套的 for
循环遍历指定坐标周围的 8 个格子(包括自身),将每个格子的值减去 '0'
转换为整数并累加到 count
中,最后返回 count
。FindMine
函数:该函数是游戏的核心逻辑,负责玩家的排查操作。通过一个 while
循环不断获取玩家输入的坐标,检查坐标的合法性和该位置是否已经被排查过。如果排查到雷,则游戏失败;如果排查的位置不是雷,则统计周围雷的数量并更新 show
数组,同时增加已排查的非雷格子数量 win
。当 win
等于非雷格子的总数时,游戏胜利。mytext.c
文件#include "game.h"
void menue()
{
printf("*******************\n");
printf("*****1. play*******\n");
printf("*****0. exit*******\n");
printf("*******************\n");
}
void game()
{
char mine[ROWS][COLS] = {0}; //将arr1初始化为 '0'
char show[ROWS][COLS] = {0}; //将arr2初始化为 '*'
InitBoard(mine, ROWS, COLS, '0');
InitBoard(show, ROWS, COLS, '*');
SetMine(mine, ROW, COL);
//DisplayBoard(mine, ROW, COL);
//打印棋盘
DisplayBoard(show, ROW, COL);
//排查雷
FindMine(mine, show, ROW, COL);
}
void test()
{
int input;
srand((unsigned int)time(NULL));
do{
menue();
printf("请选择:> ");
scanf("%d", &input);
switch(input)
{
case 1:
game();
break;
case 0:
printf("游戏结束,退出游戏");
break;
default:
printf("选择错误,请重新选择 !");
break;
}
}while(input);
}
int main()
{
test();
return 0;
}
这个文件是主程序文件,主要负责游戏的菜单显示和流程控制:
menue
函数:用于显示游戏菜单,提供两个选项:开始游戏(输入 1)和退出游戏(输入 0)。game
函数:该函数是游戏的入口,负责初始化 mine
和 show
数组,布置雷,打印初始棋盘,并调用 FindMine
函数开始排查雷。test
函数:使用 do-while
循环不断显示菜单,获取玩家的选择,并根据选择执行相应的操作。使用 srand((unsigned int)time(NULL))
初始化随机数种子,确保每次游戏的雷的布置都是随机的。main
函数:调用 test
函数,启动游戏。通过以上三个文件的协同工作,我们成功实现了一个简单的扫雷游戏。模块化编程的思想使得代码结构清晰,易于理解和维护。在实现过程中,我们使用了数组、循环、条件判断、函数等C语言的基本知识点,同时还涉及到随机数生成和字符处理等技巧。
你可以将上述代码复制到你的C语言开发环境中编译运行,体验自己实现的扫雷游戏。如果你对代码有任何疑问或者想要进一步扩展功能,欢迎在评论区留言讨论。希望这篇博客对你有所帮助!