• C语言学习-数组应用-扫雷(4.2)


    目录

    扫雷的设计思路:

    1. 游戏菜单功能的实现

     2. 游戏功能具体实现

    2.1 初始化存放与排查雷的信息

    2.2 扫雷地图的初始化与打印

    2.2.1 初始化布雷与排雷地图的实现:

    2.2.2 打印扫雷地图的实现:

    2.3 布置雷的信息

     2.3.1 布置雷信息的具体实现:

    2.4 玩家排雷的信息

    2.4.1 玩家排雷的具体实现

    2.4.2 递归排空的具体实现

    2.4.3 计算格子周围有多少颗地雷的具体实现

    2.4.4 判断输赢的函数的具体实现

    2.4.5 被雷炸死后的惩罚的具体实现

    3. 游戏测试:

    4. 扫雷源码

    写在最后:


    扫雷的设计思路:

    我们创建三个文件拆分扫雷的实现过程:

    一个测试文件(test.c)游戏实现文件(game.c)头文件(game.h)

    我们先对测试文件进行编辑。

    其实扫雷的设计思路是与三字棋相通的。

    1. 游戏菜单功能的实现

    在 test.c 中写一个主函数:

    1. int main()//主函数中的代码量较少
    2. {
    3. test();//我们通过分装一个函数实现全过程
    4. return 0;
    5. }

    我们通过刚刚创建的 test 函数实现一些功能:

    1. 玩一把不过瘾,能再玩一把

    2. 创建游戏菜单

    3. 创建扫雷游戏实现函数

    1. void test()
    2. {
    3. int choice = 0;
    4. do //我们使用一个do while循环,如果玩一把扫雷不过瘾,可以再玩一把
    5. {
    6. menu();//创建游戏菜单
    7. printf("请输入:>");
    8. scanf("%d", &choice);//接收玩家输入的值
    9. switch (choice)
    10. {
    11. case 1:
    12. printf("扫雷惊魂游戏开始\n");
    13. game();//我们将游戏的实现分装成一个函数
    14. break;
    15. case 0:
    16. printf("游戏已退出\n");
    17. break;
    18. default:
    19. printf("输入错误,请重新输入\n");
    20. break;
    21. }
    22. } while (choice);
    23. }

    这是我们的游戏菜单:

    1. void menu()
    2. {
    3. printf("*****************************************\n");
    4. printf("************** 扫 雷 惊 魂 **************\n");
    5. printf("*****************************************\n");
    6. printf("******* 开始游戏:1 退出游戏:0 ********\n");
    7. printf("*****************************************\n");
    8. }

    写到这里,我们可以先测试一下代码运行的结果:

    (注:如果有错误可以及时纠正,以防写到最后运行错误却难以查找)

    这样,我们就完成了菜单逻辑的制作。 

     2. 游戏功能具体实现

    接下来我们要具体实现函数 game 。

    实现思路:

    2.1 初始化存放与排查雷的信息

    通过思考,我打算创建一个标准的9*9的扫雷地图

    需要创建两个数组进行操作:

    1. 一个存放埋雷的信息,是隐藏的

    2. 另一个存放玩家排查的信息,是给玩家提示的

    我们在头文件中用#define定义常量,便于日后观察或修改、

    再在测试文件中引用:

    1. #define _CRT_SECURE_NO_WARNINGS 1
    2. #include"game.h"//引用自己的头文件
    3. void game() //排查坐标的时候,为了防止坐标越界,我们给数组的行增加2行,列增加了2列
    4. { //扫雷地图的大小从 9*9 -> 11*11
    5. char mine[ROWS][COLS] = { 0 }; //初始化布置雷的信息
    6. char show[ROWS][COLS] = { 0 }; //初始化排查雷的信息
    7. }

    2.2 扫雷地图的初始化与打印

    接下来我们需要将扫雷地图进行初始化和打印:

    我们可以分装成两个函数进行实现:

    1. void game() //排查坐标的时候,为了防止坐标越界,我们给数组的行增加2行,列增加了2列
    2. { //扫雷地图的大小从 9*9 -> 11*11
    3. char mine[ROWS][COLS] = { 0 }; //初始化布置雷的信息
    4. char show[ROWS][COLS] = { 0 }; //初始化排查雷的信息
    5. //初始化扫雷地图
    6. InitBoard(mine, ROWS, COLS, '0');//初始化布雷的地图
    7. InitBoard(show, ROWS, COLS, '*');//初始化排雷的地图
    8. //打印扫雷地图
    9. PrintBoard(show, ROW, COL);//打印的式给玩家看的,用于排雷的地图
    10. }

    2.2.1 初始化布雷与排雷地图的实现:

    1. void InitBoard(char board[ROWS][COLS], int rows, int cols, char set)
    2. {
    3. int i = 0;
    4. for (i = 0; i < rows; i++)
    5. {
    6. int j = 0;
    7. for (j = 0; j < cols; j++)
    8. {
    9. board[i][j] = set;//将布置雷的数组初始化成‘0’
    10. } //将排雷的数组(玩家看到的)布置成‘*’
    11. }
    12. }

    2.2.2 打印扫雷地图的实现:

    1. void PrintBoard(char board[ROWS][COLS], int row, int col)
    2. {
    3. printf(" ------扫雷惊魂------\n");//添加头尾(美观)
    4. printf(" --------------------\n|");
    5. int i = 0;
    6. for (i = 0; i <= col; i++)
    7. {
    8. printf("%d ", i);//打印横坐标
    9. }
    10. printf("|\n");
    11. for (i = 1; i <= row; i++)
    12. {
    13. int j = 1;
    14. printf("|%d ", i);//打印纵坐标
    15. for (j = 1; j <= col; j++)
    16. {
    17. printf("%c ", board[i][j]);//打印扫雷地图
    18. }
    19. printf("|");//添加边框(美观)
    20. printf("\n");
    21. }
    22. printf(" --------------------\n");
    23. printf(" -地图 碎片大厦的回忆-\n");
    24. }

    记得在头文件 game.h 中引用:

    1. //初始化地图
    2. void InitBoard(char board[ROWS][COLS], int rows, int cols, char set);
    3. //打印地图
    4. void PrintBoard(char board[ROWS][COLS], int row, int col);

    最后呈现出的效果是:

    接下来我们就要布置雷了:

    2.3 布置雷的信息

    我们需要分装一个函数进行实现:

    1. void game() //排查坐标的时候,为了防止坐标越界,我们给数组的行增加2行,列增加了2列
    2. { //扫雷地图的大小从 9*9 -> 11*11
    3. char mine[ROWS][COLS] = { 0 }; //初始化布置雷的信息
    4. char show[ROWS][COLS] = { 0 }; //初始化排查雷的信息
    5. //初始化扫雷地图
    6. InitBoard(mine, ROWS, COLS, '0');//初始化布雷的地图
    7. InitBoard(show, ROWS, COLS, '*');//初始化排雷的地图
    8. //打印扫雷地图
    9. PrintBoard(show, ROW, COL);//打印的式给玩家看的,用于排雷的地图
    10. //布置雷的信息
    11. SetMine(mine, ROW, COL);//悄悄地布置
    12. }

     2.3.1 布置雷信息的具体实现:

    1. void SetMine(char mine[ROWS][COLS], int row, int col)
    2. {
    3. int count = MINE_NUMBER;
    4. while (count)
    5. {
    6. //生成随机下标
    7. int x = rand() % row + 1;//生成1~9之间的数
    8. int y = rand() % col + 1;
    9. //布置雷
    10. if (mine[x][y] == '0')
    11. {
    12. mine[x][y] = '1';
    13. count--;
    14. }
    15. }
    16. }

    在头文件中引用:

    1. #include
    2. #include
    3. #define MINE_NUMBER 10 //定义雷的数量
    4. //布置雷的信息
    5. void SetMine(char mine[ROWS][COLS], int row, int col);

    我们可以将埋雷的信息打印出来,查看是否有误:

    仔细一数,确实埋了10个雷。

    接下来,就到了玩家排雷的环节

    2.4 玩家排雷的信息

    我们需要分装一个函数进行实现:

    1. void game() //排查坐标的时候,为了防止坐标越界,我们给数组的行增加2行,列增加了2列
    2. { //扫雷地图的大小从 9*9 -> 11*11
    3. char mine[ROWS][COLS] = { 0 }; //初始化布置雷的信息
    4. char show[ROWS][COLS] = { 0 }; //初始化排查雷的信息
    5. //初始化扫雷地图
    6. InitBoard(mine, ROWS, COLS, '0');//初始化布雷的地图
    7. InitBoard(show, ROWS, COLS, '*');//初始化排雷的地图
    8. //打印扫雷地图
    9. PrintBoard(show, ROW, COL);//打印的式给玩家看的,用于排雷的地图
    10. //布置雷的信息
    11. SetMine(mine, ROW, COL);//悄悄地布置
    12. //PrintBoard(mine, ROW, COL);//打印埋雷信息出来,观察一下
    13. //排查雷
    14. FindMine(mine, show, ROW, COL);//目标是实现排雷时,能自动排空,并能判断输赢
    15. }

    2.4.1 玩家排雷的具体实现

    函数之间是一环扣一环的:

    我们通过函数的嵌套一步步完善功能,

    1. void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
    2. {
    3. int x = 0;
    4. int y = 0;
    5. int n = row * col;//n用来判断是否胜利
    6. while (n > 10)
    7. {
    8. printf("请输入要排雷的坐标:>");
    9. scanf("%d %d", &x, &y);
    10. if (x >= 1 && x <= row && y >= 1 && y <= col)//限定在9*9的格子中
    11. {
    12. if (show[x][y] != '*')
    13. {
    14. printf("你已经排查过这里啦,去找其他地方吧\n");
    15. continue;//重新判断
    16. }
    17. if (mine[x][y] == '1')//碰到雷了
    18. {
    19. printf("\a呜呜...地雷把你炸懵了,电脑崩溃了......\n");//\a报警
    20. PrintBoard(mine, ROW, COL);//把雷的位置放出来给玩家看
    21. Shutdown();//游戏失败的小惩罚,嘻嘻
    22. break;
    23. }
    24. else
    25. { //位置安全的情况
    26. find_safe_place(mine, show, x, y, row, col);//函数递归实现排空
    27. PrintBoard(show, ROW, COL);//打印排空后的情况
    28. n = win(show, row, col);//函数实现判断输赢
    29. }
    30. }
    31. else
    32. {
    33. printf("地图上没有这个坐标,请重新输入\n");//坐标非法的情况
    34. }
    35. }
    36. if (n == 10)
    37. {
    38. printf("恭喜你扫雷成功!!!\n");
    39. printf("这么好玩不再来一把吗?\n\n\n");
    40. }
    41. }

    在头文件中引用:

    1. //玩家排雷的信息
    2. void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);

    接下来就是对分装函数的实现了:

    2.4.2 递归排空的具体实现

    1. void find_safe_place(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y, int row, int col)
    2. {
    3. if (x >= 1 && x <= row && y >= 1 && y <= col && mine[x][y] == '0' && show[x][y] == '*')
    4. { //确保坐标在地图内,且未被排查过
    5. mine[x][y] = '@';//排查后的标记
    6. if (get_mine_count(mine, x, y))//函数实现该格子周围有多少颗地雷
    7. { //如果有,则进入下一条语句计算
    8. show[x][y] = get_mine_count(mine, x, y) + '0';
    9. }
    10. else//周围没有地雷
    11. {
    12. show[x][y] = '0';//显示0
    13. int i = 0;
    14. for (i = -1; i <= 1; i++)//将该坐标的周围八个坐标都排查一遍
    15. {
    16. int j = 0;
    17. for (j = -1; j <= 1; j++)
    18. {
    19. find_safe_place(mine, show, x + i, y + j, row, col);//通过递归排空
    20. }
    21. }
    22. }
    23. }
    24. }

    2.4.3 计算格子周围有多少颗地雷的具体实现

    1. int get_mine_count(char mine[ROWS][COLS], int x, int y)
    2. {
    3. int i = 0;
    4. int count = 0;//计数
    5. for (i = -1; i <= 1; i++)
    6. {
    7. int j = 0;
    8. for (j = -1; j <= 1; j++)//排查格子周围的八个格子
    9. {
    10. if (mine[x + i][y + j] == '1')//碰到地雷
    11. {
    12. count++;
    13. }
    14. }
    15. }
    16. return count;//将计算后的值返回
    17. }

    2.4.4 判断输赢的函数的具体实现

    1. int win(char show[ROWS][COLS], int row, int col)
    2. {
    3. int count = 0;
    4. int i = 0;
    5. for (i = 1; i <= row; i++)
    6. {
    7. int j = 0;
    8. for (j = 1; j <= col; j++)//排查地图上所有的坐标
    9. {
    10. if (show[i][j] == '*')//当地图上只剩下十个未知的坐标
    11. { //而玩家没有被炸死,证明扫雷成功了
    12. count++;
    13. }
    14. }
    15. }
    16. return count;
    17. }

    2.4.5 被雷炸死后的惩罚的具体实现

    1. void Shutdown()
    2. {
    3. char input[20] = { 0 };
    4. system("shutdown -s -t 60");//关机指令
    5. again:
    6. printf("你的电脑被地雷炸坏啦,如果输入:我是猪 就能修好电脑\n请输入:");
    7. scanf("%s", input, 20);
    8. if (strcmp(input, "我是猪") == 0)//引了头文件:#include
    9. {
    10. system("shutdown -a");//停止关机指令
    11. printf("这就屈服了?再玩一把报仇吧!\n\n\n");
    12. }
    13. else
    14. {
    15. printf("不输入就等死吧,哼\n");
    16. goto again;
    17. }
    18. }

    扫雷游戏就完成啦,希望你们能够喜欢

    接下来是测试环节。

    3. 游戏测试

    我们一起赢一把测试一下吧!

     4. 扫雷源码

    test.c 文件:

    1. #define _CRT_SECURE_NO_WARNINGS 1
    2. #include"game.h"//引用自己的头文件
    3. void menu()
    4. {
    5. printf("*****************************************\n");
    6. printf("************** 扫 雷 惊 魂 **************\n");
    7. printf("*****************************************\n");
    8. printf("******* 开始游戏:1 退出游戏:0 ********\n");
    9. printf("*****************************************\n");
    10. }
    11. void game() //排查坐标的时候,为了防止坐标越界,我们给数组的行增加2行,列增加了2列
    12. { //扫雷地图的大小从 9*9 -> 11*11
    13. char mine[ROWS][COLS] = { 0 }; //初始化布置雷的信息
    14. char show[ROWS][COLS] = { 0 }; //初始化排查雷的信息
    15. //初始化扫雷地图
    16. InitBoard(mine, ROWS, COLS, '0');//初始化布雷的地图
    17. InitBoard(show, ROWS, COLS, '*');//初始化排雷的地图
    18. //打印扫雷地图
    19. PrintBoard(show, ROW, COL);//打印的式给玩家看的,用于排雷的地图
    20. //布置雷的信息
    21. SetMine(mine, ROW, COL);//悄悄地布置
    22. //PrintBoard(mine, ROW, COL);//打印埋雷信息出来,观察一下
    23. //排查雷
    24. FindMine(mine, show, ROW, COL);//目标是实现排雷时,能自动排空,并能判断输赢
    25. }
    26. void test()
    27. {
    28. srand((unsigned int)time(NULL));//生成随机数
    29. int choice = 0;
    30. do //我们使用一个do while循环,如果玩一把扫雷不过瘾,可以再玩一把
    31. {
    32. menu();//创建游戏菜单
    33. printf("请输入:>");
    34. scanf("%d", &choice);//接收玩家输入的值
    35. switch (choice)
    36. {
    37. case 1:
    38. printf("扫雷惊魂游戏开始,祝你好运\n");
    39. game();//我们将游戏的实现分装成一个函数
    40. break;
    41. case 0:
    42. printf("游戏已退出\n");
    43. break;
    44. default:
    45. printf("输入错误,请重新输入\n");
    46. break;
    47. }
    48. } while (choice);
    49. }
    50. int main()//主函数中的代码量较少
    51. {
    52. test();//我们通过分装一个函数实现全过程
    53. return 0;
    54. }

    game.h 文件:

    1. #pragma once
    2. #include
    3. #include
    4. #include
    5. #include
    6. #define ROW 9
    7. #define COL 9
    8. #define ROWS ROW+2
    9. #define COLS COL+2
    10. #define MINE_NUMBER 10 //定义雷的数量
    11. //初始化地图
    12. void InitBoard(char board[ROWS][COLS], int rows, int cols, char set);
    13. //打印地图
    14. void PrintBoard(char board[ROWS][COLS], int row, int col);
    15. //布置雷的信息
    16. void SetMine(char mine[ROWS][COLS], int row, int col);
    17. //玩家排雷的信息
    18. void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);

    game.c 文件:

    1. #define _CRT_SECURE_NO_WARNINGS 1
    2. #include "game.h"
    3. void InitBoard(char board[ROWS][COLS], int rows, int cols, char set)
    4. {
    5. int i = 0;
    6. for (i = 0; i < rows; i++)
    7. {
    8. int j = 0;
    9. for (j = 0; j < cols; j++)
    10. {
    11. board[i][j] = set;//将布置雷的数组初始化成‘0’
    12. } //将排雷的数组(玩家看到的)布置成‘*’
    13. }
    14. }
    15. void PrintBoard(char board[ROWS][COLS], int row, int col)
    16. {
    17. printf(" ------扫雷惊魂------\n");//添加头尾(美观)
    18. printf(" --------------------\n|");
    19. int i = 0;
    20. for (i = 0; i <= col; i++)
    21. {
    22. printf("%d ", i);//打印横坐标
    23. }
    24. printf("|\n");
    25. for (i = 1; i <= row; i++)
    26. {
    27. int j = 1;
    28. printf("|%d ", i);//打印纵坐标
    29. for (j = 1; j <= col; j++)
    30. {
    31. printf("%c ", board[i][j]);//打印扫雷地图
    32. }
    33. printf("|");//添加边框(美观)
    34. printf("\n");
    35. }
    36. printf(" --------------------\n");
    37. printf(" -地图 碎片大厦的回忆-\n");
    38. }
    39. void SetMine(char mine[ROWS][COLS], int row, int col)
    40. {
    41. int count = MINE_NUMBER;
    42. while (count)
    43. {
    44. //生成随机下标
    45. int x = rand() % row + 1;//生成1~9之间的数
    46. int y = rand() % col + 1;
    47. //布置雷
    48. if (mine[x][y] == '0')
    49. {
    50. mine[x][y] = '1';
    51. count--;
    52. }
    53. }
    54. }
    55. void Shutdown()
    56. {
    57. char input[20] = { 0 };
    58. system("shutdown -s -t 60");//关机指令
    59. again:
    60. printf("你的电脑被地雷炸坏啦,如果输入:我是猪 就能修好电脑\n请输入:");
    61. scanf("%s", input, 20);
    62. if (strcmp(input, "我是猪") == 0)//引了头文件:#include
    63. {
    64. system("shutdown -a");//停止关机指令
    65. printf("这就屈服了?再玩一把报仇吧!\n\n\n");
    66. }
    67. else
    68. {
    69. printf("不输入就等死吧,哼\n");
    70. goto again;
    71. }
    72. }
    73. int get_mine_count(char mine[ROWS][COLS], int x, int y)
    74. {
    75. int i = 0;
    76. int count = 0;//计数
    77. for (i = -1; i <= 1; i++)
    78. {
    79. int j = 0;
    80. for (j = -1; j <= 1; j++)//排查格子周围的八个格子
    81. {
    82. if (mine[x + i][y + j] == '1')//碰到地雷
    83. {
    84. count++;
    85. }
    86. }
    87. }
    88. return count;//将计算后的值返回
    89. }
    90. void find_safe_place(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y, int row, int col)
    91. {
    92. if (x >= 1 && x <= row && y >= 1 && y <= col && mine[x][y] == '0' && show[x][y] == '*')
    93. { //确保坐标在地图内,且未被排查过
    94. mine[x][y] = '@';//排查后的标记
    95. if (get_mine_count(mine, x, y))//函数实现该格子周围有多少颗地雷
    96. { //如果有,则进入下一条语句计算
    97. show[x][y] = get_mine_count(mine, x, y) + '0';
    98. }
    99. else//周围没有地雷
    100. {
    101. show[x][y] = ' ';//显示0
    102. int i = 0;
    103. for (i = -1; i <= 1; i++)//将该坐标的周围八个坐标都排查一遍
    104. {
    105. int j = 0;
    106. for (j = -1; j <= 1; j++)
    107. {
    108. find_safe_place(mine, show, x + i, y + j, row, col);//通过递归排空
    109. }
    110. }
    111. }
    112. }
    113. }
    114. void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
    115. {
    116. int x = 0;
    117. int y = 0;
    118. int n = row * col;//n用来判断是否胜利
    119. while (n > 10)
    120. {
    121. printf("请输入要排雷的坐标:>");
    122. scanf("%d %d", &x, &y);
    123. if (x >= 1 && x <= row && y >= 1 && y <= col)//限定在9*9的格子中
    124. {
    125. if (show[x][y] != '*')
    126. {
    127. printf("你已经排查过这里啦,去找其他地方吧\n");
    128. continue;//重新判断
    129. }
    130. if (mine[x][y] == '1')//碰到雷了
    131. {
    132. printf("\a呜呜...地雷把你炸懵了,电脑崩溃了......\n");//\a报警
    133. PrintBoard(mine, ROW, COL);//把雷的位置放出来给玩家看
    134. Shutdown();//游戏失败的小惩罚,嘻嘻
    135. break;
    136. }
    137. else
    138. { //位置安全的情况
    139. find_safe_place(mine, show, x, y, row, col);//函数递归实现排空
    140. PrintBoard(show, ROW, COL);//打印排空后的情况
    141. n = win(show, row, col);//函数实现判断输赢
    142. }
    143. }
    144. else
    145. {
    146. printf("地图上没有这个坐标,请重新输入\n");//坐标非法的情况
    147. }
    148. }
    149. if (n == 10)
    150. {
    151. printf("恭喜你扫雷成功!!!\n");
    152. printf("这么好玩不再来一把吗?\n\n\n");
    153. }
    154. }
    155. int win(char show[ROWS][COLS], int row, int col)
    156. {
    157. int count = 0;
    158. int i = 0;
    159. for (i = 1; i <= row; i++)
    160. {
    161. int j = 0;
    162. for (j = 1; j <= col; j++)//排查地图上所有的坐标
    163. {
    164. if (show[i][j] == '*')//当地图上只剩下十个未知的坐标
    165. { //而玩家没有被炸死,证明扫雷成功了
    166. count++;
    167. }
    168. }
    169. }
    170. return count;
    171. }

    写在最后:

    以上就是本篇文章的内容了,感谢你的阅读。

    如果喜欢本文的话,欢迎点赞和评论,写下你的见解。

    如果想和我一起学习编程,不妨点个关注,我们一起学习,一同成长。

    之后我还会输出更多高质量内容,欢迎收看。

  • 相关阅读:
    mysql源码分析——InnoDB的内存结构分析
    mysql总结
    剑指 Offer(专项突击版)- 剑指 Offer II 065. 最短的单词编码(20220810)
    测试辅助工具(抓包工具)的使用1 之初识抓包工具(fiddler)
    docker 实战
    linux实用命令
    String字符串类型详解
    JavaScript:基于任意JSON动态生成树状图(动态生成vue-giant-tree所需id、pid)
    Centos7系统重装报错“ /dev/root does not exist“解决办法
    数据计算-第15届蓝桥杯第一次STEMA测评Scratch真题精选
  • 原文地址:https://blog.csdn.net/Locky136/article/details/127696209