学习了C语言,总想动手写点什么,扫雷就听不错,那么现在来实现扫雷
首先我们需要为扫雷游戏写个主函数,这样我们的代码才能跑起来,方便测试
我们在主函数中需要实现什么功能呢?
我们要先打印菜单,所以需要在主函数中使用menu函数,然后玩家选择是否玩游戏,这时候,我们需要用到switch语句,在语句中使用game函数,所以有了如下代码:
int main() { int input = 0; do { menu();//打印菜单 printf("请输入:>"); scanf("%d", &input); switch (input) { case 1://玩游戏 printf("玩游戏\n"); game(); break; case 0://退出 printf("退出\n"); break; default: printf("输入错误,请重新输入\n"); } } while (input);//判断是否循环 return 0; }
那么,按照先后顺序,我们现在要实现menu函数啦
menu函数非常简单,只需要用到printf,代码如下:
void menu() { printf("***************************************\n"); printf("*************** 1. play **************\n"); printf("*************** 0. exit **************\n"); printf("***************************************\n"); }
然后,重头戏来啦,我们要实现game函数了
现在,我们需要考虑一下,我们具体该怎么实现这个游戏啦。首先,我们实现行列分别为ROW、COL的扫雷棋盘,我们知道,当排除雷的时候,如果该位置没有雷,就显示周围雷的数量之和,所以我们需要应用行列分别为ROW+2,COL+2的二维数组,为了方便,我们定义ROWS为ROW+2,COLS为COL+2,并且,我们需要两个数组,一个用来存放放置雷的信息,另一个用来存放排除雷的信息,我们创建如下数组:
char mine[ROWS][COLS] = { 0 };//存放布置的雷的信息 char show[ROWS][COLS] = { 0 };//存放排除的雷的信息
初始化数组
所以现在,我们的需求是把两个数组分别初始化,讲show数组初始化为*,*更为神秘一点,mine数组内部是存放放置雷的信息的,所以我们用0表示没有雷,用1表示有雷,所以实现初始化数组的代码如下:
void InitBoard(char board[ROWS][COLS], int row, int col, char set) { int i = 0; int j = 0; for (i = 0; i < row; i++) { for (j = 0; j < col; j++) { board[i][j] = set; } } }
打印棋盘
初始化完成以后,我们需要打印一下棋盘,来看看我们初始化是否成功,并且,在游戏过程中,我们需要多次打印棋盘内容,因此,分装一个Display函数是有必要的,在打印棋盘的时候,我们最好顺便打印一下行号和列号
void DisplayBoard(char board[ROWS][COLS], int row, int col) { printf("-------扫雷游戏-------\n"); int i = 0; int j = 0; for (i = 0; i <= col; i++) { printf("%d ", i); } printf("\n"); for (i = 1; i <= row; i++) { printf("%d ", i); for (j = 1; j <= col; j++) { printf("%c ", board[i][j]); } printf("\n"); } printf("-------扫雷游戏-------\n"); }
按照顺序的话,我们现在应该实现设置雷这个项目了
那么我们应该怎么设置雷呢,显而易见,用随机数是最好的方式,这时候,我们就会用到rand和srand函数,srand函数是用来设置起点的,那么只需要使用一次,那我们把他放在main函数中是最合适的,所以main函数应该调整为
int main() { srand((unsigned int)time(NULL));//设置随机数起点 int input = 0; do { menu(); printf("请输入:>"); scanf("%d", &input); switch (input) { case 1: printf("玩游戏\n"); game(); break; case 0: printf("退出\n"); break; default: printf("输入错误,请重新输入\n"); } } while (input); return 0; }
设置雷函数代码如下:
void SetMine(char board[ROWS][COLS], int row, int col) { int x = 0; int y = 0; int count = EASY; while (count) { x = rand() % row + 1; y = rand() % col + 1; if (x > 0 && x < ROWS && y>0 && y < COLS) { if (board[x][y] == '0') { board[x][y] = '1'; count--; } } } }
那么现在,到了最激动人心的时刻啦,终于要开始排雷啦
排雷需要排很多次,所以我们要用到循环,在循环内实现排雷才行。这个逻辑也很好理解,在此就不过多赘述了,直接上代码
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col) { int x = 0; int y = 0; int count = 0; int win = 0; while (win < row * col - EASY) { printf("请输入要排查的坐标:>"); scanf("%d%d", &x, &y); if (x >= 1 && x <= row && y >= 1 && y <= col) { if (show[x][y] != '*') { printf("该坐标已经被排查过啦!\n"); } else { if (mine[x][y] == '1') { printf("很遗憾,被炸死了\n"); DisplayBoard(mine, ROW, COL); break; } else { win++; count = get_mine_count(mine, x, y); show[x][y] = count + '0'; DisplayBoard(show, ROW, COL); } } } else { printf("输入坐标错误,请重新输入\n"); } } if (win == row * col - EASY) { printf("恭喜你,你赢了\n"); DisplayBoard(mine, ROW, COL); } }
如果仔细阅读我的代码,就会发现,这段代码里有一个函数,还没有实现,但是通过他的名字应该能猜出这个函数是干嘛的。对,就是用来实现显示周围雷的个数的。
那么我们如何显示出周围有多少雷呢?记得前面我们用0表示没有放置雷,用1来表示已经放置雷了,那么我们把这8个位置的内容相加不就得到了雷的个数啦,但是注意,我们初始化和设置雷的时候,用的是字符0和字符1,所以相加后返回的整数是很大的,因为返回的是ASCLL码值,所以我们需要减去8*‘0’;代码实现如下:
int get_mine_count(char board[ROWS][COLS], int x, int y) { return board[x - 1][y - 1] + board[x][y - 1] + board[x + 1][y - 1] + board[x - 1][y] + board[x + 1][y] + board[x - 1][y + 1] + board[x][y + 1] + board[x + 1][y + 1] - 8 * '0'; }
到此为止,扫雷的基本版就算是完成啦。
最后,附一下完整版代码
https://gitee.com/gascsd/litter-game/tree/master/%E6%89%AB%E9%9B%B7%E5%B0%8F%E6%B8%B8%E6%88%8F%E5%9F%BA%E7%A1%80%E7%89%88