排查地雷
- 接下来就需要用户排查地雷了
- 我们利用循环提醒用户输入要排查的坐标,有以下五种情况:
- 如果排查的坐标是雷,那么直接退出game()函数,表示排雷失败(如果排雷失败,那么就要向用户展示存放雷的数组,让用户明白到底错在了哪)
- 如果排查的坐标已经被检查过,那么提醒用户,重新输入
- 如果排查的坐标非法,那么提醒用户,重新输入
- 如果排查的坐标不是雷,并且还未排雷完毕,那么显示该区域周围有几个雷,继续循环
- 如果排查的坐标不是雷,并且所有雷已经排查完毕,那么退出game()函数,表示排雷成功
- 每排查完一次,都要重新打印一次展示数组
记录指定区域周围地雷的个数
- 上面我们讲到,要确定一个指定坐标(X,Y)周围地雷的个数,只需要查看(X,Y-1), (X,Y+1), (X+1,Y), (X+1,Y+1), (X+1,Y-1), (X-1,Y), (X-1,Y+1), (X-1,Y-1)这八个坐标的值
- 前面我们已经假设字符‘1’代表地雷,字符‘0’代表非地雷,由于字符‘0’的ASCII的值为48,字符‘1’的ASCII值为49(比字符‘0’大一),那么我们统计(X,Y)周围地雷的个数就只需要将周围八个坐标储存的值相加,然后减去8个字符‘0’即可
- 这也是将字符‘1’设置为地雷,字符‘0’设置为非地雷的巧妙之处,可以在计算地雷个数的时候少去很多操作
/* 这里row = ROWS,col = COLS 这样可以确保排查任意区域操作的一致性(数组不会越界) */ int MineNumber(char board[][COLS], int x, int y) { return (board[x][y - 1] + board[x][y + 1] + board[x - 1][y] + board[x - 1][y - 1] + board[x - 1][y + 1] + board[x + 1][y] + board[x + 1][y - 1] + board[x + 1][y + 1] - 8 * '0'); }
判断排雷成功
- 如果被排查完的区域的总个数等于整块区域的个数减去地雷个数,那就说明排雷成功
/* 传入的是展示数组showBoard 这里row = ROW,col = COL,扩容区域不需要排查 扩容区域只是为了方便记录边界区域周围的地雷个数 */ //如果排雷成功,就返回真,否则返回假 bool MineFinish(char board[][COLS], int row, int col) { int count = 0; //count用来记录已经排查的区域的个数 for(int i = 1; i <= row; i++) for (int j = 1; j <= col; j++) { if (board[i][j] != '*') { count++; if (count == row * col - MINENUMBER) //MINENUMBER就是地雷总个数 return true; } } return false; }
排查地雷实现代码
void MineFind(char mine[][COLS], char show[][COLS], int row, int col) { int x, y; while (1) { printf("请输入您要排查的坐标(用空格分隔):"); scanf_s("%d %d", &x, &y); //如果排查的区域未被检查并且坐标合法 if (show[x][y] == '*' && x > 0 && x <= row && y > 0 && y <= col) { //如果踩到了雷 if (mine[x][y] == '1') { printf("很遗憾,排雷失败\n"); BoardDisplay(mine, row, col); return; } //否则继续排雷 else { show[x][y] = MineNumber(mine, x, y) + '0'; // if (MineFinish(show, row,col)) { printf("恭喜你,排雷成功\n"); BoardDisplay(mine, row, col); return; } BoardDisplay(show, row, col); } } //如果排查的区域合法但已经被检查 else if (show[x][y] != '*' && x > 0 && x <= row && y > 0 && y <= col) { printf("该位置已经被检查,请重新输入:\n"); BoardDisplay(show, row, col); } //如果排查的区域不合法 else { printf("坐标非法,请重新输入:\n"); BoardDisplay(show, row, col); } }
基本功能的实现代码和效果展示
- 我们先来看看实现效果:
- 实现代码:
#include<stdio.h> #include<stdlib.h> #include<time.h> #include<stdbool.h> #define ROW 9 #define COL 9 #define ROWS ROW + 2 #define COLS COL + 2 #define MINENUMBER 10 void BoardInit(char board[][COLS], int row, int col, char set); void BoardDisplay(char board[][COLS], int row, int col); void MineSet(char board[][COLS], int row, int col); int MineNumber(char board[][COLS], int x, int y); void MineFind(char mine[][COLS], char show[][COLS], int row, int col); bool MineFinish(char board[][COLS], int row, int col); void meau() { printf("****************\n"); printf("*****1.Play*****\n"); printf("*****0.Exit*****\n"); printf("****************\n"); } void game() { //生成时间戳 srand((unsigned int)time(NULL)); //定义存放地雷的数组,和展示结果的数组 char mineBoard[ROWS][COLS]; char showBoard[ROWS][COLS]; //对两个数组进行初始化 BoardInit(mineBoard, ROWS, COLS, '0'); BoardInit(showBoard, ROWS, COLS, '*'); //设置地雷 MineSet(mineBoard, ROW, COL); //打印展示数组 BoardDisplay(showBoard, ROW, COL); //排查地雷 MineFind(mineBoard, showBoard, ROW, COL); } void BoardInit(char board[][COLS], int row, int col, char set) { for (int i = 0; i < row; i++) for (int j = 0; j < col; j++) board[i][j] = set; } void BoardDisplay(char board[][COLS], int row, int col) { 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"); } } void MineSet(char board[][COLS], int row, int col) { int count = 0; while (count < MINENUMBER) { int x = rand() % row + 1; int y = rand() % col + 1; if (board[x][y] == '0') { board[x][y] = '1'; count++; } } } void MineFind(char mine[][COLS], char show[][COLS], int row, int col) { int x, y; while (1) { printf("请输入您要排查的坐标(用空格分隔):"); scanf_s("%d %d", &x, &y); if (show[x][y] == '*' && x > 0 && x <= row && y > 0 && y <= col) { if (mine[x][y] == '1') { printf("很遗憾,排雷失败\n"); BoardDisplay(mine, row, col); return; } else { show[x][y] = MineNumber(mine, x, y) + '0'; if (MineFinish(show, row,col)) { printf("恭喜你,排雷成功\n"); BoardDisplay(mine, row, col); return; } BoardDisplay(show, row, col); } } else if (show[x][y] != '*' && x > 0 && x <= row && y > 0 && y <= col) { printf("该位置已经被检查,请重新输入:\n"); BoardDisplay(show, row, col); } else { printf("坐标非法,请重新输入:\n"); BoardDisplay(show, row, col); } } } int MineNumber(char board[][COLS], int x, int y) { return (board[x][y - 1] + board[x][y + 1] + board[x - 1][y] + board[x - 1][y - 1] + board[x - 1][y + 1] + board[x + 1][y] + board[x + 1][y - 1] + board[x + 1][y + 1] - 8 * '0'); } bool MineFinish(char board[][COLS], int row, int col) { int count = 0; for(int i = 1; i <= row; i++) for (int j = 1; j <= col; j++) { if (board[i][j] != '*') { count++; if (count == row * col - MINENUMBER) return true; } } return false; } int main() { int input; meau(); //展示选择菜单 printf("请输入您的选择:"); while (1) { scanf_s("%d", &input); switch (input) { case 1: game(); break; case 0: printf("退出游戏,感谢游玩\n"); break; default : printf("输入错误,请重新输入:"); break; } meau(); printf("是否重新游玩:"); } return 0; }
拓展功能
简化游戏界面
- 根据上面的展示我们可以看到,我们每排查一次,展示数组就要打印一次,这样就会使得游戏界面太过复杂
- 我们可以使用system(“cls”)函数来清除已经不需要的打印结果
- 注:要包含头文件
- 修改后的MineFind()函数:
void MineFind(char mine[][COLS], char show[][COLS], int row, int col) { int x, y; while (1) { printf("请输入您要排查的坐标(用空格分隔):"); scanf_s("%d %d", &x, &y); //就是多了这样一条语句 system("cls"); if (show[x][y] == '*' && x > 0 && x <= row && y > 0 && y <= col) { if (mine[x][y] == '1') { printf("很遗憾,排雷失败\n"); BoardDisplay(mine, row, col); return; } else { show[x][y] = MineNumber(mine, x, y) + '0'; if (MineFinish(show, row,col)) { printf("恭喜你,排雷成功\n"); BoardDisplay(mine, row, col); return; } BoardDisplay(show, row, col); } } else if (show[x][y] != '*' && x > 0 && x <= row && y > 0 && y <= col) { printf("该位置已经被检查,请重新输入:\n"); BoardDisplay(show, row, col); } else { printf("坐标非法,请重新输入:\n"); BoardDisplay(show, row, col); } } }
- 实现效果:
改变字体颜色
- 为了将坐标数字和代表地雷个数的数字作出区分,我们可以改变这两种数字的颜色
- 如果对如何改变字体颜色和背景色还不是太了解,可以先看看C语言——修改控制台背景色和字体颜色这篇博客
- 直接上代码(只需要调整打印数组的函数BoardDisplay且在主函数最开始加上system(“color”)函数即可)
int main() { system("color 17"); ………………; }
void BoardDisplay(char board[][COLS], int row, int col) { for (int i = 0; i <= col; i++) { SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 4 | 16); printf("%d ", i); } printf("\n"); for (int i = 1; i <= row; i++) { SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 4 | 16); printf("%d ", i); SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7 | 16); for (int j = 1; j <= col; j++) printf("%c ", board[i][j]); printf("\n"); } }
- 看看效果: