当前位置:   article > 正文

C语言扫雷(递归展开)(详细注释)(完整代码)_扫雷代码

扫雷代码

目录

一、功能实现

1.雷盘初始化与打印

雷盘定义

初始化雷盘

打印雷盘

随机布置雷

2.玩家排查雷

获取坐标周围雷数

递归展开

胜负判断

显示雷位置

二、游戏试玩

三、游戏完整代码

game.h 

test.c

game.c


      扫雷大家应该都知道,翻开一个格子,显示的数字就是周围 8 格所含的雷数。例如,红色框框里的1周围8格就只有一个雷。

      我们定义两个数组来实现,show数组存放玩家看到的棋盘,mine数组存放隐藏的雷盘

这两个数组搭配使用,就能计算某个位置周围的雷数,并且修改show数组来显示这个位置的雷数。

但是如果计算边缘格子周围的雷数时,数组会越界

我们只要在周围留一圈就能解决这个问题

如下图所示,假设我们要玩 9x9 的大小,我们的数组大小就定义为 11x11

一、功能实现

1.雷盘初始化与打印

  • 雷盘定义

  • 初始化雷盘

初始化show,mine两个数组,show 存放 '*' , mine存放 '0'

  1. void init_board(char board[ROWS][COLS], int rows, int cols, char set)
  2. {
  3. int i = 0;
  4. int j = 0;
  5. for (i = 0; i < rows; i++)
  6. {
  7. for (j = 0; j < cols; j++)
  8. {
  9. board[i][j] = set;
  10. }
  11. }
  12. }
  • 打印雷盘

  1. //打印show雷盘
  2. void display_board(char board[ROWS][COLS], int row, int col)
  3. {
  4. int i = 0;
  5. int j = 0;
  6. //这里打印上面一行数字
  7. printf("|");
  8. for (j = 0; j <= col; j++)
  9. {
  10. printf(" %-2d |", j);
  11. }
  12. printf("\n");
  13. for (i = 1; i <= row; i++)
  14. {
  15. printf("|");
  16. for (j = 0; j <= col; j++)
  17. {
  18. printf("----|");//打印两行之间的分割线
  19. }
  20. printf("\n");
  21. printf("|");
  22. printf(" %-2d |", i);//打印左边一列数字
  23. for (j = 1; j <= col; j++)
  24. {
  25. printf(" %2c |",board[i][j]);//打印show数组
  26. }
  27. printf("\n");
  28. }
  29. }

 效果图:

  • 随机布置雷

随机布置雷,将mine中的 '0' 改为 '1'

  1. //随机布置雷,在mine数组里随机设置COUNT个雷
  2. void set_mine(char mine[ROWS][COLS], int row, int col)
  3. {
  4. int count = 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'; //地雷设置为 '1'
  12. count--;
  13. }
  14. }
  15. }

2.玩家排查雷

  • 获取坐标周围雷数

计算该坐标在mine中 周围 '1'的个数

  1. //获取一个格子周围的雷数
  2. int get_mine_count(char mine[ROWS][COLS], int x, int y)
  3. {
  4. //mine 中存放的是字符'0' 和 '1'
  5. return (mine[x][y + 1] +
  6. mine[x - 1][y + 1] +
  7. mine[x - 1][y] +
  8. mine[x - 1][y - 1] +
  9. mine[x][y - 1] +
  10. mine[x + 1][y - 1] +
  11. mine[x + 1][y] +
  12. mine[x + 1][y + 1] - 8 * '0');
  13. }
  • 递归展开

我们玩扫雷时,翻开一个格子会展开一片,如上图所示,翻开黑格子,展开紫色区域

我们可以用递归来实现

当这个格子周围没雷时,显示空白,然后继续递归它周围的八个格子

有雷时,显示雷数,停止递归。

  1. //递归展开
  2. void expand(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y, int* win)
  3. {
  4. if (x >= 1 && x <= ROW && y >= 1 && y <= COL) //限制在棋盘内展开,防止越界
  5. {
  6. int count = get_mine_count(mine, x, y);//获取雷数
  7. if (count == 0) //四周没雷,进入递归展开
  8. {
  9. show[x][y] = ' ';//四周没雷的改为 空格 ' '
  10. int i = 0;
  11. //向四周共8个位置递归
  12. for (i = x - 1; i <= x + 1; i++)
  13. {
  14. int j = 0;
  15. for (j = y - 1; j <= y + 1; j++)
  16. {
  17. //只对 '*' 进行展开,防止死循环
  18. if (show[i][j] == '*')
  19. {
  20. expand(mine, show, i, j, win);
  21. }
  22. }
  23. }
  24. }
  25. else //四周有雷显示雷数
  26. {
  27. show[x][y] = count + '0';
  28. }
  29. //记录展开的数量
  30. (*win)++;
  31. }
  32. }
  • 胜负判断

这里定义了一个 win 来表示翻开的格子数,当翻开的格子数量 = 行 x 列 - 雷数 ===> 排雷成功。

  1. //玩家排查雷
  2. void find_mine(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 < row * col - COUNT)//当翻开的格子数量 = 行 x 列 - 雷数 ===> 排雷成功
  8. {
  9. printf("请输入要排查的坐标:>");
  10. scanf("%d %d", &x, &y);
  11. //检查坐标是否越界
  12. if (x >= 1 && x <= row && y >= 1 && y <= col)
  13. {
  14. //检查坐标是否排查过了
  15. if (show[x][y] == '*')
  16. {
  17. if (mine[x][y] == '1')
  18. {
  19. system("cls");
  20. show_mine(mine, show, row, col);
  21. printf("-----------很遗憾,你被炸死了-----------\n");
  22. break;
  23. }
  24. else
  25. {
  26. //展开
  27. expand(mine, show, x, y, &win);
  28. system("cls");//清屏
  29. display_board(show, row, col);
  30. printf("--------------还需翻开%d格--------------\n", row * col - COUNT - win);
  31. }
  32. }
  33. else
  34. {
  35. printf("该坐标已排查,请重新输入\n");
  36. }
  37. }
  38. else
  39. {
  40. printf("坐标非法,请重新输入\n");
  41. }
  42. }
  43. if (win == row* col - COUNT)
  44. {
  45. system("cls");
  46. show_mine(mine, show, row, col);//展示地雷位置
  47. printf("------------恭喜你,排雷成功-----------\n");
  48. }
  49. }
  • 显示雷位置

  1. //显示地雷位置,排雷成功或被炸死后 向玩家展示地雷位置
  2. void show_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
  3. {
  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 (mine[i][j] == '1')
  11. {
  12. show[i][j] = '@'; //将地雷改成 '@'
  13. }
  14. }
  15. }
  16. display_board(show, row, col); //打印
  17. }

二、游戏试玩

游戏设置    10 行 ,10 列  ,15个雷

 排雷成功

 排雷失败

三、游戏完整代码

game.h 

头文件   常量定义,函数声明

  1. #pragma once
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <time.h>
  5. //玩家看到的大小
  6. #define ROW 10
  7. #define COL 10
  8. //实际数组大小,防止越界
  9. #define ROWS ROW+2
  10. #define COLS COL+2
  11. #define COUNT 10//雷数
  12. //初始化棋盘
  13. void init_board(char board[ROWS][COLS], int rows, int cols, char set);
  14. //打印棋盘
  15. void display_board(char board[ROWS][COLS], int row, int col);
  16. //随机布置雷
  17. void set_mine(char mine[ROWS][COLS], int row, int col);
  18. //获取坐标周围地雷数
  19. int get_mine_count(char mine[ROWS][COLS], int x, int y);
  20. //显示地雷位置并打印
  21. void show_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
  22. //递归展开
  23. void expand(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y, int* win);
  24. //排查雷
  25. void find_mine(char mine[ROWS][COLS],char show[ROWS][COLS],int row, int col);

test.c

游戏测试文件

  1. #define _CRT_SECURE_NO_WARNINGS 1
  2. #include "game.h"
  3. //菜单
  4. void menu()
  5. {
  6. printf("======================\n");
  7. printf("|| 扫雷 ||\n");
  8. printf("|| 1-开始游戏 ||\n");
  9. printf("|| 0-退出游戏 ||\n");
  10. printf("======================\n");
  11. }
  12. //游戏流程
  13. void game()
  14. {
  15. char mine[ROWS][COLS] = { 0 };//存放布置的雷(隐藏的)
  16. char show[ROWS][COLS] = { 0 };//存放排查的雷(游戏看到的)
  17. //初始化棋盘
  18. //mine 全为'0'
  19. //show 全为'*'
  20. init_board(mine, ROWS, COLS, '0');
  21. init_board(show, ROWS, COLS, '*');
  22. //随机布置雷
  23. set_mine(mine,ROW,COL);
  24. //打印棋盘
  25. //display_board(mine, ROW, COL);
  26. display_board(show, ROW, COL);
  27. printf("--------------需要翻开%d格--------------\n", ROW * COL - COUNT);
  28. //排查雷(游戏开始)
  29. find_mine(mine, show, ROW, COL);
  30. }
  31. int main()
  32. {
  33. int input = 0;
  34. srand((unsigned int)time(NULL));
  35. do
  36. {
  37. menu();
  38. printf("请选择:>");
  39. scanf("%d", &input);
  40. switch (input)
  41. {
  42. case 1:
  43. system("cls");
  44. game();
  45. break;
  46. case 0:
  47. printf("退出游戏\n");
  48. break;
  49. default:
  50. printf("选择错误,请重新输入\n");
  51. break;
  52. }
  53. } while (input);
  54. return 0;
  55. }

game.c

函数定义

  1. #define _CRT_SECURE_NO_WARNINGS 1
  2. #include "game.h"
  3. //将两个数组初始化,show全为'*' ,mine全为'0'
  4. void init_board(char board[ROWS][COLS], int rows, int cols, char set)
  5. {
  6. int i = 0;
  7. int j = 0;
  8. for (i = 0; i < rows; i++)
  9. {
  10. for (j = 0; j < cols; j++)
  11. {
  12. board[i][j] = set;
  13. }
  14. }
  15. }
  16. //打印show棋盘
  17. void display_board(char board[ROWS][COLS], int row, int col)
  18. {
  19. int i = 0;
  20. int j = 0;
  21. //这里打印上面一行数字
  22. printf("|");
  23. for (j = 0; j <= col; j++)
  24. {
  25. printf(" %-2d |", j);
  26. }
  27. printf("\n");
  28. for (i = 1; i <= row; i++)
  29. {
  30. printf("|");
  31. for (j = 0; j <= col; j++)
  32. {
  33. printf("----|");//打印两行之间的分割线
  34. }
  35. printf("\n");
  36. printf("|");
  37. printf(" %-2d |", i);//打印左边一列数字
  38. for (j = 1; j <= col; j++)
  39. {
  40. printf(" %2c |",board[i][j]);//打印show数组
  41. }
  42. printf("\n");
  43. }
  44. }
  45. //随机设置雷,在mine数组里随机设置COUNT个雷
  46. void set_mine(char mine[ROWS][COLS], int row, int col)
  47. {
  48. int count = COUNT;
  49. while (count)
  50. {
  51. int x = rand() % row + 1;
  52. int y = rand() % col + 1;
  53. if (mine[x][y] == '0')
  54. {
  55. mine[x][y] = '1'; //地雷设置为 '1'
  56. count--;
  57. }
  58. }
  59. }
  60. //获取一个格子周围的雷数
  61. int get_mine_count(char mine[ROWS][COLS], int x, int y)
  62. {
  63. //mine 中存放的是字符'0' 和 '1'
  64. return (mine[x][y + 1] +
  65. mine[x - 1][y + 1] +
  66. mine[x - 1][y] +
  67. mine[x - 1][y - 1] +
  68. mine[x][y - 1] +
  69. mine[x + 1][y - 1] +
  70. mine[x + 1][y] +
  71. mine[x + 1][y + 1] - 8 * '0');
  72. }
  73. //递归展开
  74. void expand(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y, int* win)
  75. {
  76. if (x >= 1 && x <= ROW && y >= 1 && y <= COL) //限制在棋盘内展开,防止越界
  77. {
  78. int count = get_mine_count(mine, x, y);//获取雷数
  79. if (count == 0) //四周没雷,进入递归展开
  80. {
  81. show[x][y] = ' ';//四周没雷的改为 空格 ' '
  82. int i = 0;
  83. //向四周共8个位置递归调用
  84. for (i = x - 1; i <= x + 1; i++)
  85. {
  86. int j = 0;
  87. for (j = y - 1; j <= y + 1; j++)
  88. {
  89. //只对 '*' 进行展开,防止死循环
  90. if (show[i][j] == '*')
  91. {
  92. expand(mine, show, i, j, win);
  93. }
  94. }
  95. }
  96. }
  97. else //四周有雷显示雷数
  98. {
  99. show[x][y] = count + '0';
  100. }
  101. //记录展开的数量
  102. (*win)++;
  103. }
  104. }
  105. //显示地雷位置,排雷成功或被炸死后 向玩家展示地雷位置
  106. void show_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
  107. {
  108. int i = 0;
  109. for (i = 1; i <= row; i++)
  110. {
  111. int j = 0;
  112. for (j = 1; j <= COL; j++)
  113. {
  114. if (mine[i][j] == '1')
  115. {
  116. show[i][j] = '@'; //将地雷改成 '@'
  117. }
  118. }
  119. }
  120. display_board(show, row, col); //打印
  121. }
  122. //玩家排查雷
  123. void find_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
  124. {
  125. int x = 0;
  126. int y = 0;
  127. int win = 0;//初始化 翻开的格子数量
  128. while (win < row * col - COUNT)//当翻开的格子数量 = 行 x 列 - 雷数 ===> 排雷成功
  129. {
  130. printf("请输入要排查的坐标:>");
  131. scanf("%d %d", &x, &y);
  132. //检查坐标是否越界
  133. if (x >= 1 && x <= row && y >= 1 && y <= col)
  134. {
  135. //检查坐标是否排查过了
  136. if (show[x][y] == '*')
  137. {
  138. if (mine[x][y] == '1')
  139. {
  140. system("cls");
  141. show_mine(mine, show, row, col);
  142. printf("-----------很遗憾,你被炸死了-----------\n");
  143. break;
  144. }
  145. else
  146. {
  147. //展开
  148. expand(mine, show, x, y, &win);
  149. system("cls");//清屏
  150. display_board(show, row, col);
  151. printf("--------------还需翻开%d格--------------\n", row * col - COUNT - win);
  152. }
  153. }
  154. else
  155. {
  156. printf("该坐标已排查,请重新输入\n");
  157. }
  158. }
  159. else
  160. {
  161. printf("坐标非法,请重新输入\n");
  162. }
  163. }
  164. if (win == row* col - COUNT)
  165. {
  166. system("cls");
  167. show_mine(mine, show, row, col);//展示地雷位置
  168. printf("------------恭喜你,排雷成功-----------\n");
  169. }
  170. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/602960
推荐阅读
相关标签
  

闽ICP备14008679号