目录
- 1.扫雷游戏的分析和设计
- 1.1.扫雷游戏的功能说明
- 1.2.游戏的分析与设计
- 1.2.1 数据结构的分析
- 1.2.2 文件结构设计
- 2.扫雷游戏的代码实现
1.扫雷游戏的分析和设计
1.1.扫雷游戏的功能说明
- 使用控制台实现经典的扫雷游戏
- 游戏可以通过菜单实现继续玩游戏或者退出游戏
- 扫雷的棋盘是9*9的格子
- 默认随机排布10个雷
- 排查雷
- 如果位置不是雷,则显示周围有几个雷
- 如果是雷,则炸死游戏结束
- 把除10个雷之外的所有雷都找出来,排雷成功,游戏结束
游戏界面
1.2.游戏的分析与设计
1.2.1 数据结构的分析
扫雷的过程中,布置的雷和排出的雷都需要被存储,因为如果将两种都放在一起,就分别不出这个位置是雷的位置还是周围8个格子的雷的总数。
因为我们需要在99的棋盘上布置雷的信息和排查雷,首先想到的是创建一个99的数组来实现棋盘。
那如果这个位置布置雷,就存放1,没有布置雷就存放0。
当这个位置不是雷的时候,就需要统计周围8个位置的和,然后存放到当前位置。
那如果在计算边角时进行计算,就会发生数组越界的问题,为了解决这个问题,我们可以再在周围加一圈构成11*11的棋盘,这样就不会发生数组越界了。
解决了这个问题,就可以关注两个数组的问题了,因为我们的展示界面全是由 *构成的,而排查雷需要使用数字来表示,那我们可以使用数字字符来表示数值,最后将字符转化为数字就行了
1.2.2 文件结构设计
这里我们设置3个文件
1.test.c 文件中写游戏的逻辑测试
2.game.c 文件中写游戏的函数实现
3.game.h 文件中写游戏需要的数据类型和游戏声明
2.扫雷游戏的代码实现
第一步:菜单设置
test.c
void menu(void) {printf("******************\n");printf("******1.play******\n");printf("******0.exit******\n");printf("******************\n");int main() {int input = 0;//srand((unsigned int)time(NULL));//使用时间种子do {menu();printf("请选择:>");scanf("%d", &input);if (input == 1) {//printf("ready\n");game();}else if(input == 0) {printf("end\n");}else {printf("输入错误,重新输入\n");}} while (input);return 0;
}
}
这样就可输出菜单,选择1的话就可以开始游戏,选择0退出游戏,选择错误重新选择
第二步:游戏函数
test.c
void game(void) {//设置棋盘的格数,,11*11的棋盘不会出现越界问题char mine[ROWS][COLS];//11char show[ROWS][COLS];//11//初始化棋盘InitBoard(mine, ROWS, COLS,'0');InitBoard(show, ROWS, COLS,'*');}
game.h
#include<stdio.h>#define COL 9
#define ROW 9#define ROWS ROW+2
#define COLS COL+2//初始化棋盘函数
void InitBoard(char borad[ROWS][COLS], int rows, int cols,char type);
game.c
#include"game.h"
void InitBoard(char borad[ROWS][COLS], int rows, int cols,char type) {for (int i = 0; i < rows; i++) {for (int j = 0; j < cols; j++) {borad[i][j] = type;}}
}
这个函数的作用是创建数组,初始化棋盘,分别将数据类型和函数实现写在头文件中
第三步:打印棋盘
test.c
void game(void) {//设置棋盘的格数,,11*11的棋盘不会出现越界问题char mine[ROWS][COLS];//11char show[ROWS][COLS];//11//初始化棋盘InitBoard(mine, ROWS, COLS,'0');InitBoard(show, ROWS, COLS,'*');//打印棋盘Printborad(show, ROW, COL);Printborad(mine, ROW, COL);
}
game.h
#define COL 9
#define ROW 9#define ROWS ROW+2
#define COLS COL+2
//初始化棋盘函数
void InitBoard(char borad[ROWS][COLS], int rows, int cols,char type);
//打印棋盘函数
void Printborad(char borad[ROW][COL], int row,int col);
game.c
void Printborad(char borad[ROW][COL],int row,int col) {for (int i = 0; i <= row; i++) {printf("%d ", i);}printf("\n");for (int i = 1; i <= row; i++) {printf("%d ", i);for (int j = 1; j <= col; j++) {printf("%c ",borad[i][j]);}printf("\n");}
}
这个函数用以打印棋盘,可以看出棋盘的规划是否正确,当然我们只用打印show棋盘,不用打印mine棋盘,因为mine棋盘可以看到的全是0,这里为了不多写一个函数用来分别打印’*‘和’0’,所有我们再传一个一个参数type,告诉Printboard函数应该打印什么字符。
第四步:布置雷
test.c
void game(void) {//设置棋盘的格数,,11*11的棋盘不会出现越界问题char mine[ROWS][COLS];//11char show[ROWS][COLS];//11//初始化棋盘InitBoard(mine, ROWS, COLS,'0');InitBoard(show, ROWS, COLS,'*');//打印棋盘Printborad(show, ROW, COL); //Printborad(mine, ROW, COL);//布置雷SetMine(mine, ROW, COL);Printborad(mine, ROW, COL);//查看是否将雷布置好了
}
int main() {int input = 0;srand((unsigned int)time(NULL));//使用时间种子do {menu();printf("请选择:>");scanf("%d", &input);if (input == 1) {//printf("ready\n");game();}else if(input == 0) {printf("end\n");}else {printf("输入错误,重新输入\n");}} while (input);return 0;
}
game.h
#include<time.h>//使用时间种子
#include<stdlib.h>//使用随机数#define COUNT 10//10个雷//布置雷函数
void SetMine(char borad[ROW][COL], int row, int col);
game.c
void SetMine(char borad[ROW][COL], int row, int col) {//产生随机数int count = COUNT;while (count) {int x = rand() % row + 1;int y = rand() % col + 1;if (borad[x][y] == '0') {borad[x][y] = '1';count--;}}}
这里使用随机数设置雷的位置坐标,需要包含头文件#include<time.h>和
#include<stdlib.h>,使用语句srand((unsigned int)time(NULL));确定时间种子,这样就可以将雷布置进去了,可以使用Printborad(mine, ROW, COL);打印棋盘看看雷布置的正确与否。
第五步:排查雷
test.c
void game(void) {//设置棋盘的格数,,11*11的棋盘不会出现越界问题char mine[ROWS][COLS];//11char show[ROWS][COLS];//11//初始化棋盘InitBoard(mine, ROWS, COLS,'0');InitBoard(show, ROWS, COLS,'*');//打印棋盘Printborad(show, ROW, COL); //Printborad(mine, ROW, COL);//布置雷SetMine(mine, ROW, COL);Printborad(mine, ROW, COL);//查看是否将雷布置好了//排查雷FindMine(mine, show, ROW, COL);}
game.h
void FindMine(char mine[ROW][COL], char show[ROW][COL], int row, int col);
game.c
int GetMineCount(char mine[ROWS][COLS], int x, int y) {return (mine[x - 1][y] + mine[x - 1][y - 1] +mine[x-1][y+1] + mine[x][y - 1] + mine[x + 1][y - 1] + mine[x + 1][y] + mine[x][y + 1] + mine[x + 1][y + 1] - 8 * '0');
}void FindMine(char mine[ROW][COL], char show[ROW][COL], int row, int col) {int x = 0;int y = 0;int win = 0;while (win < row * col- COUNT) {printf("输入要查看的坐标:>");scanf("%d %d", &x, &y);if (x >= 1 && x <= row && y >= 1 && y <= col) {if (mine[x][y] == '1') {printf("很遗憾,你被炸死了\n");Printborad(show, ROW, COL);break;}else {//说明此处不是雷,则统计周围8个雷int count = GetMineCount(mine, x, y);show[x][y] = count + '0';Printborad(show, ROW, COL);win++;}}else {printf("坐标非法,重新输入\n");}}if (win == row * col - COUNT) {printf("恭喜,排雷成功\n");Printborad(mine, ROW, COL);}
}
使用FindMine函数排查雷,先输入要查看的坐标,如果坐标符合规定,则看这个坐标是否是雷,如果不是则计算周围8个位置的和并输出在棋盘上,当排查完71个没有雷的位置后,游戏成功。如果该位置非法,则重新输入。
以上涉及到一个重要的知识点,那就是:如何将数字字符转化为数字
可以直接使用数字字符减去字符0,比如:
‘0’ - ‘0’ = 0
‘1’ - ‘0’ = 1
‘55’ - ‘0’ = 55
这是因为字符之间的减法是减的ASCII码值,所以ASCII值相减就可以得到数字。
完整代码:
game.h
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<time.h>//使用时间种子
#include<stdlib.h>//使用随机数#define COUNT 10//10个雷#define COL 9
#define ROW 9#define ROWS ROW+2
#define COLS COL+2
//初始化棋盘函数
void InitBoard(char borad[ROWS][COLS], int rows, int cols,char type);
//打印棋盘函数
void Printborad(char borad[ROW][COL], int row,int col);
//布置雷函数
void SetMine(char borad[ROW][COL], int row, int col);
//排查雷
void FindMine(char mine[ROW][COL], char show[ROW][COL], int row, int col);
game.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
void InitBoard(char borad[ROWS][COLS], int rows, int cols,char type) {for (int i = 0; i < rows; i++) {for (int j = 0; j < cols; j++) {borad[i][j] = type;}}
}void Printborad(char borad[ROW][COL],int row,int col) {for (int i = 0; i <= row; i++) {printf("%d ", i);}printf("\n");for (int i = 1; i <= row; i++) {printf("%d ", i);for (int j = 1; j <= col; j++) {printf("%c ",borad[i][j]);}printf("\n");}
}void SetMine(char borad[ROW][COL], int row, int col) {//产生随机数int count = COUNT;while (count) {int x = rand() % row + 1;int y = rand() % col + 1;if (borad[x][y] == '0') {borad[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-1][y+1] + mine[x][y - 1] + mine[x + 1][y - 1] + mine[x + 1][y] + mine[x][y + 1] + mine[x + 1][y + 1] - 8 * '0');
}void FindMine(char mine[ROW][COL], char show[ROW][COL], int row, int col) {int x = 0;int y = 0;int win = 0;while (win < row * col- COUNT) {printf("输入要查看的坐标:>");scanf("%d %d", &x, &y);if (x >= 1 && x <= row && y >= 1 && y <= col) {if (mine[x][y] == '1') {printf("很遗憾,你被炸死了\n");Printborad(show, ROW, COL);break;}else {//说明此处不是雷,则统计周围8个雷int count = GetMineCount(mine, x, y);show[x][y] = count + '0';Printborad(show, ROW, COL);win++;}}else {printf("坐标非法,重新输入\n");}}if (win == row * col - COUNT) {printf("恭喜,排雷成功\n");Printborad(mine, ROW, COL);}
}
test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
void menu(void) {printf("******************\n");printf("******1.play******\n");printf("******0.exit******\n");printf("******************\n");
}void game(void) {//设置棋盘的格数,,11*11的棋盘不会出现越界问题char mine[ROWS][COLS];//11char show[ROWS][COLS];//11//初始化棋盘InitBoard(mine, ROWS, COLS,'0');InitBoard(show, ROWS, COLS,'*');//打印棋盘Printborad(show, ROW, COL); //Printborad(mine, ROW, COL);//布置雷SetMine(mine, ROW, COL);Printborad(mine, ROW, COL);//查看是否将雷布置好了//排查雷FindMine(mine, show, ROW, COL);}
int main() {int input = 0;srand((unsigned int)time(NULL));//使用时间种子do {menu();printf("请选择:>");scanf("%d", &input);if (input == 1) {//printf("ready\n");game();}else if(input == 0) {printf("end\n");}else {printf("输入错误,重新输入\n");}} while (input);return 0;
}
感谢观看!