扫雷简单版介绍:
布置雷-10个
扫雷
输入坐标
是雷 --就炸死,游戏结束
不是雷 --告诉你这个坐标周围8个坐标上总共有几个雷。
直到把所有非雷的位置全部找出来,游戏结束,扫雷成功。
布局分析:
首先要我们要有一个9*9的棋盘,然后把雷的位置存储进去
但是这些的雷的存储需要存储空间,如何才能存储雷的信息呢?
数组 创建一个二维数组来存储这些雷的信息
接下来就是雷的布置了,如果用字符‘0’表示为非雷,用字符‘1’表示为雷。
当我们扫雷的时候,挑选了一个坐标不是雷,同时周围有两个雷,这个坐标就会显示‘2’。
问题来了,当我们扫到一个坐标周围有一个雷的时候就先显示‘1’,这与布置雷时显示‘1’的含义冲突。
为了避免这种冲突,我们创建两个二维数组,分别为mine[9][9]和show[9][9]。
mine数组:存储布置好雷的信息,非雷为字符‘0’,雷为字符‘1’ (挖坑,注:后面会把坑填上)
show数组:存储排查出雷达信息,未排查的用‘*’显示,排查出的则显示周围雷的个数
接下来又出现一个新问题,当我们在排查的时候,如果这个坐标不是雷那么就会访问周围八个坐标的雷数。
如果这个排查雷的坐标在边缘如下图(9,8)那么在访问过程中就会越界,而如果我们每一次排查边缘位置时就要判断周围八个坐标的合法性就会显的太过麻烦,所以最后的解决方案是把mine数组提升到11*11(注:上下各加一行,左右各加一列)
为了让show数组对应mine数组,所以show数组也要提升到11*11
代码实现:
本次分为三个部分game.h h和 test.c 和 game.c
test.c 主要实现扫雷主体,game.c主要实现扫雷中函数实现,game.h主要实现个函数声明
game.h代码实现:
#include<stdio.h> #include<stdlib.h> #include<time.h> #define ROW 9 //行数 #define COL 9 //列数 #define ROWS ROW+2 #define COLS COL+2 #define EASY_COUNT 10 //简单版 布置10个雷 //初始化 void init_board(char arr[ROWS][COLS], int rows, int cols, char set); //打印 void show_board(char arr[ROWS][COLS], int row, int col); //布置雷 void set_mine(char mine[ROWS][COLS],int row,int col); //排查雷 void find_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col); //获取雷的数量 int get_mine_count(char mine[ROWS][COLS], int x, int y);
test.c代码实现:
main函数实现:
首先要实现一个菜单界面,比如选择1:开始玩游戏、选择0:退出
创建一个input变量(目的:为了接收玩家输入信息),用do while语句循环,接着添加menu函数scanf函数接受input的值,switch语句进行选择。
srand((unsigned int)time(NULL))是为了实现随机数,会在game.c模块里面提及
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; }
menu函数实现(菜单):
void menu() { printf("**************************\n"); printf("******** 1.paly ********\n"); printf("******** 0.exit ********\n"); }
game函数实现:
首先创建mine和show数组
用init_board函数进行初始化
用set_mine函数布置雷
用show_board函数打印棋盘
用find_mine函数排查雷
这些函数会在game.c里面实现
void game() { //扫雷实现 //mine数组是用来存放布置好雷的信息 char mine[ROWS][COLS] = { 0 };//'0' //show数组是用来存放排查出的雷的信息的 char show[ROWS][COLS] = { 0 };//'*' //初始化棋盘 init_board(mine, ROWS, COLS,'0'); //mine[11][11]数组全部初始化为字符‘0’ init_board(show, ROWS, COLS,'*'); //show[11][11]数组全部初始化为字符‘1’ //布置雷 set_mine(mine, ROW,COL); //打印棋盘 show_board(show, ROW, COL); //排查雷 find_mine(mine, show, ROW, COL); }
game.c代码实现(主要功能):
init_board函数实现:
主要功能:初始化棋盘
传参:{ arr[11][11],行,列,初始化内容}
返回值: 无
void init_board(char arr[ROWS][COLS], int rows, int cols,char set) { int i = 0; int j = 0; for (i = 0; i < rows; i++) { for (j = 0; j < cols; j++) { arr[i][j] = set; } } }
show_board函数实现:
主要功能:打印棋盘
传参:{ arr[11][11] ,行,列,初始化内容}
(这里面传入的是ROW和COL,因为玩游戏时只用显示中间9*9的空间就行了)
返回值: 无
在打印棋盘的过程中,加入行和列数方便玩家出入坐标,效果如下
void show_board(char arr[ROWS][COLS], int row, int col) { int i = 0; int 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 ", arr[i][j]); } printf("\n"); } printf("---------扫雷---------\n"); }
set_mine 函数实现:
功能:布置雷
传参:{mine[11][11],行(9),列(9)}
首先声明一个变量count,并赋值为EASY_COUNT。
声明x、y表示坐标
接下来布置雷的坐标用rand库函数来实现
rand() % row + 1 表示生成的坐标在1~9 之间
同时还要判断随机产生的坐标是不是已经布置好雷,用if语句
rand()生成随机数的函数
然后要布置EASY_COUNT个雷,每次布置一个雷,EASY_COUNT就减去一个,所以用while循环来表示这种效果。
void set_mine(char mine[ROWS][COLS], int row, int col) { int count = EASY_COUNT; // EASY_COUNT = 9 在game.h中声明 int x = 0; int y = 0; while (count) { x = rand() % row + 1; y = rand() % col + 1; if (mine[x][y] == '0') { mine[x][y] = '1';//布置雷 count--; } } }
get_mine_count函数实现:
功能:获取雷达数量
传参:{mine[11][11],行(坐标),列(坐标)}
返回值: n(雷的个数)
首先声明一个整数n 记录雷的个数。
下面用for循环遍历九个坐标。
不知 大家有没有了解过下面两个式子
‘0’ - ‘0’ = 0
‘1’ - ‘0’ = 1
(‘0’的ASCII 码的值为 48,‘1’的ASCII 码的值为 49)
所以,只需要需要把九个坐标相加并减去九个‘0’,也就得到雷的个数。
而如果要用‘*’或者‘#’表示雷或非雷,就不能用这种情况,会变得麻烦。
这也是为啥在mine数组里面都是用字符‘0’表示非雷,用字符‘1’表示雷(填坑)
int get_mine_count(char mine[ROWS][COLS],int x,int y) { int n = 0; for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) { n += mine[x + i][y + j] - '0'; } } return n; }
search_mine函数实现:
功能:对坐标为非雷且周围没有雷的位置,进行连展
传参:{ mine[11][11] , show[11][11] , x(横坐标) , y(纵坐标)}
返回值:无
实现思路:先证明有个整数count记录该坐标周围雷的个数,接下来进行判断,如果该位置周围没有雷,则把该坐标在show中的内容改为‘空格’,反之则改为count + '0' 并返回结束该函数。
如果为‘空格’,这下一步进行for循环遍历周围八个坐标,声明连个整数a和b,分别记录 (x+i)的值和(y+j)的值。
接下来判断mine[a][b]中存储的是否为‘0’(非雷),如果是则进行递归调用 search_mine函数。
void search_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y) { if (show[x][y] != '*' ) { return ; } int count = get_mine_count(mine, x, y); if (count == 0) { show[x][y] = ' '; } else { show[x][y] = count + '0'; return; } for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) { int a = x + i; int b = y + j; if (mine[a][b] != '1') { search_mine(mine, show, a, b); } } } }
find_mine函数实现:
功能:扫雷游戏的主框架,对输入的坐标进行判断,同时判断输赢(排查雷)
传参:{ mine[11][11] , show[11][11] , 行,列 }
返回值:无
实现思路:
先声明三个整数 x, y , win。x和y用来记录玩家输入的坐标,win用来记录非雷的个数
玩家需要一直输入坐标直到扫到雷或者把非雷的位置找完,所用要用while循环来实现这一功能,循环的条件为(row*col- EASY_COUNT),循环内用if语句进行判断。
循环结束判断玩家是否满足赢的条件(行*列 - 雷的个数)= win。
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col) { int x = 0; int y = 0; int win = 0; //9*9-10 while (win<row*col- EASY_COUNT) { printf("请输入排查雷的坐标:>"); scanf("%d%d", &x, &y); if (x >= 1 && x <= row && y >= 1 && y <= col) { //坐标合法 //1.踩雷 if (mine[x][y] == '1') { printf("很遗憾,你被炸死了\n"); Displayboard(mine, row, col); break; } else //不是雷 { //计算x,y坐标周围有几个雷 int count = get_mine_count(mine, x, y); show[x][y] = count + '0'; Displayboard(show, row, col); win++; } } else { printf("输入坐标非法,请重新输入!\n"); } } if (win == row * col - EASY_COUNT) { printf("恭喜你!排雷成功"); Displayboard(mine, row, col); } }
代码整体呈现(可以跳过以上内容,直接复制代码测试):
game.h(头文件) #include<stdio.h> #include<stdlib.h> #include<time.h> #define ROW 9 #define COL 9 #define ROWS ROW+2 #define COLS COL+2 #define EASY_COUNT 10 //初始化 void init_board(char arr[ROWS][COLS], int rows, int cols, char set); //打印 void show_board(char arr[ROWS][COLS], int row, int col); //布置雷 void set_mine(char mine[ROWS][COLS],int row,int col); //连展 void search_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y); //排查雷 void find_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col); //获取周围雷的个数 int get_mine_count(char mine[ROWS][COLS], int x, int y); test.c #include"game.h" void menu() { printf("**************************\n"); printf("******** 1.paly ********\n"); printf("******** 0.exit ********\n"); } void game() { //扫雷实现 //mine数组是用来存放布置好雷的信息 char mine[ROWS][COLS] = { 0 };//'0' //show数组是用来存放排查出的雷的信息的 char show[ROWS][COLS] = { 0 };//'*' //初始化棋盘 init_board(mine, ROWS, COLS,'0'); init_board(show, ROWS, COLS,'*'); //打印棋盘 //show_board(mine,ROW,COL); //布置雷 set_mine(mine, ROW,COL); show_board(show, ROW, COL); //排查雷 find_mine(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; } game.c #include"game.h" void init_board(char arr[ROWS][COLS], int rows, int cols,char set) { int i = 0; int j = 0; for (i = 0; i < rows; i++) { for (j = 0; j < cols; j++) { arr[i][j] = set; } } } void show_board(char arr[ROWS][COLS], int row, int col) { int i = 0; int 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 ", arr[i][j]); } printf("\n"); } printf("---------扫雷---------\n"); } //布置雷 void set_mine(char mine[ROWS][COLS], int row, int col) { int count = EASY_COUNT; int x = 0; int y = 0; while (count) { x = rand() % row + 1; y = rand() % col + 1; if (mine[x][y] == '0') { mine[x][y] = '1';//布置雷 count--; } } } // int get_mine_count(char mine[ROWS][COLS],int x,int y) { int n = 0; for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) { n += mine[x + i][y + j] - '0'; } } return n; } void search_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y) { if (show[x][y] != '*' ) { return ; } int count = get_mine_count(mine, x, y); if (count == 0) { show[x][y] = ' '; } else { show[x][y] = count + '0'; return; } for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) { int a = x + i; int b = y + j; if (mine[a][b] != '1') { search_mine(mine, show, a, b); } } } } //排查雷 void find_mine(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"); show_board(mine, ROW, COL); break; } else { search_mine(mine, show, x, y); show_board(show, ROW, COL); win++; } } else { printf("坐标非法,重新输入\n"); break; } } if (win == row * col - EASY_COUNT) { printf("恭喜你排雷成功\n"); show_board(mine, ROW, COL); } }