- 分析
- 玩法
扫雷就是要把所有非地雷的格子揭开即胜利;踩到地雷格子就算失败。
游戏主区域由很多个方格组成。使用鼠标左键随机点击一个方格,方格即被打开并显示出方格中的数字;方格中数字则表示其周围的8个方格隐藏了几颗雷;如果点开的格子为空白格,即其周围有0颗雷,则其周围格子自动打开;如果其周围还有空白格,则会引发连锁反应;在你认为有雷的格子上,点击右键即可标记雷;如果一个已打开格子周围所有的雷已经正确标出,则可以在此格上同时点击鼠标左右键以打开其周围剩余的无雷格。
- 玩法
- 思路
- 注意事项
我们使用控制台实现扫雷时,就不能使用鼠标点击,所以通过输入坐标以实现点击操作,右键标记暂不实现 - 游戏流程
- 选择菜单打印,人机交互
- 开始游戏
- 地图和雷阵初始化
- 地图初始化为 “*”
- 雷阵初始化为“0”
- 坐标随机数布雷为 “x”
- 打印地图
- 玩家输入坐标点击方块(while循环)
- 判断输入坐标越界,如果越界重新输入
- 判断输入坐标是否踩雷,如果踩雷游戏结束
- 判断剩余雷数是否为开始布置雷数,如果相等则游戏结束游戏成功
- 每输入一次更新地图
- 点击一个方格,方格即被打开并显示出方格中的数字,数字表示该格子四周雷数
- 如果点开的格子为空白格,即其周围有0颗雷,则其周围格子自动打开;如果其周围还有空白格,则会引发连锁反应
- 更新地图后显示地图
- 注意事项
- 实现
- 宏定义
后面列数和行数都会加2,将地图设置围墙,防止越界.避免越界检测。#define ROW 10 //行 #define COL 10 //列 #define MINE_NUMBER 10 //列数
- 菜单
void Menu() { printf("--------------\n"); printf(" 1. 开始游戏\n"); printf(" 0. 退出游戏\n"); printf("--------------\n"); int choice; scanf("%d", &choice); if (choice == 1) { GameStart(); } }
- 开始游戏
void GameStart() { char map[ROW + 2][COL + 2]; char mineMap[ROW + 2][COL + 2]; // 1.地图初始化 mapInit(map, mineMap); // 2.打印地图 displayMap(map); // 3.玩家点击地图 clickBlock(map, mineMap); }
- 地图初始化
//初始化地图 void mapInit(char map[ROW + 2][COL + 2], char mineMap[ROW + 2][COL + 2]) { for (int row = 0; row < ROW + 2; row++) { for (int col = 0; col < COL + 2; col++) { map[row][col] = '*'; } } for (int row = 0; row < ROW + 2; row++) { for (int col = 0; col < COL + 2; col++) { mineMap[row][col] = '0'; } } srand((unsigned int)time(0)); //随机布雷 int count = MINE_NUMBER; while (count > 0) { int row = rand() % 10 + 1; int col = rand() % 10 + 1; if (mineMap[row][col] == 'x') { continue; } mineMap[row][col] = 'x'; count--; } }
- 打印地图
//打印地图 void displayMap(char map[ROW + 2][COL + 2]) { printf(" "); for (int i = 1; i < COL + 1; i++) { printf("%d ", i); } printf("\n"); for (int i = 1; i < COL; i++) { printf("---"); } printf("\n"); for (int row = 1; row < ROW + 1; row++) { printf("%02d ", row); for (int col = 1; col < COL + 1; col++) { printf("%c ", map[row][col]); } printf("\n"); } printf("\n"); }
- 玩家点击方块
//点击方块 void clickBlock(char map[ROW + 2][COL + 2], char mineMap[ROW + 2][COL + 2]) { while (1) { int row, col; printf("请输入坐标\n"); scanf("%d %d", &row, &col); if (row < 1 || row > ROW || col < 1 || col > COL) { printf("输入错误!,请重新输入\n"); continue; } if (mineMap[row][col] == 'x') { printf("游戏结束,踩到雷了!\n"); displayMap(mineMap); break; } if (reminderMine(map) == MINE_NUMBER) { printf("通关了!\n"); displayMap(mineMap); break; } updateMap(map, mineMap, row, col); displayMap(map); } }
- 剩余雷数检查
// 剩余地雷 int reminderMine(char map[ROW + 2][COL + 2])//判断剩余未知区域的个数,个数为雷数时玩家赢 { int count = 0; for (int row = 1; row < ROW + 1; row++) { for (int col = 1; col < COL + 1; col++) { if (map[row][col] == '*') { count++; } } } return count; }
- 地图更新
// 更新地图 void updateMap(char map[ROW + 2][COL + 2], char mineMap[ROW + 2][COL + 2], int row, int col) { if (checkAround(mineMap, row, col) != 0) { map[row][col] = checkAround(mineMap, row, col) + '0'; } else { openMore(map, mineMap, row, col); } }
- 空白格周围展开并连锁反应
八个方向检测格子中是否为“0”,如果为零继续延伸检测,直到有雷该方向停止检测,递归检测.不为零设置被打开格子附近雷数void openMore(char map[ROW + 2][COL + 2], char mineMap[ROW + 2][COL + 2], int row, int col) { if (map[row][col] == '*' && mineMap[row][col] == '0') { map[row][col] = checkAround(mineMap, row, col) + '0'; } //上 if (mineMap[row - 1][col] == '0' && map[row - 1][col] == '*') { map[row - 1][col] = checkAround(mineMap, row - 1, col) + '0'; if (checkAround(mineMap, row - 1, col) == 0) { openMore(map, mineMap, row - 1, col); } } //下 if (mineMap[row + 1][col] == '0' && map[row + 1][col] == '*') { map[row + 1][col] = checkAround(mineMap, row + 1, col) + '0'; if (checkAround(mineMap, row + 1, col) == 0) { openMore(map, mineMap, row + 1, col); } } //左 if (mineMap[row][col - 1] == '0' && map[row][col - 1] == '*') { map[row][col - 1] = checkAround(mineMap, row, col - 1) + '0'; if (checkAround(mineMap, row, col - 1) == 0) { openMore(map, mineMap, row, col - 1); } } //右 if (mineMap[row][col + 1] == '0' && map[row][col + 1] == '*') { map[row][col + 1] = checkAround(mineMap, row, col + 1) + '0'; if (checkAround(mineMap, row, col + 1) == 0) { openMore(map, mineMap, row, col + 1); } } // 东北 if (mineMap[row - 1][col + 1] == '0' && map[row - 1][col + 1] == '*') { map[row - 1][col + 1] = checkAround(mineMap, row - 1, col + 1) + '0'; if (checkAround(mineMap, row - 1, col + 1) == 0) { openMore(map, mineMap, row - 1, col + 1); } } // 西北 if (mineMap[row - 1][col - 1] == '0' && map[row - 1][col - 1] == '*') { map[row - 1][col - 1] = checkAround(mineMap, row - 1, col - 1) + '0'; if (checkAround(mineMap, row - 1, col - 1) == 0) { openMore(map, mineMap, row - 1, col - 1); } } // 东南 if (mineMap[row + 1][col + 1] == '0' && map[row + 1][col + 1] == '*') { map[row + 1][col + 1] = checkAround(mineMap, row + 1, col + 1) + '0'; if (checkAround(mineMap, row - 1, col) == 0) { openMore(map, mineMap, row + 1, col + 1); } } // 西南 if (mineMap[row + 1][col - 1] == '0' && map[row + 1][col - 1] == '*') { map[row + 1][col - 1] = checkAround(mineMap, row + 1, col - 1) + '0'; if (checkAround(mineMap, row + 1, col - 1) == 0) { openMore(map, mineMap, row + 1, col - 1); } } }
- 四周环境检测 并返回周围雷数
// 检查周围环境 int checkAround(char mineMap[ROW + 2][COL + 2], int row, int col) { int count = 0; //上 if (mineMap[row - 1][col] == 'x') { count++; } //下 if (mineMap[row + 1][col] == 'x') { count++; } //左 if (mineMap[row][col - 1] == 'x') { count++; } //右 if (mineMap[row][col + 1] == 'x') { count++; } // 东北 if (mineMap[row - 1][col + 1] == 'x') { count++; } // 西北 if (mineMap[row - 1][col - 1] == 'x') { count++; } // 东南 if (mineMap[row + 1][col + 1] == 'x') { count++; } // 西南 if (mineMap[row + 1][col - 1] == 'x') { count++; } return count; }
- 宏定义
写在最后
最近推出了公众号 coding趣谈,一位在读学生的技术提升之路,为您提供一系列我在学习路上的笔记,经验,以及感悟。往与君共勉,共同进步! 欢迎大家来关注哦!