目录
前言
一、总体规划
二、使用步骤
1.特别的
2.游戏的开关
3.游戏的实现
(1).初始化棋盘
(2).打印棋盘
(3).布置雷
(4).排查雷
总结
前言
排雷,非常经典的一个小游戏,最近有幸学到了其相关知识,借于此想把它用c语言实现的步骤说出来提供参考,以便我后续的反思与掌握。
一、总体规划
首先,要制作一个项目,整体的规划是十分重要的,以便我们早早的把问题想清楚,程序的设计做好规划,别到时候编写程序遇到问题在想,因为那个时候在改动程序是十分的麻烦的。
实现简易的扫雷游戏,首先要实现游戏的开关(可别把游戏的登出键扣了(▼ヘ▼#)),然后就要看到游戏的运行里去:你要布置一下棋盘,初始化一下棋盘,要能放地雷,和呈现给玩家的棋盘。所以,这里就需要两个棋盘。然后就要把棋盘打印出来,随后就要布置雷,布置雷的话要明确布置几个和随机布置,那就要用到rand()函数了,然后玩家排雷,选中的数组检查是否有雷,有雷游戏结束,没有雷就检查周围是否存在雷,存在几个雷。这个由其重要,因为这种的特殊情况就是涉及到数组越界访问的问题,为了不让我们每次都对数组是否越界,那么我们一开始对这个棋盘进行扩展,是展示只展示一部分,而实际的要大,以便不用判断是否越界和下标对应的好处。随后,将检查到的数存入展示数组中,进行循环,循环直到排雷完或者被雷炸到游戏结束,进行下次游戏是否继续询问即可。
总之就是:游戏的开关,布置棋盘,打印棋盘,布置雷,玩家排雷,检查。
二、使用步骤
1.特别的
创建项目时,为了使其分工更明显更模块化一般分成几个文件进行使用,而定义宏,头文件,函数的声明一般几个文件都要用,所以放入一个文件(.h)中,其他的一个专门放实现功能函数的代码l另一个文件专门用来测试(.c)
比如:game.h game.c test.c
一般在边做函数时在上什么和定义头文件和宏,这里为了后续好说明,先上game.h头文件的内容
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
//定义宏
#define LINE 9 //真正的行和列
#define COLUMN 9
#define LINES 11 //用于统计雷的行和列
#define COLUMNS 11
#define MINES 10 //布置雷的个数
//函数声明
//菜单函数
void manu();
//初始化函数 第一个字符数组初始化为0,第二个字符数组初始化为*
void Initialize_the(char(*a)[COLUMNS], char(*b)[COLUMNS], int lines, int columns);
//打印函数
void print(char(*arr)[COLUMNS], int line, int column); //注意s和无s的区别
//布置雷
void Arrangement_of_mine(char(*a)[COLUMNS], int line, int column, int mines);
//排雷
void Eliminate_landmines(char(*a)[COLUMNS], char(*b)[COLUMNS], int line, int column);
2.游戏的开关
废话不多说,直接上代码:
static void test()
{
int a = 0;//选择1or0按钮
srand((unsigned int)time(NULL)); //一个工程里面设置一个rand随机数产生起点,使其获得系统时间,随时发生变化。可达到随机的效果
do {
manu();
printf("请选择->");
scanf("%d", &a);
switch (a)
{
case 1:
printf("开始游戏\n");
game();
break;
case 0:
printf("谢谢游玩,欢迎下次游玩\n");
break;
default :
printf("输入错误请重新输入:\n");
break;
}
} while (a);
}
int main()
{
test();
return 0;
}
这里所用的manu()菜单函数是在game.c文件里面实现的,其中代码是:
//菜单图像
void manu()
{
printf("###############game_Mine_clearance#############\n");
printf("############### 1.start #############\n");
printf("############### 0.exit #############\n");
printf("###############################################\n");
}
然后使用了switch来实现我们游戏开关的流程,这里是在test.c文件里面实现的
接下来,就要对game函数进行具体的实现:
3.游戏的实现
先上代码:
void game()
{
char a[LINES][COLUMNS] = { 0 }; //布置雷的棋盘,放置0/1,注意是在我们想要呈现的棋盘|行和列均加了2|
char b[LINES][COLUMNS] = { 0 }; //呈现给玩家的棋盘,放置*/'数字'
Initialize_the(a, b, LINES, COLUMNS); //初始化棋盘
print(b, LINE, COLUMN); //打印棋盘
Arrangement_of_mine(a, LINE, COLUMN, MINES); //布置雷,在a字符数组中,MINES代表了几个雷
//print(a, LINE, COLUMN);
Eliminate_landmines(a, b, LINE, COLUMN); //玩家开始排雷 a检查是否有雷器,b是给玩家呈现结果器
print(a, LINE, COLUMN); //退出来了说明失败了或者成功排完了
}
首先就是要得到两个存放棋盘的数组,一个用于放雷,一个用于呈现给玩家,其次就要初始化棋盘,打印棋盘,布置雷,排雷,检查,下面来具体说明每个函数具体实现的功能:ps:这里的每个函数均在game.c文件里面实现
(1).初始化棋盘
//初始化棋盘
void Initialize_the(char(* a)[COLUMNS], char(*b)[COLUMNS], int lines, int columns)
{
for (int i = 0; i < lines; i++)
for (int j = 0; j < columns; j++)
{
a[i][j] = '0'; //布雷棋盘(相当于透视眼,里面0代表没有雷,1代表有雷)
b[i][j] = '*'; //呈现棋盘(给玩家看的)
}
}
这里分别对不同的棋盘进行初始化,其中一个为放雷的(1为雷),这里为什么偏要设1为雷呢,这就是长远规划的好处了:以后我们在检查周围存在的雷时,只需要周围的元素相加即可,这样就保证了不用嵌套判断来进行判断了,但是这个函数也可以进行优化,让它变成三个形参,把一个数组指针删掉,一个形参替换为符号来接受,稍作修改可以根据传过来的符号进行对这样的符号进行初始化。
(2).打印棋盘
顾名思义,就是打印到屏幕上给玩家看的,那么,先上代码:
void print(char(*arr)[COLUMNS], int line, int column)
{
printf("--------------saolei--%d*%dge-------------------------\n", line, column);
for (int i = 0; i <= line; i++) //打印列数,方便数
printf("%3d", i);
printf("\n");
for (int i = 1; i <= line; i++) {
printf("%3d", i); //打印行数,方便数
for (int j = 1; j <= column; j++)
printf("%3c", arr[i][j]);
printf("\n");
}
printf("--------------saolei--%d*%dge-------------------------\n", line, column);
}
第一行和最后一行是为了美观的(不知道是不是美工做的事,其实我也不知道) ,随后的定义三个空是防止以后出现100以上的棋盘(10*10)
(3).布置雷
比较重点的部分来了,因为现在棋盘都已经初始化好了,现在我们只需对专门弄雷的数组进行放置MINES个雷就好了:
void Arrangement_of_mine(char(*a)[COLUMNS], int line, int column, int mines)
{
//使用随机数产生函数,用它来模line或者column然后加一可以实现随机1~line\column的效果
int x = 0;//对应line
int y = 0;//对应column
while (mines)
{
x = rand() % line + 1;
y = rand() % column + 1;
if (a[x][y] == '0') {
a[x][y] = '1';
mines--;
}
}
}
这里要使用rand函数,所以对应的整个工程在起初要设一个随机数产生起点,接受系统随机变化的值即可:
srand((unsigned int)time(NULL)); //一个工程里面设置一个rand随机数产生起点,使其获得系统时间,随时发生变化。可达到随机的效果
这个放在test函数里面,对应文件test.c里面,上面的//就可以去掉了。
(4).排查雷
玩家输入坐标,来排除此处的雷(自然是限定范围之内),那么我们首先判断此处是否存在1,存在1就死,因为触发了雷了,如果不是,那么就统计周围有多少雷。上代码:
排查函数:
void Eliminate_landmines(char(*a)[COLUMNS], char(*b)[COLUMNS], int line, int column)
{
int x = 0;
int y = 0;
int sum = 0;//统计排雷的个数
while (sum < line*column -MINES) {
printf("请输入要排雷的坐标->");
scanf("%d %d", &x, &y);
if (x < 0 || y < 0 || x > line || y > column) {
printf("输入坐标错误,请重新输入\n");
continue;
}
if (a[x][y] == '1') {
printf("嘭!排雷失败\n");
break;
}
b[x][y] = statistical(a, x, y) + '0';//统计周围的雷的个数
print(b, LINE, COLUMN);
printf("排雷成功!\n");
sum++; //统计除开雷所排出的个数
}
if (sum == line * column - MINES)
printf("恭喜你排完了全部的雷\n");
}
statistical函数就是用于排查周围的雷的,单独写出,函数类型为int
int statistical(char(*a)[COLUMNS], int x, int y)
{
return a[x][y - 1] + a[x][y + 1] + a[x + 1][y] + a[x + 1][y - 1] +
a[x + 1][y + 1] + a[x - 1][y] + a[x - 1][y - 1] + a[x - 1][y + 1] - 8*'0';
}
特别注意:这里需要说明的是,数组是字符数组,所以相加是字符相加,既然字符相加的话就应该是ascll值相加,因为我们要返回的是整型,如果不每个减去零字符的ascll码值的话那返回的十个什么数,转化后就不是数字了,所以每个数组元素都有减去‘0’,随后,在接受函数那里因为是用的字符数组储存,所以返回来的数实际上是ascll值,加一个‘0’的ascll码值,理所应当储存进去的就是数字字符啦,而不是什么奇奇怪怪的东西。
总结
最后,这个排雷小游戏就实现啦!首先要对这个游戏的玩法深挖,比如解决问题的方法,想清楚之后,也就是做好规划之后在进行写代码效果越好,代码就越高效。
更多推荐
简易的排雷小游戏(c语言制作)
发布评论