当前位置:   article > 正文

趣味小游戏——扫雷(优化版)_扫雷小游戏代码优化

扫雷小游戏代码优化

目录

一.前言  

二.游戏主体框架

三.游戏内部实现

1.给出一个ROW*COL的棋盘

2.初始化两棋盘

3.随机生成雷

4.反馈信息

5.排雷过程

6.优化部分

四.结语


一.前言  

  这里是趣味小游戏第二篇,扫雷想必也是大家以前电脑上必备的休闲游戏,那么今天我就来带大家用代码的方式来回忆并实现它吧!

二.游戏主体框架

  要实现游戏我们首先要搭建出一个主体游戏框架。

  1. #include <stdio.h>
  2. void menu()
  3. {
  4. printf("********************\n");
  5. printf("***** 1.play *****\n");
  6. printf("***** 0.exit *****\n");
  7. printf("********************\n");
  8. }
  9. void test()
  10. {
  11. int input = 0;
  12. do
  13. {
  14. menu();//给出一个游戏的开始菜单
  15. printf("欢迎来到扫雷游戏\n");
  16. printf("输入1开始游戏,输入0退出游戏\n");
  17. printf("请输入:");
  18. scanf("%d", &input);
  19. switch (input)//对于不同输入值给出不同结果
  20. {
  21. case 1:
  22. game();//由此进入游戏
  23. break;
  24. case 0:
  25. printf("游戏已退出\n");//由此退出游戏
  26. break;
  27. default:
  28. printf("输入错误,请重新输入:");//输入其他值时给出反馈,增强代码健壮性
  29. break;
  30. }
  31. } while (input);//输入为真(1)时则进入do里的循环输入为假(0)时即退出循环
  32. }
  33. int main()
  34. {
  35. test();//主体内容
  36. return 0;
  37. }

三.游戏内部实现

  在搭建好主体后,我们就进入游戏实现阶段。

  1. #define ROW 9
  2. #define COL 9
  3. #define ROWS ROW+2
  4. #define COLS COL+2
  5. void game()
  6. {
  7. //1.给出一个ROW*COL的棋盘
  8. char mine[ROWS][COLS];
  9. char show[ROWS][COLS];
  10. //2.初始化两棋盘
  11. IniBoard(mine, ROWS, COLS, '0');
  12. IniBoard(show, ROWS, COLS, '*');
  13. //3.随机生成雷
  14. SetMine(mine, ROW, COL);
  15. //4.反馈信息
  16. //PrintBoard(mine, ROW, COL);
  17. PrintBoard(show, ROW, COL);
  18. //5.排雷过程
  19. FindMine(mine, show, ROW, COL);
  20. }

1.给出一个ROW*COL的棋盘

我们在这里假定ROW=COL=9,那么目标就是产生这样一个9*9的棋盘。

  

 而在我们统计一个格子周围雷的个数时,会出现一些格子统计雷的数量比较困难(如9 9坐标),因此我们将其行和列拓宽两行得到如下棋盘

 因此我们便创建两个11*11的二维数组,一个用来作为生成雷的数组(mine),一个用来作为玩家看与猜测的数组(show)。

2.初始化两棋盘

  在成功生成两棋盘后,我们对其分别进行初始化(即将所有的元素化成同一元素)。

在此,我们将mine数组初始化为'0'(后面会解释),将show数组初始化为'*'(方便玩家观察该数组)。因此,我们编写一个函数来实现此目的。

  1. void IniBoard(char board[ROWS][COLS], int row, int col, char n)
  2. {
  3. int i = 0;
  4. for (i = 0; i < row; i++)//得到每行数据
  5. {
  6. int j = 0;
  7. for (j = 0; j < col; j++)//得到每列数据
  8. {
  9. board[i][j] = n;//将每个元素都转变成字符n
  10. }
  11. }
  12. }

3.随机生成雷

  在初始化两数组后,我们便开始在mine数组中随机布置雷。

(注意:可供我们操作的范围为1 1——9 9的范围内,因此雷的生成位置也应该处于1 1——9 9之间)

  1. #define EASY 15
  2. //简单模式的雷的个数
  3. void SetMine(char mine[ROWS][ROWS], int row, int col)
  4. {
  5. srand((unsigned int)time(NULL));//用时间戳来创造伪随机数
  6. int count = EASY;
  7. while(count)
  8. {
  9. int x = rand() % row + 1;
  10. int y = rand() % col + 1;//因为行数与列数确定,因此需要保证x,y都处于[1,9]这个区间
  11. if (mine[x][y] == '0')//判断该位置是否已经被布置了雷
  12. {
  13. mine[x][y] = '1';
  14. count--;//布置成功则使需要布置的雷的个数减少一个
  15. }
  16. }
  17. }

4.反馈信息

  在游戏进行的过程中,我们作为玩家需要不断地知道自己输入坐标后的结果怎么样,所以便离不开显示棋盘这一操作,因此,我们便设计一个函数来进行这个操作。

  1. void PrintBoard(char board[ROWS][COLS], int row, int col)
  2. {
  3. int i = 0;
  4. int j = 0;
  5. printf("---------扫雷游戏--------\n");//上分割行
  6. for (j = 0; j <= col; j++)
  7. {
  8. printf("%d ", j);//提供一个精准的定位信息
  9. }
  10. printf("\n");
  11. for (i = 1; i <= row; i++)
  12. {
  13. printf("%d ", i);
  14. for (j = 1; j <= col; j++)
  15. {
  16. printf("%c ", board[i][j]);//打印每个元素
  17. }
  18. printf("\n");
  19. }
  20. printf("---------扫雷游戏--------\n");//下分割行
  21. }

我们用它来打印show数组,得到如下的效果

5.排雷过程

  在看到棋盘后,想必大家已经手痒痒了吧,别急,让我来带各位进入正戏环节。

还是老样子,我们编写一个函数来实现这一步骤。

  1. void Change(char show[ROWS][COLS], char mine[ROWS][COLS], int row, int col)
  2. {
  3. int i = 1;
  4. for (i = 1; i <= row; i++)
  5. {
  6. int j = 1;
  7. for (j = 1; j <= col; j++)
  8. {
  9. if (mine[i][j] == '1')
  10. {
  11. show[i][j] = '#';//将mine棋盘中的雷表现为show数组中的#
  12. }
  13. }
  14. }
  15. }
  16. int MineCount(char board[ROWS][COLS], int x, int y)
  17. {
  18. return board[x-1][y-1] + board[x-1][y] + board[x-1][y+1] + board[x][y-1]
  19. + board[x][y+1] + board[x+1][y-1] + board[x+1][y] + board[x+1][y+1] -8*'0';//根据ASCII码表将所有1的个数相加并返回
  20. }
  21. void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
  22. {
  23. printf("输入排查位置(如5 5)\n");
  24. int count = ROW * COL - EASY;//用count代表场上除去雷的剩余位置
  25. while(1)//无法具体确定判断条件,所以用1作为条件,后面完成行为后用break跳出
  26. {
  27. int x = 0;
  28. int y = 0;
  29. printf("请输入你想排查的坐标\n");
  30. printf("请输入:");
  31. scanf("%d %d", &x, &y);
  32. if (x >= 1 && x <= row && y >= 1 && y <= col)//判断输入的位置是否在棋盘内,如果不在内就反馈给玩家
  33. {
  34. if (mine[x][y] == '1')
  35. {
  36. printf("很遗憾,你碰到了炸弹,游戏结束\n");
  37. Change(show, mine, row, col);//在判定玩家已输的情况下,将情况反映到show数组上
  38. PrintBoard(show, row, col);//让玩家知道自己如何输的
  39. break;
  40. }
  41. else if (show[x][y] != '*')//如果玩家手误,可以借此重新输入
  42. {
  43. printf("该位置已被排查过,请重新输入\n");
  44. }
  45. else
  46. {
  47. int ret = MineCount(mine, x, y);//将该位置周围的雷的数量做一个统计
  48. show[x][y] = '0' + ret;//将该数字通过ASCII码表还原成对应字符
  49. PrintBoard(show, row, col);//将结果反馈给玩家
  50. count--;
  51. }
  52. }
  53. else
  54. {
  55. printf("输入坐标非法,请重新输入\n");
  56. }
  57. if (count == 0)//当除雷以外的剩余个数为0时,那么棋盘上只剩下雷,即玩家获胜
  58. {
  59. printf("恭喜你,排雷成功\n");
  60. PrintBoard(mine, row, col);//将最后结果反馈给玩家
  61. break;
  62. }
  63. }
  64. }

6.优化部分

在经过了上述流程后,虽然我们体验到了扫雷游戏,但是总感觉玩起来不是很方便,此时我们的心头便会冒出一些想法:可不可以在周围有0个雷的时候直接展开一片?在排查完雷之后可不可以自己标记雷的位置?在标记后可不可以显示自己主观认为的剩余的雷的个数?

答案是:当然!

我们先对展开方面进行优化

 我们在反馈前先构建一个Cls函数进行对0的清除与展开,即改为如下这样

  1. else
  2. {
  3. int ret = MineCount(mine, x, y);//将该位置周围的雷的数量做一个统计
  4. show[x][y] = '0' + ret;//将该数字通过ASCII码表还原成对应字符
  5. Cls(mine, show, row, col, x, y);
  6. PrintBoard(show, row, col);//将结果反馈给玩家
  7. count--;
  8. }

下面具体实现Cls函数

  1. void Cls(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col, int x, int y)
  2. {
  3. if (show[x][y] == '0')//如果此元素已经为'0'才进入此函数
  4. {
  5. show[x][y] = ' ';//将其修改为' '便于观查
  6. int i = x - 1;
  7. for (; i <= x + 1; i++)
  8. {
  9. int j = y - 1;
  10. for (; j <= y + 1; j++)//得到该元素的从左上到右下的全部下标
  11. {
  12. if (show[i][j] == ' ')//如果已经有元素被替换为' ',则无需再次进行下面的操作
  13. {
  14. continue;
  15. }
  16. if (i >= 1 && i <= row && j >= 1 && j <= col)//判断该元素是否在棋盘内
  17. {
  18. if (show[i][j] != '*')//如果该元素不是'*',即已经被赋值了数字就无需进行下面的操作
  19. {
  20. continue;
  21. }
  22. int ret = MineCount(mine, i, j);//对该元素进行判定
  23. show[i][j] = '0' + ret;
  24. Cls(mine, show, row, col, i, j);//不断迭代,直到不再出现0或数字为止
  25. }
  26. }
  27. }
  28. }
  29. }

 成功展开后,我们再来对标记进行操作与优化

  1. else
  2. {
  3. int ret = MineCount(mine, x, y);//将该位置周围的雷的数量做一个统计
  4. show[x][y] = '0' + ret;//将该数字通过ASCII码表还原成对应字符
  5. Cls(mine, show, row, col, x, y);
  6. PlayerJudge(show, row, col);
  7. PrintBoard(show, row, col);//将结果反馈给玩家
  8. count--;
  9. }

同样的我们编写一个PlayerJduge函数来实现此操作

  1. void Judge(char show[ROWS][COLS], int row, int col)
  2. {
  3. printf("坐标操作:\n");
  4. printf("1 - 不确定是否为雷\n");
  5. printf("2 - 确定是雷\n");//根据ASCII码表将1和2转换成对应的?与#
  6. printf("3 - 取消标记\n");
  7. printf("请输入你想标记的坐标(如5 5) :\n");
  8. int x = 0;
  9. int y = 0;
  10. while(1)
  11. {
  12. printf("请输入:");
  13. scanf("%d %d", &x, &y);
  14. printf("请输入你想对该坐标进行的操作\n");
  15. int c = 0;
  16. scanf("%d", &c);
  17. if (show[x][y] == '*')
  18. {
  19. if (c == 1)
  20. {
  21. c = 63;//将1转换成?所对应的ASCII值
  22. }
  23. if (c == 2)
  24. {
  25. c = 35;//将2转换成#所对应的ASCII值
  26. }
  27. char ch = c;
  28. show[x][y] = ch;
  29. printf("标记成功!\n");//给出反馈
  30. PrintBoard(show, row, col);
  31. break;//结束本次标记
  32. }
  33. else if (show[x][y] == '?' || show[x][y] == '#' && c == 3)//如果输入3还要判断该元素是否已经被标记
  34. {
  35. show[x][y] = '*';
  36. printf("取消成功!\n");//给出反馈
  37. PrintBoard(show, row, col);
  38. break;
  39. }
  40. else
  41. {
  42. printf("输入位置不合法,请重新输入\n");//输入不合理
  43. }
  44. }
  45. }
  46. void PlayerJudge(char show[ROWS][COLS], int row, int col)
  47. {
  48. int m = 0;
  49. printf("请问你是否想标记某位置\n");
  50. printf("是:1 否:0\n");
  51. do
  52. {
  53. printf("请输入(如已标记完毕请输入0,想继续标记请输入1):");//在进行完一次标记后,玩家需要确定是否进行下一次标记
  54. scanf("%d", &m);
  55. switch (m)
  56. {
  57. case 1:
  58. Judge(show, row, col);//具体实现标记操作
  59. break;
  60. case 0:
  61. break;
  62. default:
  63. printf("输入有误,请重新输入:\n");
  64. break;
  65. }
  66. } while (m);
  67. }

最后呢,我们再对雷量的剩余做一个LeaveMine函数来反馈

  1. else
  2. {
  3. int ret = MineCount(mine, x, y);//将该位置周围的雷的数量做一个统计
  4. show[x][y] = '0' + ret;//将该数字通过ASCII码表还原成对应字符
  5. Cls(mine, show, row, col, x, y);
  6. PlayerJudge(show, row, col);
  7. int res = LeaveMine(show, row, col);//show数组中#的个数
  8. printf("剩余雷量:%d\n", EASY - res);//反馈剩余的雷的个数
  9. PrintBoard(show, row, col);//将结果反馈给玩家
  10. count--;
  11. }

下面是具体的实现办法

  1. int LeaveMine(char show[ROWS][COLS], int row, int col)
  2. {
  3. int i = 1;
  4. int num = 0;
  5. for (i = 1; i <= row; i++)
  6. {
  7. int j = 1;
  8. for (j = 1; j <= col; j++)
  9. {
  10. if (show[i][j] == '#')//统计所有元素中#的个数
  11. {
  12. num++;
  13. }
  14. }
  15. }
  16. return num;//返回#的个数
  17. }

至此,我们便完成了扫雷游戏的优化!

四.结语

  以上就是扫雷游戏的全部实现过程了,希望各位程序员能够玩得开心,同时也希望能从本文中得到灵感与启发!路过的点个赞吧,谢谢!

声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号