扫雷游戏 我用到了递归函数 循环语句 二维数组 自定义函数为核心
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); }
?后言,我的代码并不是最简化,按照直接的思路来写,希望大家能指出不好的地方,分享好的部分给我学习。