目录
一、扫雷游戏分析和设计
1.1 功能说明
-
使用控制台实现经典的扫雷游戏
-
游戏可以通过菜单实现继续玩或者退出游戏
-
扫雷棋盘9*9
-
默认随机布置10个雷
-
可以排查雷:如果这个位置不是雷,就显示周围有几个雷; 如果这个位置是雷,就炸死游戏结束; 把10个雷之外所有非雷位置找出来,排雷成功,游戏结束
1.2 游戏分析和设计
1.2.1 数据结构的分析
游戏过程中,布置的雷和排查的信息都需要存储。
-
因为游戏棋盘为9*9,首先可以想到需要一个9*9的棋盘来存放信息。某个位置上有雷就存放1,没有雷就存放0。
-
在排查边界上坐标时,访问周围一圈8个位置,就会出现有越界访问。为了防止越界,在设计时,将9*9的数组扩大一圈,外层一圈不布置雷,这样就解决了越界的问题。所以此时,将存放数据的数组创建成11*11的数组。
-
排查某个坐标以后,需要将雷的信息记录下来,若将雷的信息存储在布置好雷的数组中,会导致布置雷的信息与排查后的信息混淆。因此,我们需要一个新的棋盘用来存储排查出的雷的信息。
-
设置两个棋盘,第一个棋盘(对应数组mine)存放布置好的雷的信息;第二个棋盘(对应数组show),存放排查出的雷的信息。
-
为了确保信息对游戏参与者保密,show数组开始时初始化为字符 '*',mine数组开始初始化为字符 '0',对布置雷的位置改成字符 '1'。(可以使用同一套函数处理)
1.2.2 文件结构分析
test.c //⽂件中写游戏的测试逻辑
game.c //⽂件中写游戏中函数的实现等
game.h //⽂件中写游戏需要的数据类型和函数声明等
二、扫雷游戏的代码实现
- game.h
#pragma once #include <stdio.h> #include <stdlib.h> #include <time.h> #define EASY_COUNT 10 #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); //打印棋盘 void DisplayBoard(char board[ROWS][COLS], int row, int col); //布置雷 void SetMine(char board[ROWS][COLS], int row, int col); //排查雷 void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
- game.c
#include "game.h" void InitBoard(char board[ROWS][COLS], int rows, int cols, char set) { int i = 0; for (i = 0; i < rows; i++) { int j = 0; for (j = 0; j < cols; j++) { board[i][j] = set; } } } void DisplayBoard(char board[ROWS][COLS], int row, int col) { int i = 0; printf("--------扫雷游戏-------\n"); for (i = 0; i <= col; i++) { printf("%d ", i); } printf("\n"); for (i = 1; i <= row; i++) { printf("%d ", i); int j = 0; for (j = 1; j <= col; j++) { printf("%c ", board[i][j]); } printf("\n"); } } void SetMine(char board[ROWS][COLS], int row, int col) { //布置10个雷 //⽣成随机的坐标,布置雷 int count = EASY_COUNT; while (count) { int x = rand() % row + 1; int y = rand() % col + 1; if (board[x][y] == '0') { board[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 (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"); } } if (win == row * col - EASY_COUNT) { printf("恭喜你,排雷成功\n"); DisplayBoard(mine, ROW, COL); } }
- test.c
#include "game.h" void menu() { printf("***********************\n"); printf("***** 1. play *****\n"); printf("***** 0. exit *****\n"); printf("***********************\n"); } void game() { char mine[ROWS][COLS];//存放布置好的雷 char show[ROWS][COLS];//存放排查出的雷的信息 //初始化棋盘 //1. mine数组最开始是全'0' //2. show数组最开始是全'*' InitBoard(mine, ROWS, COLS, '0'); InitBoard(show, ROWS, COLS, '*'); //打印棋盘 //DisplayBoard(mine, ROW, COL); DisplayBoard(show, ROW, COL); //1. 布置雷 SetMine(mine, ROW, COL); //DisplayBoard(mine, ROW, COL); //2. 排查雷 FindMine(mine, show, ROW, COL); } int main() { int input = 0; srand((unsigned int)time(NULL)); 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; }
三、排雷游戏的扩展
• 是否可以选择游戏难度
◦ 简单 9 * 9 棋盘,10个雷
◦ 中等 16 * 16棋盘,40个雷
◦ 困难 30 * 16棋盘,99个雷
• 如果排查位置不是雷,周围也没有雷,可以展开周围的⼀⽚
• 是否可以标记雷
• 是否可以加上排雷的时间显⽰