3.详细步骤实现
1.创建数组
采取分模块写法:
1.test.c的主源文件中写主体步骤
2.game.h 中申明扫雷游戏模块相关的函数申明,自定义等
3.game.c 中实现函数定义
test.c 中代码如下:
void game()//游戏函数实现 { char mine[ROWS][COLS] = { 0 };//存放雷的数组 char show_mine[ROWS][COLS] = { 0 };//存放展示扫雷的素组 } void menu() //菜单函数实现 { printf("****************\n"); printf("**** 1.play ****\n"); printf("**** 0.exit ****\n"); printf("****************\n"); } int main() { int input = 0; srand((unsigned)time(NULL)); do { menu(); //菜单 printf("请选择: \n"); scanf("%d", &input); switch (input) { case 1: game(); break; case 0: printf("即将退出游戏\n"); break; default: printf("选择错误,请重新选择\n"); break; } } while (input);//玩家输入的值来进行循环的判断,可达到循环玩游戏的效果 return 0; }
game.h 中代码如下:
#define ROW 9 //操作的行 #define COL 9 //操作的列 #define COLS COL+2 //防止数组越界 #define ROWS ROW+2 //防止素组越界
由于我们看到的扫雷的棋盘是一个9*9的棋盘,因此我们操作的棋盘应该就是这个大小,但是当判断内容时,我们是以一个数字为中心的九宫格,那么,在边界上的数字(如上图所示)的九宫格就会超过需要的棋盘大小,为了防止越界,我们将棋盘的行列均扩大,上下左右均需要扩大,因此行列扩大两行。
2.初始化素组
test.c 中代码如下:
void game() { char mine[ROWS][COLS] = { 0 };//存放雷的数组 char show_mine[ROWS][COLS] = { 0 };//展示扫雷的素组--给玩家观察的数组 Initboard(mine, ROWS, COLS, '0'); //初始化为字符‘0’ Initboard(show_mine, ROWS, COLS, '*');//初始化为字符‘*’ }
game.h 中代码如下:
//初始化数组中的内容 void Initboard(char board[ROWS][COLS], int rows, int cols ,char sz);
game.c 中代码如下:
game.c 中实现函数时所涉及的头文件我们放在game.h中,可以防止重复引用
#define _CRT_SECURE_NO_WARNINGS 1 #include"game.h"//用了game.h 中 ROWS COLS 等自定义的变量须应用头文件 void Initboard(char board[ROWS][COLS], int rows, int cols,char sz) { //**传入 sz 这个字符参数 方便我们一个函数可以解决 雷的棋盘和展示棋盘的初始化** int i = 0; int j = 0; for (i = 0; i < rows; i++) { for (j = 0; j < cols; j++) { board[i][j] = sz; } } }
3.展示(打印)数组
test.c 中代码如下:
void game() { char mine[ROWS][COLS] = { 0 };//存放雷的数组 char show_mine[ROWS][COLS] = { 0 };//展示扫雷的数组--给玩家观察的数组 Initboard(mine, ROWS, COLS, '0'); //初始化为字符‘0’ Initboard(show_mine, ROWS, COLS, '*');//初始化为字符‘*’ print_board(show_mine, ROW, COL);//展示扫雷的数组 //注意的是,我们操作的是展示的9*9的棋盘,因此我们传入的棋盘行列大小也是9*9,即ROW,COL }
game.h 中代码如下:
#include<stdio.h> //打印初始化后的内容 void print_board(char board[ROWS][COLS], int row, int col); 我们传入的是show_mine 这个数组,因此这里的【ROWS】【COLS】也应当是和 show_mine创建的时候保持一直,但我们展示的却是9*9的棋盘,因此传入的行列是 row和col
game.c 中代码如下:
void print_board(char board[ROWS][COLS], int row, int col) { printf("--------扫雷-------\n");//上分割线 int i = 0; int j = 0; //打印横坐标 for (i = 0; i <= row; i++) { if (i == 0) printf(" "); else 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");下分割线 }
效果展示:
4. 设置雷(埋雷)
test.c 中代码如下:
void game() { char mine[ROWS][COLS] = { 0 };//存放雷的数组 char show_mine[ROWS][COLS] = { 0 };//展示扫雷的数组--给玩家观察的数组 Initboard(mine, ROWS, COLS, '0'); //初始化为字符‘0’ Initboard(show_mine, ROWS, COLS, '*');//初始化为字符‘*’ print_board(show_mine, ROW, COL);//展示扫雷的数组 Set_mine(mine, ROW, COL); //埋雷的过程,只操作我们存放雷的数组 //print_board(mine, ROW, COL);//可以观察设置的雷是否正确 }
game.h 中代码如下:
#define junior_mine 10 //雷的数目 #include<stdlib.h>//srand,rand 的头文件 #include<time.h> //time 的头文件 //设置雷 void Set_mine(char board[ROWS][COLS], int row, int col); 同上面展示雷的数组一样,埋雷的这个数组操作的是创建的 mine这个数组 【ROWS】【COLS】需要保持一直,由于扫雷的方块是9*9大小,所以我们传 入的棋盘大小任然是row 和 col
game.c 中代码如下:
void Set_mine(char board[ROWS][COLS], int row, int col) { int x = 0; int y = 0; int count = junior_mine; while (count) //雷的数量为0时跳出循环说明雷已经布置完了 { //随机产生雷的坐标在 1~9的范围内 x = rand() % row + 1; y = rand() % col + 1; if (board[x][y] == '0') //说明该坐标处没有雷并且可以设置雷 { board[x][y] = '1'; //埋雷成功 用 字符 1表示 count--; } } }
5.扫雷
test.c 中代码如下:
void game() { char mine[ROWS][COLS] = { 0 };//存放雷的数组 char show_mine[ROWS][COLS] = { 0 };//展示扫雷的数组--给玩家观察的数组 Initboard(mine, ROWS, COLS, '0'); //初始化为字符‘0’ Initboard(show_mine, ROWS, COLS, '*');//初始化为字符‘*’ print_board(show_mine, ROW, COL);//展示扫雷的数组 Set_mine(mine, ROW, COL); Find_mine(mine, show_mine, ROW, COL); }
game.h 中代码如下:
//排雷 void Find_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
game.c 中代码如下:
//统计该坐标周围雷的个数 int sum_mine(char board[ROWS][COLS], int x, int y) { int sum = 0; int i = 0; int j = 0; for (i = x - 1; i <= x + 1; i++) { //产生以该坐标为中心的九宫格内的八个坐标 for (j = y - 1; j <= y + 1; j++) { sum+=board[i][j] - '0'; //注意数字和字符之间的转换 } } return sum; } void Find_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col) { printf("请输入坐标进行排查:\n"); int x = 0; int y = 0; //IsWin函数用于判断是否胜利 下在一步具体实现 while (IsWin(show,row,col)==0) { scanf("%d %d", &x, &y); if (x >= 1 && x <= row && y >= 1 && y <= col)//判断坐标合法性 { if (mine[x][y] == '1') { printf("踩雷!\n"); print_board(mine, ROW, COL);//踩雷后给玩家展示踩雷在哪里 //和雷的全部坐标 break; } else //没有踩雷 { int count = sum_mine(mine, x, y);//先统计该做标的周围的雷 show[x][y] = count + '0';//注意int类型和字符类型转换 Open_Not_mine(mine, show, x, y);//展开该坐标周围没有雷的方块 print_board(show, ROW, COL);//展示完以及雷的个数统计后,展示给玩家观察 } } else printf("输入错误,请重新输入\n"); }
6.展开该坐标周围没有雷的全部方块
由于展开周围坐标没有雷的方块这个函数不属于游戏模块test.c 中的game()里的函数,因此不需要写在game.h中声明
game.c 中代码如下:
void Open_Not_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y) { int i = 0; int j = 0; int count = 0; //判断坐标是否合法 if (x >= 1 && x <= 9 && y >= 1 && y <= 9) { for (i = -1; i<= 1; i++) { //该坐标为中心的八个坐标的循环写法 for (j = -1; j<= 1; j++) { //如果这个坐标不是雷的情况下 if (mine[x + i][y + j] == '0') { // 注意是 [x+i]和[y+i] 是改坐标周围其他坐标 //统计这个坐标周围的雷 count = sum_mine(mine, x + i, y + j); if (count == 0) //坐标周围没有雷,说明可以展开 { if (show[x + i][y + j] == '*') { show[x + i][y + j] = ' '; Open_Not_mine(mine, show, x + i, y + j); //回去递归调用周围坐标判断 } } else //周围有雷 则这个坐标轴为中心的九宫格将不展开 { show[i + x][j + y] = count + '0'; //统计这个坐标周围有几个雷并显示在改坐标处 } } } } } }
7.判断输赢
同展开函数 Open_Not_mine 一样, 判断输赢这个函数也不需要在game.h中进行声明
game.c中代码如下:
int IsWin(char show[ROWS][COLS], int row, int col) { int i = 0; int j = 0; int count = 0; for (i = 1; i <= row;i++) { //判断坐标范围 for (j = 1; j <= col; j++) { if (show[i][j] == '*') { count++; //统计show数组在9*9中棋盘上一共有多少个不是雷的个数 } } } //雷的个数 return count == junior_mine;//相等返回1 不想动返回0 //相等时说明 没有雷的方块都已经找到了,其余的位置都为雷--胜利 //不相等的时候表明,不是雷的方块还没有全部找出来--未胜利 }