前言
扫雷作为一个童年经典小游戏,还是比较有意思的。今天我们就用C语言来实现一个简易版的扫雷小程序,难度也不高,也是一个可以拿来当做前期学习C语言的练手小项目。
一、游戏规则
1、扫雷棋盘由一个方格网格组成,每个方格可能包含雷或数字。
2、每一次选择一个方格,方格即被打开并显示出方格中的数字,方格中数字则表示其周围的8个方格隐藏了几颗雷。例如数字是1,就代表黑色方框中的其他8个方格中有1颗雷。同理,如果数字是3,就表示周围的8个方格隐藏了3颗雷。
3、玩家依次进行选择,当玩家选择到的位置是雷时,即是踩雷,游戏失败;而当玩家选择出了不是雷的所有数字方格后,则是排雷成功,游戏胜利。
二、所需技术
本次我们将使用C语言来实现这个简易版的扫雷游戏,对于C语言的要求不是很高,跟之前的三子棋难度相近,只需熟练掌握循坏与分支、二维数组、函数编写和调用相关知识,同时运用分文件模式进行编写,这也是一个前期C语言学习的练手小项目,而且程序编写出来后可玩性比三子棋强,还可以给自己或者朋友玩一玩,趣味性较高。
三、编写菜单目录
头文件部分
在正式编写程序前,我们先进行头文件的编写,先将要用到的头文件用#include进行包含。本次我们就实现一个简单版的扫雷游戏,所以棋盘大小我们就只设定为9*9的大小,后面如果想要增加难度,就只需在头文件这里的#define宏定义位置改变大小即可改变棋盘大小,这样可以使程序的可维护性变高。而后面的函数声明部分是当你后面每次要写一个函数时,就在头文件这里多加一份函数的声明,这样就可以实现函数的声明和定义的分离,进而实现了分文件的编写。
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define X 9
#define Y 9
void chu(char arr[X][Y], char brr[X][Y],int x, int y);
void pan(char arr[X][Y], int x, int y);
void lei(char brr[X][Y], int x, int y);
int play(char arr[X][Y], char brr[X][Y], int x, int y);
char suan(char brr[X][Y], int x, int y, int a, int b);
顺带一提,变量的命名和函数的命名建议用英文取一些更有意义的名字,这样更加规范。
菜单目录部分
void menu()
{
printf("**********************\n");
printf("*********扫雷*********\n");
printf("******1.开始游戏******\n");
printf("******0.退出游戏******\n");
printf("**********************\n");
}
int main()
{
srand((unsigned)time(NULL));
int n = 0;
do
{
menu();
scanf("%d", &n);
switch (n)
{
case 1:
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("输入错误,请重新输入:\n");
}
} while (n);
return 0;
}
srand((unsigned)time(NULL)); --这一语句是初始化随机数,为后面程序使用rand()函数获得随机数做铺垫。
然后是一个do…while语句嵌套switch语句做一个开始的菜单目录(这是一个简单的模版,后面的很多开始菜单目录都可以这样实现)。然后可以设置一个menu()函数,里面就可以编写程序自定义打印菜单目录的内容。这里的这段程序当我们输入1时,就会调用game()函数,进入我们的游戏内容部分。
四、游戏内容部分
1、游戏运行部分
void game()
{
char arr[X][Y] = { 0 };
char brr[X][Y] = { 0 };
chu(arr,brr, X, Y);
pan(arr, X, Y);
lei(brr, X, Y);
while (1)
{
int s = play(arr, brr, X, Y);
if (s == 0)
{
pan(brr, X, Y);
printf("你被炸死了,游戏失败!\n");
break;
}
else if (s == 1)
{
pan(arr, X, Y);
continue;
}
else if (s == 2)
{
pan(brr, X, Y);
printf("扫雷成功,游戏胜利!\n");
break;
}
}
}
首先我们要定义两个二维数组arr,brr(建议取一些更有意义的名字,后面的函数命名也是),一个数组(arr)主要是为了打印出来给我们看的,另一个数组(brr)主要是用来存储每个方格位置的具体内容(雷或者数字)。然后使用chu()函数对两个数组棋盘进行初始化,全部初始化为’ '(空格字符)。pan()函数就是一个打印棋盘的函数。lei()函数就是对棋盘的雷进行初始化,即埋雷。然后用一个死循环来让游戏持续进行,通过play()函数的返回值来判断游戏状态,然后决定是否跳出循环结束游戏。
2、游戏内容部分
chu()函数,用来对两个棋盘进行初始化,将每个位置都初始化为’ '(空白字符)。
void chu(char arr[X][Y], char brr[X][Y], int x, int y)
{
int i = 0;
for (i = 0; i < x; i++)
{
int j = 0;
for (j = 0; j < Y; j++)
{
arr[i][j] = ' ';
brr[i][j] = ' ';
}
}
}
pan()函数,负责进行打印棋盘的操作。
void pan(char arr[X][Y], int x, int y)
{
int i = 0;
for (i = 0; i < X; i++)
{
int j = 0;
for (j = 0; j < Y; j++)
{
printf("---");
}
printf("\n");
for (j = 0; j < Y; j++)
{
printf("| %c", arr[i][j]);
if (j == Y - 1)
{
printf("|");
}
}
printf("\n");
if (i == X - 1)
{
for (j = 0; j < Y; j++)
{
printf("---");
}
printf("\n");
}
}
}
通过for循环的嵌套来打印棋盘,这里使用的是打印"—“和”|"配合打印数组来生成棋盘,你可以根据自己的想象和实践打印一个更好看的棋盘也可。
lei()函数,进行生成随机位置的雷,进行埋雷操作。这里考虑到棋盘大小为9*9,所以这里通过rand()函数随机在不同设置了10个雷,这里用 * 字符来表示雷,即将brr数组相应的位置设置为 * 字符。
void lei(char brr[X][Y], int x, int y)
{
int i = 0;
for (i = 0; i < 10; i++)
{
int a = rand() % x;
int b = rand() % y;
if (brr[a][b] == ' ')
{
brr[a][b] = '*';
}
else
{
i--;
}
}
}
play()函数,实现游戏内容的主要函数。当玩家输入一个位置时,要先要判断是否越界,以及是否已经下过(已有数字)。当都不满足时,才算是输入了合理的坐标,然后进行判断,通过返回值来控制游戏状态。
当该位置为雷时,即踩雷,返回0,游戏失败;若不为雷,则调用一个suan()函数进行计算该位置周围有多少个雷。这里需要注意的是字符数字和整形数字的区别,因为棋盘是char类型的二维数组,所以赋值给两个数组具体位置时一定要用字符数字,不然在打印棋盘时以"%c"的格式打印会出现问题,而将int类型的数字转换为char类型的字符数字只需加一个’0’或48即可。之后对brr数组进行遍历,一旦还有’ '(空格字符),说明还没有完成排雷,则返回1,游戏继续;而当遍历完brr数组后’ '(空格字符)数量n仍然为0的话,说明brr数组中不是雷就是数字,即已经排雷完成,返回2,游戏胜利。
char suan(char brr[X][Y], int x, int y,int a,int b)
{
char c = 0;
int i = 0;
for (i = x - 1; i <= x + 1; i++)
{
int j = 0;
for (j = y - 1; j <= y + 1; j++)
{
if (brr[i][j] == '*' && i >= 0 && i <= a - 1 && j >= 0 && j <= b - 1)
{
c = c + 1;
}
}
}
return c;
}
int play(char arr[X][Y], char brr[X][Y], int x, int y)
{
int a = 0;
int b = 0;
while (1)
{
printf("请输入坐标:");
scanf("%d %d", &a, &b);
if (a >= 1 && a <= x && b >= 1 && b <= y)
{
if (brr[a-1][b-1] == '*')
{
return 0;
}
else if (brr[a-1][b-1] == ' ')
{
char z = (char)suan(brr,a-1,b-1,x,y);
brr[a - 1][b - 1] = 48 + z;
arr[a - 1][b - 1] = 48 + z;
int n = 0;
int i = 0;
for (i = 0; i < x; i++)
{
int j = 0;
for (j = 0; j < Y; j++)
{
if (brr[i][j] == ' ')
{
n++;
}
if (n)
{
return 1;
}
}
}
return 2;
}
else
{
printf("坐标重复,请重新输入!\n");
}
}
else
{
printf("输入错误,请重新输入!\n");
}
}
}
这是完成后的大致效果
总结
本次扫雷游戏的简易实现分享就到这里了,该版本比较基础,适合C语言初学者练手巩固基础。
在这里我给出以下几个可以改进提升的地方:
1、可以在棋盘外边多打一圈坐标数字,这样选择位置时就能一目了然,不用再去数坐标位置。
2、可以多增设几个游戏难度,即可以扩大棋盘的大小和雷的数量等,让玩家有更灵活的选择。
3、该版本只能一个坐标一个坐标地推进游戏,有点慢。我们都知道当选择的位置为数字0时,周围一圈肯定是没有雷的,但我们还需一次一次地下周围那一圈,很麻烦,所以当我们选择位置为0时,可以让电脑自动帮我们把周围的一圈下了。这里提供一个很常规的思路就是使用递归来解决这个问题,而且递归对于初学者可能还是有一定难度的,所以如果你能用递归解决这个问题应该能有很大的收获。
这里我只是列举了几个可以改进的地方,当然你还可以根据你的需求来让这个程序更加丰满。
如需源码,可在我的gitee上找到,下面是链接。
扫雷源码
如对您有所帮助,可以来个三连,感谢大家的支持。
每文推荐
林宥嘉–背影
司南–冬眠
周传雄–冬天的秘密
学技术学累了时可以听歌放松一下