使用二维数组,指针和函数的知识实现地雷数和棋盘大小可变的扫雷游戏
完整代码如上,此代码在上文基础上增加了即时显示时间和限时通关的功能。
程序截图
1.时间计算
- 通过time函数获取时间戳
- 在游戏开始的时候获取一次,赋给变量timeStart,作为初始时间
- 之后每此循环获取一次,赋给变量timeCurrent,作为当前时间
- 则时间差值就是游戏时长timeDifference = timeCurrent - timeStart;
void game(int x, int y, int nummine) {
time_t timeStart = time(NULL);//初始时间
int num = x * y - nummine; //统计无雷且未被探测的格子数,当为0时退出退出,此时所有未探测的地方都有雷
char flag[100][100]; //标记已经探测过的位置,当已经探测过,显示周围地雷数,否则显示*
int mine[101][101]; // 统计地雷位置,有雷时为1,无雷时为0;
int bl = 0;
Lay(x, y, nummine, flag, mine); //初始化游戏数据
system("CLS");
do {
time_t timeCurrent = time(NULL);//当前时间
int timeDifference = difftime(timeCurrent,timeStart);//时间差
if(bl != 4) interfaceone(x, y, flag); //打印游戏界面
printf("(还有%d个无雷格子待探测)", num);
bl = detect(x, y, &num, bl, mine, flag, timeDifference); //进行扫雷行为
Sleep(10);//程序休眠10ms
if (bl == 4) printf("\r");
else system("CLS");//清空屏幕
if (num == 0) break;//剩余无雷格子数为0时游戏胜利。
} while (bl);
if (bl) printf("*********扫雷完成**********\n");
else print(x, y, mine);
}
2.无输入时继续程序运行
正常来说,循环计算时间差值打印在屏幕上作为程序运行时间没有问题。但是C语言的语句执行时顺序的,而我们每次循环都需要输入一个坐标来进行地雷探测。在输入的时候,程序会停止在这一行。此时屏幕上的时间计数也会停止;
我们需要程序在我们没有输入的时候继续循环打印时间,在有输入的时候获取输入。
这时候使用__kbhit()
if(_kbhit())
scanf("%d %d",&a,&b);//有输入时获取输入 赋值给变量a,b
else
return;//无输入时结束函数
3.扫雷过程中实现即时显示时间
int detect(int x, int y, int* num, int bl, int mine[101][101], char flag[100][100],int timeDifference) {
int a, b;
if (bl == 2) printf("这个位置已经探测过了,请输入一个未探测过的位置(%ds):>", timeDifference);
else if (bl == 3) printf("这个位置不在棋盘上,请重新输入(%ds):>", timeDifference);
else printf("请输入你要探测的位置(%ds):>", timeDifference);
if (_kbhit()){//有输入时开始探测
scanf("%d %d", &a, &b);
if (a <= x && b <= y && a > 0 && b > 0) {
if (mine[a][b]) return 0;//如果有雷则退出
else if (flag[a][b] != 42) return 2;
else {
flag[a][b] = numminearound(a, b, mine);
(*num)--;
return 1;
}
}
else return 3;//
}
else return 4;//无输入时返回3
}
4. 保持屏幕干净
- system(“CLS”)可以实现清空控制台界面;
- printf(“\t”);可以让指针回到行首,实现删除指针所在行的功能
4.1 detect的返回值
- 在返回数为0时,表示扫到了雷,游戏失败
- 返回数为1时,表示探测地无雷。且已经显示探测地周围雷数。
- 返回数为2时,表示新的探测地点在前面的游戏行为中已经被探测过了。直接退出,不在探测周围雷数。
- 返回值为3时,则探测的地方不在棋盘上。请求重新输入
- 返回值为4时,玩家没有输入行为
4.2 根据返回值判断如何清理屏幕
- 返回值为0时,游戏失败,运行system(“CLS”)打印地雷棋盘和开始菜单。玩家可以选择重新开始游戏或者退出。
- 返回值为4时,玩家没有输入,运行printf(“\t”)。使得屏幕上显示时间戳被清除。重新打印。(此时只是在屏幕的相同位置循环打印时间,不影响棋盘)
- 返回值为其他,此时玩家有输入。运行system(“CLS”)清除屏幕,并打印棋盘和时间。(此时同时打印棋盘和时间)
do {
time_t timeCurrent = time(NULL);//当前时间
int timeDifference = difftime(timeCurrent,timeStart);//时间差
if(bl != 4) interfaceone(x, y, flag); //打印游戏界面
printf("(还有%d个无雷格子待探测)", num);
bl = detect(x, y, &num, bl, mine, flag, timeDifference); //进行扫雷行为
Sleep(10);//程序休眠10ms
if (bl == 4) printf("\r"); //只清理时间
else system("CLS");//清空屏幕
if (num == 0) break;
} while (bl);
5.实现限时通关
- 我们已经成功统计了游戏内的时间
- 只需要设置一个时间最大值,在时间超过这个最大值时退出
int timemax = 0;
if(timemax){ //当时间最大值大于0时判断是否超时,否则表示没设置时间上限
if(timeDifference > timemax) {
bl = 0; //bl为detect函数的返回值,当bi为0时表示扫到雷了,循环退出。
}
}
还需要修改bl等于0时的逻辑,之前bl=0时只有一种情况:踩到雷了;现在多了一种:超出时间
if (bl) printf("*********扫雷完成**********\n");
else {
if(timeDifference > timemax) printf("*****扫雷失败,时间耗尽*****\n");
else printf("*****扫雷失败,踩到雷了*****\n");
print(x, y, mine)
}
游戏内打印的时间变为剩余时间
else printf("请输入你要探测的位置(%ds):>", timemax-timeDifference);
//可以直接把timemax-timeDifference的结果当参数传入detect函数,否则还要把两个变量都传入