和我们之前的三子棋一样,扫雷的核心思想也是二维数组的利用
今天我们就来试着利用数组的知识来实现扫雷游戏
1.扫雷实现的逻辑
跟三子棋一样,我们首先创建三个文件:game.h , game.c , test.c
- 1.用define定义常量,定义数组的行和列,这样改变数组行列不需要整个修改代码,只需要改变define后面定义常量的值;
- 2.需要一个菜单来供我们选择进入游戏还是退出游戏,menu函数;
- 3.玩游戏肯定不止玩一局,所以需要设置循环do...while;
- 4.需要俩个数组,一个用来设置雷(mine),存放雷的信息;一个用来让玩家排查雷(show),存放玩家输入的坐标信息;
- 5.需要初始化俩个数组,我们把要埋雷的数组初始化为’0‘,要排雷的数组初始化为’*‘;
- 6.需要打印棋盘让玩家来排雷;
- 7.需要设置雷和排雷函数;
2.游戏的实现
2.1打印菜单
定义一个menu()函数来打印菜单
void menu() { printf("******************\n"); printf("***** 1.play *****\n"); printf("***** 0.exit *****\n"); printf("******************\n"); }
2.2玩家选择
我们在main()中采取do-while循环来实现重复游戏,用switch()来获取玩家的选择
int main() { int input = 0; do { menu(); printf("请选择>"); scanf("%d", &input); switch (input) { case 1: game(); break; case 0: printf("退出游戏\n"); break; default: printf("选择错误,重新选择\n"); break; } } while (input); return 0; }
目前我们的实现效果是这样的
2.3游戏实现扫雷的逻辑
1.布置雷的逻辑
假设我们实现一个9*9的棋盘,上面布置十个雷
这样我们就需要一个9*9的数组来存放雷
假设这是我们的棋盘
最开始每个位置都放0;0表示非雷
当我们布置雷的时候,把雷放成1
2.排雷的第一种情况
假设我们在排这个绿色坐标的时候,它不是雷,这时候我们需要统计它周围红圈中8个坐标的雷的个数;像上面这种情况,我们需要显示1;但是这个1会与我们表示雷的1冲突,为了解决这个问题,我们再单独给他一个数组,全部放成 ‘ * ’ ;
这个时候,我们在 ‘ * ’ 棋盘中,对应的位置显示‘1’表示这个坐标周围的八个坐标里有一个雷;我们给玩家展示的时候,展示第2个数组
- 第一个棋盘存雷和非雷的信息
- 第二个棋盘存玩家排查出来的雷的信息
3.排雷的第二种情况
假设我们要排查边缘的这个坐标,这个是超出了我们9*9的数组范围
这个时候为了防止越界,我们再把这个数组扩充,即在设置存雷的数组的时候,范围设置成11*11
像这样
这个时候,就不存在越界行为了
为了便于计算,我们的展示棋盘同样扩大到11*11(严丝合缝);
2.4棋盘的初始化
我们定一个InitBoard()函数来初始化棋盘
定义两个11*11的数组
这个数组用来放布置好的雷的信息(11*11)
这个数组用来放排查出的雷的信息(11*11)
为了保证两个数组严格的统一,包括元素类型也要统一,我们定义为char数组
game.h
#define ROW 9 #define COL 9 #define ROWS ROW+2 #define COLS COL+2 //初始化棋盘 void InitBoard(char board[ROWS][COLS], int rows, int cols, char set);
game.c
//初始化棋盘 void InitBoard(char board[ROWS][COLS], int rows, int cols, char set) { int i = 0, j = 0; for (i = 0; i < rows; i++) { for (j = 0; j < cols; j++) { board [i][j] = set; } } }
test.c
void game() { char mine[ROWS][COLS] = { 0 }; char show[ROWS][COLS] = { 0 }; InitBoard(mine, ROWS, COLS, '0'); InitBoard(show, ROWS, COLS, '*'); }
2.5打印棋盘
我们定义一个DisplayBoard()函数来打印棋盘
在打印的时候,我们可以打印出坐标
1.代码
game.c
//打印棋盘 void DisplayBoard(char board[ROWS][COLS], int row, int col) { int i = 0, 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"); } }
test.c
void game() { char mine[ROWS][COLS] = { 0 }; char show[ROWS][COLS] = { 0 }; InitBoard(mine, ROWS, COLS, '0'); InitBoard(show, ROWS, COLS, '*'); DisplayBoard(mine, ROW, COL); DisplayBoard(show, ROW, COL); }
2.打印效果
2.6布置雷
我们定义一个setMine()函数来布置雷
假设我要布置十个雷
- 随机布置
- 用1表示雷
这里我们又要用到我们的随机数函数rand(),使用rand函数必然需要在main()函数中调用srand();
//布置雷 void setMine(char mine[ROWS][COLS], int row, int col) { int count = EASY_COUNT; while (count) { int x = rand() % row + 1; int y = rand() % col + 1; if (mine[x][y] == '0') { mine[x][y] = '1'; count--; } } }
2.7排雷
排查雷的逻辑是:
- 如果这个位置不是雷,就计算这个位置周围八个坐标有几个雷,并显示雷的个数
- 如果这个位置是雷,就炸死了,游戏结束
- 如果把不是雷的位置都找出来了,那么游戏也结束,玩家胜利
在扫雷的过程中,我们还需要计算周围雷的个数
定义一个GetMineCount()函数来统计周围雷的个数
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'); }
定义一个FindMine()函数来排查雷
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(show, 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); } }
2.8game()函数
void game() { char mine[ROWS][COLS] = { 0 }; char show[ROWS][COLS] = { 0 }; InitBoard(mine, ROWS, COLS, '0'); InitBoard(show, ROWS, COLS, '*'); //DisplayBoard(mine, ROW, COL); DisplayBoard(show, ROW, COL); //布置雷 setMine(mine, ROW, COL); //排查雷 FindMine(mine, show, ROW, COL); }
3.源代码
game.h
#define _CRT_SECURE_NO_WARNINGS 1 #pragma once #include<stdio.h> #include<time.h> #include<stdlib.h> #define ROW 9 #define COL 9 #define ROWS ROW+2 #define COLS COL+2 #define EASY_COUNT 10//十个雷 //初始化棋盘 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); //计算扫出来的雷个数 int GetMineCount(char mine[ROWS][COLS], int x, int y);
game.c
#define _CRT_SECURE_NO_WARNINGS 1 #include"game.h" //初始化棋盘 void InitBoard(char board[ROWS][COLS], int rows, int cols, char set) { int i = 0, j = 0; for (i = 0; i < rows; i++) { for (j = 0; j < cols; j++) { board [i][j] = set; } } } //打印棋盘 void DisplayBoard(char board[ROWS][COLS], int row, int col) { int i = 0, j = 0; printf("--------扫雷--------\n"); 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"); } //布置雷 void setMine(char mine[ROWS][COLS], int row, int col) { int count = EASY_COUNT; while (count) { int x = rand() % row + 1; int y = rand() % col + 1; if (mine[x][y] == '0') { mine[x][y] = '1'; count--; } } } //扫雷 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'); } 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(show, 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); } }
test.c
#define _CRT_SECURE_NO_WARNINGS 1 #include"game.h" void menu() { printf("******************\n"); printf("***** 1.play *****\n"); printf("***** 0.exit *****\n"); printf("******************\n"); } void game() { char mine[ROWS][COLS] = { 0 }; char show[ROWS][COLS] = { 0 }; InitBoard(mine, ROWS, COLS, '0'); InitBoard(show, ROWS, COLS, '*'); //DisplayBoard(mine, ROW, COL); DisplayBoard(show, ROW, COL); //布置雷 setMine(mine, ROW, COL); //排查雷 FindMine(mine, show, ROW, COL); } int main() { srand((unsigned int)time(NULL)); int input = 0; do { menu(); printf("请选择>"); scanf("%d", &input); switch (input) { case 1: game(); break; case 0: printf("退出游戏\n"); break; default: printf("选择错误,重新选择\n"); break; } } while (input); return 0; }
4.总结
这就是扫雷的全部过程了,希望对各位有帮助4
今天我们练习写出了扫雷游戏,这是一个不错的进步,对数组有了更多的理解
小杜跟各位小伙伴在一起成长,祝我们都能成为大牛!
//小杜的成长之路