• C语言-扫雷游戏的实现


    🌈write in front🌈
    🧸大家好,我是Aileen🧸.希望你看完之后,能对你有所帮助,不足请指正!共同学习交流.
    🆔本文由Aileen_0v0🧸 原创 CSDN首发🐒 如需转载还请通知⚠️
    📝个人主页:Aileen_0v0🧸—CSDN博客
    🎁欢迎各位→点赞👍 + 收藏⭐️ + 留言📝​
    📣系列专栏:Aileen_0v0🧸的C语言学习系列专栏——CSDN博客
    🗼我的格言:"没有罗马,那就自己创造罗马~"

    目录

    1.扫雷游戏的分析和设计👻

    1.1扫雷游戏的功能说明💭

    1.2游戏的界面▶️​编辑

    2.扫雷游戏的代码实现🔆

    2.1数据结构的分析🙉

    ​编辑

    2.2文件结构设计💫

    2.3游戏的过程实现,代码块💦

    主函数,用户菜单页面代码⏸️:

    棋盘打印*️⃣:

    给棋盘加坐标:🔢

    布置雷💣:

    排雷💥:

    3.扫雷游戏的完整代码✨


    1.扫雷游戏的分析和设计👻

    1.1扫雷游戏的功能说明💭

    使用控制台实现经典的扫雷游戏

    游戏可以通过菜单实现继续玩或退出游戏
    • 扫雷的棋盘是9*9的格子
    • 默认随机布置10个雷
     可以排查雷
            

    1.2游戏的界面▶️

    初始界面

    排雷界面

    排雷失败界面

    2.扫雷游戏的代码实现🔆

    2.1数据结构的分析🙉

    但是如果我们判断边缘的格子位置是否含雷时,

    由于周围边界没有东西,导致我们需要判断这个格子是否位于边缘位置,这就会让代码变的复杂~

    于是,我们可以通过 在原来9 * 9 的方格的 上下 , 左右位置 放没有雷的空格子(如上面左右两个数组的橙色边界)

    根据刚刚的分析,

    我们在左边创建一个mine数组 布置好雷的信息,全部初始化成 字符"0" ~

    雷 - "1"

    非雷 - "0"


    在右边创建一个show数组放置 排查处的雷的信息, 最初未排查时,都放 *

    没有排查 - "*"

    排查 - 数字字符


    小细节:之所以都用 字符数组 是因为 只需要定义字符函数, 方便操作~

    如果 左边是整形数组,右边是字符数组 就 需要调用两个不同的函数~


    在game.c中打印棋盘的时候,我们只打印9*9的~

    因为外边的绿色空格只是为了编写变得容易一点,不会越界~~

    但是,按照这种方式打印,我们很难知道是第几行第几列,因为没有标识

    于是我们,再利用 for 循环打印出 行和列的序号 

    利用库函数rand 随机布置雷

    要从1到n中随机取一个数的公式是:


    rand()%n+1.


    解释一下:
    1、库函数rand()会返回一个大于0的随机整数;
    2、rand()%n,对这个返回的随机整数除以n取余,结果是一个0到n-1的随机整数

    3、rand()%n+1,将rand()%n的结果加上1,就可得到一个1到n的随机整数;

    更通用一点的公式,产生m到n中(n>m)的一个随机数的公式是:
    rand()%(n-m+1)+m。

    2.2文件结构设计💫

    首先,先创建这三个文件.

    2.3游戏的过程实现,代码块💦

    主函数,用户菜单页面代码⏸️:
    1. #define _CRT_SECURE_NO_WARNINGS
    2. #include
    3. //扫雷页面都实现
    4. void menu()
    5. {
    6. printf("*********************************\n");
    7. printf("****** 1. play *****\n");
    8. printf("****** 0. exit *****\n");
    9. printf("*********************************\n");
    10. }
    11. int main()
    12. {
    13. int input = 0;
    14. do
    15. {
    16. menu();
    17. printf("请选择:<");
    18. scanf("%d", &input);
    19. switch (input)
    20. {
    21. case 1:
    22. printf("扫雷\n");
    23. break;
    24. case 0:
    25. printf("退出游戏\n");
    26. break;
    27. default:
    28. printf("选择错误,请重新选择\n");
    29. break;
    30. }
    31. //case 1 和 default 都是非零
    32. //里层switch语句走完 就会走while语句
    33. } while (input);
    34. return 0;
    35. //如果while 后面为0,程序就会自动退出游戏
    36. //非0 1就打印扫雷 其他值则重新打印菜单让用户选择
    37. }

    运行效果:

    棋盘打印*️⃣:

    头文件game.h 的代码:

    1. #define _CRT_SECURE_NO_WARNINGS
    2. #include
    3. #pragma once
    4. #define ROW 9
    5. #define COL 9
    6. #define ROWS ROW + 2
    7. #define COLS COL + 2
    8. // 函数的声明
    9. //初始化棋盘
    10. void InitBoard(char board[ROWS][COLS], int rows, int cols,char set);
    11. //打印棋盘的
    12. void DisplayBoard(char board[ROWS][COLS],int rows, int cols);

    源文件game.c 的代码:

    1. #define _CRT_SECURE_NO_WARNINGS
    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;
    12. }
    13. }
    14. }
    15. //打印棋盘,就是打印数组
    16. void DisplayBoard(char board[ROWS][COLS], int row, int col)
    17. {
    18. int i = 0;
    19. for (i = 1; i <= row; i++)
    20. {
    21. int j = 0;
    22. for (j = 1; j <= col; j++)
    23. {
    24. printf("%c ", board[i][j]);
    25. }
    26. printf("\n");
    27. }
    28. }

    源文件 test.c 的代码:

    1. #define _CRT_SECURE_NO_WARNINGS
    2. #include
    3. #include "game.h"
    4. //扫雷页面都实现
    5. void menu()
    6. {
    7. printf("*********************************\n");
    8. printf("****** 1. play *****\n");
    9. printf("****** 0. exit *****\n");
    10. printf("*********************************\n");
    11. }
    12. void game()
    13. {
    14. //数组
    15. char mine[ROWS][COLS];//"0"
    16. char show[ROWS][COLS];//"*"
    17. InitBoard(mine, ROWS, COLS,'0');
    18. InitBoard(show, ROWS, COLS,'*');
    19. //棋盘打印
    20. DisplayBoard(mine, ROW, COL);
    21. DisplayBoard(show, ROW, COL);
    22. //布置雷
    23. //排查雷
    24. }
    25. int main()
    26. {
    27. int input = 0;
    28. do
    29. {
    30. menu();
    31. printf("请选择:<");
    32. scanf_s("%d", &input);
    33. switch (input)
    34. {
    35. case 1:
    36. printf("扫雷\n");
    37. game();//游戏代码模块化
    38. break;
    39. case 0:
    40. printf("退出游戏\n");
    41. break;
    42. default:
    43. printf("选择错误,请重新选择\n");
    44. break;
    45. }
    46. //case 1 和 default 都是非零
    47. //里层switch语句走完 就会走while语句
    48. } while (input);
    49. return 0;
    50. //如果while 后面为0,程序就会自动退出游戏
    51. //非0 1就打印扫雷 其他值则重新打印菜单让用户选择
    52. }

     打印结果:

    给棋盘加坐标:🔢

    在原来打印棋盘上加上坐标,进行定位,只需修改game.c部分的代码:

    1. #define _CRT_SECURE_NO_WARNINGS
    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;
    12. }
    13. }
    14. }
    15. //打印棋盘,就是打印数组
    16. void DisplayBoard(char board[ROWS][COLS], int row, int col)
    17. {
    18. int i = 0;
    19. printf("-----------扫雷游戏-----------\n");
    20. //打印棋盘序号
    21. for (i = 0; i <= row; i++)
    22. {
    23. printf("%d ", i);
    24. }
    25. printf("\n");
    26. //打印9*9的棋盘
    27. for (i = 1; i <= row; i++)
    28. {
    29. printf("%d ", i);
    30. int j = 0;
    31. for (j = 1; j <= col; j++)
    32. {
    33. printf("%c ", board[i][j]);
    34. }
    35. printf("\n");
    36. }
    37. printf("-----------扫雷游戏-----------\n");
    38. }

    打印结果:

    布置雷💣:

    game.h:

    1. #define _CRT_SECURE_NO_WARNINGS
    2. #include
    3. #include //标准库头文件
    4. #include
    5. //布置雷
    6. void SetMine(char mine[ROWS][COLS],int row , int col);
    7. //虽然布置雷是在9*9的格子里面布置--->row 和 col
    8. //但是,数组传参还是11*11的格子,即ROWS和COLS

    game.c: 

    1. //布置雷
    2. void SetMine(char mine[ROWS][COLS], int row, int col)
    3. {
    4. int count = EASY_COUNT;
    5. while (count)
    6. {
    7. int x = rand() % row + 1;
    8. int y = rand() % col + 1;
    9. if (mine[x][y] == '0')//如果该位置无雷才在这个位置放雷
    10. {
    11. mine[x][y] = '1';
    12. count--;
    13. }
    14. }
    15. }

    test.c文件: 

    1. //布置雷
    2. SetMine(mine, ROW, COL);
    3. DisplayBoard(mine, ROW, COL);

     打印结果:

    排雷💥:

    通过观察,ASCII表可知:

    字符'0'-->ASCII值:48

    字符'1'-->ASCII值:49

    字符'2'-->ASCII值:50

    字符'3'-->ASCII值:51

    依此类推

    得出规律:'1' - '0' = 49-48 = 1

                    '3' - '0' = 51-48 = 3

    字符-字符=数字   ----------> 反推: 数字+字符=字符

    统计 x y 周围有几个雷 --->

    把其周围的字符值'0'和'1'加起来即可

    然后减去8个字符'0' 得到数字,去代替  x y 处的 '*'.

    game.h:

    1. //排查雷
    2. void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);

    game.c:

    1. //实现GetMineCount数组
    2. static int GetMineCount(char mine[ROWS][COLS], int x, int y)
    3. {
    4. return(mine[x - 1][y] +
    5. mine[x - 1][y - 1] +
    6. mine[x][y - 1] +
    7. mine[x + 1][y - 1] +
    8. mine[x + 1][y] +
    9. mine[x + 1][y + 1] +
    10. mine[x][y + 1] +
    11. mine[x - 1][y + 1] - 8 * '0');
    12. }
    13. //排查雷
    14. void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
    15. {
    16. int x = 0;
    17. int y = 0;
    18. while (1)//死循环排雷
    19. {
    20. printf("请输入要排查的坐标:>");
    21. scanf("%d %d", &x, &y);
    22. //注意:x y 要在有效的排查范围(9*9)之内
    23. if (x >= 1 && x <= row && y >= 1 && y <= col)
    24. {
    25. //开始排查是否是雷
    26. if (mine[x][y] == '1')
    27. {
    28. printf("很遗憾,你被炸死了\n");
    29. DisplayBoard(mine, ROW, COL);
    30. break;
    31. }
    32. else
    33. {
    34. int count = GetMineCount(mine, x, y);
    35. show[x][y] = count + '0';
    36. DisplayBoard(show, ROW, COL);
    37. //count + 字符'0;变成对应的数字字符放到show数组里
    38. }
    39. }
    40. else
    41. {
    42. printf("坐标非法,重新输入\n");
    43. }
    44. }
    45. }

    test.c:

    1. //排查雷
    2. FindMine(mine, show, ROW, COL);

    注意:GetMineCount 没有在其它文件中声明是因为,我们只希望它在game.c处悄悄使用它,所以前加static

    运行结果:

    上面的排雷,未限制排雷次数,即可无限循环下去,这样子的游戏设计显然不合理~

    于是,我们可以根据,雷和非雷的数量关系进行排雷循环次数的限制.

    game.h:

    1. //布置80个雷
    2. #define EASY_COUNT 80

    game.c: 

    1. //排查雷
    2. void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
    3. {
    4. int x = 0;
    5. int y = 0;
    6. int win = 0;
    7. while (win//根据雷和非雷的数量关系限制循环次数
    8. {
    9. printf("请输入要排查的坐标:>");
    10. scanf("%d %d", &x, &y);
    11. //注意:x y 要在有效的排查范围(9*9)之内
    12. if (x >= 1 && x <= row && y >= 1 && y <= col)
    13. {
    14. //开始排查是否是雷
    15. if (mine[x][y] == '1')
    16. {
    17. printf("很遗憾,你被炸死了\n");
    18. DisplayBoard(mine, ROW, COL);
    19. break;
    20. }
    21. else
    22. {
    23. int count = GetMineCount(mine, x, y);
    24. show[x][y] = count + '0';
    25. DisplayBoard(show, ROW, COL);
    26. //count + 字符'0;变成对应的数字字符放到show数组里
    27. win++;
    28. }
    29. }
    30. else
    31. {
    32. printf("坐标非法,重新输入\n");
    33. }
    34. }
    35. if (win == row * col - EASY_COUNT)
    36. {
    37. printf("恭喜你,扫雷成功\n");
    38. DisplayBoard(mine, ROW, COL);
    39. }
    40. }

    我们可以通过改变雷的个数,然后根据mine的数组打印的结果对照着进行排雷成功的结果输出,检查是否有误. 

    运行结果:

    3.扫雷游戏的完整代码✨

    game.h:

    1. #define _CRT_SECURE_NO_WARNINGS
    2. #include
    3. #include //标准库头文件
    4. #include
    5. #pragma once
    6. #define ROW 9
    7. #define COL 9
    8. #define ROWS ROW + 2
    9. #define COLS COL + 2
    10. //布置10个雷
    11. #define EASY_COUNT 10
    12. // 函数的声明
    13. //初始化棋盘
    14. void InitBoard(char board[ROWS][COLS], int rows, int cols,char set);
    15. //打印棋盘的
    16. void DisplayBoard(char board[ROWS][COLS],int rows, int cols);

    game.c:

    1. #define _CRT_SECURE_NO_WARNINGS
    2. #include "game.h"
    3. #include
    4. void InitBoard(char board[ROWS][COLS], int rows, int cols,char set)
    5. {
    6. int i = 0;
    7. for (i = 0; i < rows; i++)
    8. {
    9. int j = 0;
    10. for (j = 0; j < cols; j++)
    11. {
    12. board[i][j] = set;
    13. }
    14. }
    15. }
    16. //打印棋盘,就是打印数组
    17. void DisplayBoard(char board[ROWS][COLS], int row, int col)
    18. {
    19. int i = 0;
    20. printf("-----------扫雷游戏-----------\n");
    21. //打印棋盘序号
    22. for (i = 0; i <= row; i++)
    23. {
    24. printf("%d ", i);
    25. }
    26. printf("\n");
    27. //打印9*9的棋盘
    28. for (i = 1; i <= row; i++)
    29. {
    30. printf("%d ", i);
    31. int j = 0;
    32. for (j = 1; j <= col; j++)
    33. {
    34. printf("%c ", board[i][j]);
    35. }
    36. printf("\n");
    37. }
    38. printf("-----------扫雷游戏-----------\n");
    39. }
    40. //布置雷
    41. void SetMine(char mine[ROWS][COLS], int row, int col)
    42. {
    43. int count = EASY_COUNT;
    44. while (count)
    45. {
    46. int x = rand() % row + 1;
    47. int y = rand() % col + 1;
    48. if (mine[x][y] == '0')//如果该位置无雷才在这个位置放雷
    49. {
    50. mine[x][y] = '1';
    51. count--;
    52. }
    53. }
    54. }
    55. //实现GetMineCount数组
    56. static int GetMineCount(char mine[ROWS][COLS], int x, int y)
    57. {
    58. return(mine[x - 1][y] +
    59. mine[x - 1][y - 1] +
    60. mine[x][y - 1] +
    61. mine[x + 1][y - 1] +
    62. mine[x + 1][y] +
    63. mine[x + 1][y + 1] +
    64. mine[x][y + 1] +
    65. mine[x - 1][y + 1] - 8 * '0');
    66. }
    67. //排查雷
    68. void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
    69. {
    70. int x = 0;
    71. int y = 0;
    72. int win = 0;
    73. while (win//根据雷和非雷的数量关系限制循环次数
    74. {
    75. printf("请输入要排查的坐标:>");
    76. scanf("%d %d", &x, &y);
    77. //注意:x y 要在有效的排查范围(9*9)之内
    78. if (x >= 1 && x <= row && y >= 1 && y <= col)
    79. {
    80. //开始排查是否是雷
    81. if (mine[x][y] == '1')
    82. {
    83. printf("很遗憾,你被炸死了\n");
    84. DisplayBoard(mine, ROW, COL);
    85. break;
    86. }
    87. else
    88. {
    89. int count = GetMineCount(mine, x, y);
    90. show[x][y] = count + '0';
    91. DisplayBoard(show, ROW, COL);
    92. //count + 字符'0;变成对应的数字字符放到show数组里
    93. win++;
    94. }
    95. }
    96. else
    97. {
    98. printf("坐标非法,重新输入\n");
    99. }
    100. }
    101. if (win == row * col - EASY_COUNT)
    102. {
    103. printf("恭喜你,扫雷成功\n");
    104. DisplayBoard(mine, ROW, COL);
    105. }
    106. }

    test.c:

    1. #define _CRT_SECURE_NO_WARNINGS
    2. #include
    3. #include "game.h"
    4. //扫雷页面都实现
    5. void menu()
    6. {
    7. printf("*********************************\n");
    8. printf("****** 1. play *****\n");
    9. printf("****** 0. exit *****\n");
    10. printf("*********************************\n");
    11. }
    12. void game()
    13. {
    14. //数组
    15. char mine[ROWS][COLS];//"0"
    16. char show[ROWS][COLS];//"*"
    17. InitBoard(mine, ROWS, COLS,'0');
    18. InitBoard(show, ROWS, COLS,'*');
    19. //棋盘打印
    20. //DisplayBoard(mine, ROW, COL); 雷的位置注释掉不打印出来,保持神秘感
    21. DisplayBoard(show, ROW, COL);
    22. //布置雷
    23. SetMine(mine, ROW, COL);
    24. //DisplayBoard(mine, ROW, COL);
    25. //排查雷
    26. FindMine(mine, show, ROW, COL);
    27. }
    28. int main()
    29. {
    30. int input = 0;
    31. srand((unsigned int)time(NULL));//强制转换成无符号整型
    32. do
    33. {
    34. menu();
    35. printf("请选择:<");
    36. scanf_s("%d", &input);
    37. switch (input)
    38. {
    39. case 1:
    40. printf("扫雷\n");
    41. game();//游戏代码模块化
    42. break;
    43. case 0:
    44. printf("退出游戏\n");
    45. break;
    46. default:
    47. printf("选择错误,请重新选择\n");
    48. break;
    49. }
    50. //case 1 和 default 都是非零
    51. //里层switch语句走完 就会走while语句
    52. } while (input);
    53. return 0;
    54. //如果while 后面为0,程序就会自动退出游戏
    55. //非0 1就打印扫雷 其他值则重新打印菜单让用户选择
    56. }

     

    🌻今天的扫雷游戏就分享到这里啦~🌻

    🌻喜欢就一键三连支持一下吧♥~🌻

    🌻附上今天的日落图☺️🌻

    🌻谢谢家人们!🌻

  • 相关阅读:
    SpringBoot 整合 Minio 实现 文件上传
    【PTA-训练day8】L2-020 功夫传人 + L1-032 Left-pad
    最新 IntelliJ IDEA 旗舰版和社区版下载安装教程(图解)
    Nginx网络服务三-----(三方模块和内置变量)
    JDBC封装查询单个和查询多个
    深入理解Java IO流(第二篇)
    【医学】基于Matlab实现 3-D 内表面轴细化算法构建骨架模型
    Spring高手之路16——解析XML配置映射为BeanDefinition的源码
    jmeter性能测试常见的一些问题
    docker jenkins 安装配置
  • 原文地址:https://blog.csdn.net/Aileenvov/article/details/133109952