扫雷游戏 我用到了递归函数 循环语句 二维数组 自定义函数为核心
1.首先是游戏的进入菜单界面
代码部分(不做讲解)
void menu()//菜单部分 { printf("*****************\n"); printf("******1.play*****\n"); printf("******0.exit*****\n"); printf("*****************\n"); }
和游戏进入主函数口
int main() { int play ; do { menu(); scanf("%d", &play); if (play == 1) { printf("游戏开始\n"); game();//引用外部函数 用的头文字是自己定义的 } else if(play != 1&& play !=0) { printf("输入错误请重新输入\n"); } } while (play); printf("游戏结束\n"); return 0; }
然后是基础参数的设置
2.然后是最基础的游戏内的代码设置 (我全部批注在代码中)
void game() { srand((unsigned int)time(NULL));//设置随机数的基础值 int x; int y; int z; char arr[X][Y] = { 0 };//这个是开棋盘 char arr_1[X][Y] = { 0 };//这个是要生成雷的位置 Init_game_sc(arr,X,Y);//初始化外棋盘 Init_game_sc_l(arr_1, X, Y);//初始化内棋盘 printf(" 左上角第一个为1 1 第二个为 1 2\n"); game_qp(arr, X, Y);//打印棋盘 game_scqp(arr_1);//生成炸弹 生成炸弹周围的数字 do//基础设置结束后游戏内部的代码 { printf("请输入你要打开的位置>>"); scanf("%d %d", &x, &y); while (1) { x -= 1; y -= 1; if (x >= X || x < 0 || y >= Y || y < 0) { printf("坐标输入错误请重新输入"); printf("请输入你要打开的位置>>"); scanf("%d %d", &x, &y); } else { break; } } int cango = game_pd(arr_1,arr, x, y);//判断是否合法,可以合并到这里面 if (cango == 1) { game_kq(arr_1, arr, x, y);//打开棋盘内的空位置 并且变成0 } else if (cango == -1) { printf("踩雷了,游戏失败"); game_qp(arr_1, X, Y); break; } z = gameover(arr);//判断游戏是否结束 if (z == L) { printf("游戏胜利\n"); game_qp(arr_1, X, Y); break; } game_qp(arr, X, Y); } while (1); //game_qp(arr,X,Y); }
3.逐个功能代码分析
初始化棋盘
void Init_game_sc(char arr[X][Y],int x,int y)//初始化棋盘 { int i = 0; int j = 0; for (i = 0; i < x; i++) { for (j = 0; j < y; j++) { arr[i][j] = '#'; } } } void Init_game_sc_l(char arr[X][Y], int x, int y)//初始化雷的棋盘 { int i = 0; int j = 0; for (i = 0; i < x+1; i++) { for (j = 0; j < y; j++) { arr[i][j] = ' '; } } }
我认为这里可以合并,可以进一步简化
打印棋盘
void game_qp(char arr[X][Y], int x, int y)//打印棋盘 { printf("\n"); int i = 0; int j = 0; int z = 0; printf(" "); for (z = 0; z < x; z++) { printf("%2d ",z + 1); printf(" "); } printf("\n"); printf(" "); for (z = 0; z < x; z++) { printf("---"); printf(" "); } printf("\n"); for (i = 0; i < y; i++) { printf(" %2d",i + 1); for (j = 0; j < x; j++) { printf(" | ", arr[i][j]); printf("%c", arr[i][j]); } printf(" | ", arr[i][j]); printf("\n"); printf(" "); for (z = 0; z < x; z++) { printf("---"); printf(" "); } printf("\n"); } }
打印部分不做什么解释
判断是否合法
int game_pd(char arr_1[X][Y],char arr[X][Y], int x, int y)//是否合法 { if (arr_1[x][y] != '*') { return 1; } else if (arr_1[x][y] == '*') { return -1; } }
这里的判断是否踩到雷了,踩到雷返回-1 没踩到雷返回1 这个可以合并到游戏主程序里
炸弹生成代码 和 周边数字生成代码
void game_scqp(char arr_1[X][Y])//集成炸弹生成 炸弹周围数字检测生成 { for (int l = L;l > 0;l--)//炸弹生成 用的rand函数 { int x = (rand() % X + 1);//0-9 int y = (rand() % Y + 1);//0-9 if(arr_1[x][y] != '*') { arr_1[x][y] = '*'; } else { l += 1; } } for (int i = 0; i < X; i++)//炸弹周围数字计数功能 { for (int j = 0; j < Y; j++) { if (arr_1[i][j] == '*') { continue; } else { int a; int b; int count = 0; for (a = -1; a < 2; a++) { for (b = -1; b < 2; b++) { if (i + a < 0 || i + a >= X || j + b < 0 || j + b >= Y) { continue; } if (arr_1[i + a][j + b] == '*') { count++; } } } if (count != 0) { arr_1[i][j] = count + '0'; } } } } }
炸弹周围数字计数功能,我写的并不是最优解,但是我个人认为比较直观,先找到一个坐标 然后定义数字初始为0 然后以 3 * 3的方式挨个扫描周围 如果有雷 数字加一 几个雷加几个数 数完以后 把数字填写到这个坐标里(我个人认为写的比较麻烦,希望能有更优解)
判定是否胜利
int gameover(char arr[X][Y]) { int count = 0; int i = 0; int j = 0; for (i = 0; i < X; i++) { for (j = 0; j < Y; j++) { if (arr[i][j] == '#') { count++; } } } return count; }
到最后没有扫的地方 是 # 那么当#的数量等于雷的数量就判断成功
这里返回#的数量给后面的程序判断
然后是打开空格
这里用到递归函数
我的思路就是以十字打开 然后在打开过的非数字的地方变成0 到有数字的地方停止
void game_kq(char arr_1[X][Y], char arr[X][Y], int x, int y)//开启棋盘 打开空棋盘位置 { arr[x][y] = arr_1[x][y]; if (arr_1[x][y] != '0') { if(arr_1[x][y] == ' ') arr_1[x][y] = '0'; if (x > 0) { if (arr_1[x - 1][y] == ' ') { game_kq(arr_1, arr, x - 1, y); } if (arr_1[x - 1][y] != ' ' && arr_1[x - 1][y] != '*') { arr[x - 1][y] = arr_1[x - 1][y]; } } if (x < X - 1) { if (arr_1[x + 1][y] == ' ') { game_kq(arr_1, arr, x + 1, y); } if (arr_1[x + 1][y] != ' ' && arr_1[x + 1][y] != '*') { arr[x + 1][y] = arr_1[x + 1][y]; } } if (y > 0) { if (arr_1[x][y - 1] == ' ') { game_kq(arr_1, arr, x, y - 1); } if (arr_1[x][y - 1] != ' ' && arr_1[x][y - 1] != '*') { arr[x][y - 1] = arr_1[x][y - 1]; } } if (y < Y - 1) { if (arr_1[x][y + 1] == ' ') { game_kq(arr_1, arr, x, y + 1); } if (arr_1[x][y + 1] != ' ' && arr_1[x][y + 1] != '*') { arr[x][y + 1] = arr_1[x][y + 1]; } } } }
因为是十字 所以我写了四个方向的递归(希望有大佬可以给出简化版本,而且能让简化完之后给我的是空格而不是0)
以上是程序的各个部分
//全部函数程序 头文件 #pragma once #include <stdio.h> #define X 10//长 #define Y 10//宽 #define L 1//雷的个数 void menu(); void game();
主函数 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include "game.h" int main() { int play ; do { menu(); scanf("%d", &play); if (play == 1) { printf("游戏开始\n"); game(); } else if(play != 1&& play !=0) { printf("输入错误请重新输入\n"); } } while (play); printf("游戏结束\n"); return 0; }
游戏函数 #define _CRT_SECURE_NO_WARNINGS #include "game.h" #include <stdlib.h> #include <time.h> void menu()//菜单部分 { printf("*****************\n"); printf("******1.play*****\n"); printf("******0.exit*****\n"); printf("*****************\n"); } void Init_game_sc(char arr[X][Y],int x,int y)//初始化棋盘 { int i = 0; int j = 0; for (i = 0; i < x; i++) { for (j = 0; j < y; j++) { arr[i][j] = '#'; } } } void Init_game_sc_l(char arr[X][Y], int x, int y)//初始化雷的棋盘 { int i = 0; int j = 0; for (i = 0; i < x+1; i++) { for (j = 0; j < y; j++) { arr[i][j] = ' '; } } } void game_qp(char arr[X][Y], int x, int y)//打印棋盘 { printf("\n"); int i = 0; int j = 0; int z = 0; printf(" "); for (z = 0; z < x; z++) { printf("%2d ",z + 1); printf(" "); } printf("\n"); printf(" "); for (z = 0; z < x; z++) { printf("---"); printf(" "); } printf("\n"); for (i = 0; i < y; i++) { printf(" %2d",i + 1); for (j = 0; j < x; j++) { printf(" | ", arr[i][j]); printf("%c", arr[i][j]); } printf(" | ", arr[i][j]); printf("\n"); printf(" "); for (z = 0; z < x; z++) { printf("---"); printf(" "); } printf("\n"); } } int game_pd(char arr_1[X][Y],char arr[X][Y], int x, int y)//是否合法 { if (arr_1[x][y] != '*') { return 1; } else if (arr_1[x][y] == '*') { return -1; } } void game_kq(char arr_1[X][Y], char arr[X][Y], int x, int y)//开启棋盘 打开空棋盘位置 { arr[x][y] = arr_1[x][y]; if (arr_1[x][y] != '0') { if(arr_1[x][y] == ' ') arr_1[x][y] = '0'; if (x > 0) { if (arr_1[x - 1][y] == ' ') { game_kq(arr_1, arr, x - 1, y); } if (arr_1[x - 1][y] != ' ' && arr_1[x - 1][y] != '*') { arr[x - 1][y] = arr_1[x - 1][y]; } } if (x < X - 1) { if (arr_1[x + 1][y] == ' ') { game_kq(arr_1, arr, x + 1, y); } if (arr_1[x + 1][y] != ' ' && arr_1[x + 1][y] != '*') { arr[x + 1][y] = arr_1[x + 1][y]; } } if (y > 0) { if (arr_1[x][y - 1] == ' ') { game_kq(arr_1, arr, x, y - 1); } if (arr_1[x][y - 1] != ' ' && arr_1[x][y - 1] != '*') { arr[x][y - 1] = arr_1[x][y - 1]; } } if (y < Y - 1) { if (arr_1[x][y + 1] == ' ') { game_kq(arr_1, arr, x, y + 1); } if (arr_1[x][y + 1] != ' ' && arr_1[x][y + 1] != '*') { arr[x][y + 1] = arr_1[x][y + 1]; } } } } void game_scqp(char arr_1[X][Y])//集成炸弹生成 炸弹周围数字检测生成 { for (int l = L;l > 0;l--)//炸弹生成 { int x = (rand() % X + 1);//0-9 int y = (rand() % Y + 1);//0-9 if(arr_1[x][y] != '*') { arr_1[x][y] = '*'; } else { l += 1; } } for (int i = 0; i < X; i++) { for (int j = 0; j < Y; j++) { if (arr_1[i][j] == '*') { continue; } else { int a; int b; int count = 0; for (a = -1; a < 2; a++) { for (b = -1; b < 2; b++) { if (i + a < 0 || i + a >= X || j + b < 0 || j + b >= Y) { continue; } if (arr_1[i + a][j + b] == '*') { count++; } } } if (count != 0) { arr_1[i][j] = count + '0'; } } } } } int gameover(char arr[X][Y]) { int count = 0; int i = 0; int j = 0; for (i = 0; i < X; i++) { for (j = 0; j < Y; j++) { if (arr[i][j] == '#') { count++; } } } return count; } void game() { srand((unsigned int)time(NULL));//设置随机数的基础值 int x; int y; int z; char arr[X][Y] = { 0 };//这个是开棋盘 char arr_1[X][Y] = { 0 };//这个是要生成雷的位置 Init_game_sc(arr,X,Y);//初始化外棋盘 Init_game_sc_l(arr_1, X, Y);//初始化内棋盘 printf(" 左上角第一个为1 1 第二个为 1 2\n"); game_qp(arr, X, Y);//打印棋盘 game_scqp(arr_1);//生成炸弹 生成炸弹周围的数字 do//基础设置结束后游戏内部的代码 { printf("请输入你要打开的位置>>"); scanf("%d %d", &x, &y); while (1) { x -= 1; y -= 1; if (x >= X || x < 0 || y >= Y || y < 0) { printf("坐标输入错误请重新输入"); printf("请输入你要打开的位置>>"); scanf("%d %d", &x, &y); } else { break; } } int cango = game_pd(arr_1,arr, x, y);//判断是否合法,可以合并到这里面 if (cango == 1) { game_kq(arr_1, arr, x, y);//打开棋盘内的空位置 并且变成0 } else if (cango == -1) { printf("踩雷了,游戏失败"); game_qp(arr_1, X, Y); break; } z = gameover(arr);//判断游戏是否结束 if (z == L) { printf("游戏胜利\n"); game_qp(arr_1, X, Y); break; } game_qp(arr, X, Y); } while (1); //game_qp(arr,X,Y); }
后言,我的代码并不是最简化,按照直接的思路来写,希望大家能指出不好的地方,分享好的部分给我学习。