今天学习如何实现简单的扫雷小游戏。
1.函数接口即宏定义
想要完成扫雷这个小游戏,我们需要棋盘,地雷这两个实现,在这里我们利用二维数组表示一个棋盘,用字符0与1存放在数组里表示无地雷与地雷。
对于棋盘的定义我们会定义两个数组,一个是用来存放地雷的,一个是所需要展示的棋盘,即玩家游玩时展示的。其次对于棋盘的大小因为要考虑计算某一位置处周围雷的个数,对于边缘的元素,我们需要判断它首先是否有效,这样太过麻烦,于是我们将棋盘扩大一圈,但只使用原大小棋盘的所有位置。
我们这里实现的是九成九大小的棋盘用作扫雷,但使用的时候用的是十一乘十一。
#pragma once #define ROW 9 #define COL 9 #define ROWS ROW+2 #define COLS COL+2 #define COUNT 10 #include <stdio.h> #include <stdlib.h> #include <time.h> //初始化棋盘 void InitBoard(char board[ROWS][COLS], int rows, int cols, char set); //打印棋盘 void DisplayBoard(char board[ROWS][COLS], int row, int col); //布置雷 void SetMine(char mine[ROWS][COLS], int row, int col); //排查雷 void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
对于操作实现主要是排查雷这一操作。
2.初始化棋盘
因为需要分别初始化定义的两个二维数组,一个是扫雷的本质操作,一个用作玩家展示。
扫雷棋盘初始化全为0,玩家展示棋盘初始化为*,就是未知的/两个棋盘大小相等。
所以这里初始化的参数需要有一个字符,来表示给棋盘初始化全是什么。
void InitBoard(char board[ROWS][COLS], int rows, int cols,char set) { int i = 0; int j = 0; for (i = 0; i < rows; i++) { for (j = 0; j < cols; j++) { board[i][j] = set; } } }
3.打印棋盘
打印棋盘就是遍历每一元素并打印,为了游戏操作时输入坐标方便,我们给打印出的棋盘添加了行与列。操作简单不做赘述。
void DisplayBoard(char board[ROWS][COLS], int row, int col) { int i = 0; int j = 0; printf("******* 扫雷 *******\n"); for (j = 0; j <= col; j++) { printf("%d ", j); } printf("\n"); for (i = 1; i <= row; i++) { printf("%d ", i); for (j = 1; j <= col; j++) { printf("%c ", board[i][j]); } printf("\n"); } }
4.布置雷
布置雷是随机布置的,因此这里的两个坐标利用生成随机数并缩小范围的方法给出,在初始化后的雷棋盘中布置雷还需要判断访问的位置是否有效,是否已经布置过,之后在布置雷。
这里需要布置定义的count个个数的雷,因此用循环。
void SetMine(char mine[ROWS][COLS], int row, int col) { int count = COUNT; while (count) { int x = rand() % row + 1; int y = rand() % col + 1; if (mine[x][y] == '0') { mine[x][y] = '1'; count--; } } }
5.排查雷
排查雷是最为重要的实现的操作,玩家给出所想要排查的坐标后,开始进行判断如果为0,则不是雷,打印出所展示的棋盘,并将该位置初始化的*改为其周围所有雷数的和,这里我们再写一个统计某位置周围雷个数总和的:
int GetMineCount(char mine[ROWS][COLS], int x, int y) { return (mine[x - 1][y] + mine[x - 1][y - 1] + mine[x][y - 1] + mine[x + 1][y - 1] + mine[x + 1][y] + mine[x + 1][y + 1] + mine[x][y + 1] + mine[x - 1][y + 1] - 8 * '0'); }
得到周围雷数总和,返回并改变为给玩家所展示的棋盘上,若是1,即直接遇到雷,游戏结束。在这里我们同样需要对位置的访问进行判断,其次便是游戏胜利的判断,因为每排查一次不是雷的位置,我们又会给一个win为0的整形变量加一,如果当排查的数小于棋盘总数减去雷的个数(不是雷的个数),那么就没有排查完,若等于则取得胜利。
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 >= 1 && x <= row && y >= 1 && y <= col) { if (show[x][y] == '*') { if (mine[x][y] == '1') { printf("很遗憾,你被炸死\n"); DisplayBoard(mine, 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); } }
在这里还需要注意的是我们在计算返回的雷的个数是整形,再将这个数变回字符型赋值给展示的期盼的该位置的元素使,通过对加减字符实现,字符减字符就是对应的整形,字符加数字就是对应的字符。
最后就是整个实现流程: