当前位置:   article > 正文

C/C++​​ - 扫雷​​_扫雷c++

扫雷c++

​​​​扫雷

        效果如上,本文用C/C++ 实现一下扫雷游戏,C++主要用cout 函数用来代替printf, 其他用C的结构体及函数等实现。

一、实现思路:

进入游戏,获取玩家输入

  1. 判断是否为雷:是,设置雷为点开;否,自动点开每个非雷区;
  2. 判断是否满足条件:1.雷被点开,输;2.当前剩下格子数等于总雷数 N,赢;3.都不满足继续游戏

函数

  • menu函数:获取玩家输入。
  • game函数操控进行一把游戏的整体逻辑。
  • ini 函数:函数初始化并设置随机雷。
  • show 函数:打印雷盘。
  • Click :函数玩家点击。(实际是获取输入坐标XD)
  • isOver 函数:判断游戏是否结束。
  • extend 函数:递归扩展非雷区。
  • cntBombs 函数 :雷区给周围区计数。

变量

Board  结构体 :用来存每一格的属性(包含是否点击,周围雷数)

        Bombs : -1表示当前格子炸弹>=0即为周围8格炸弹数

        isClick: 1表示点开,0表示未点开

  1. typedef struct Board
  2. {
  3. int Bombs;
  4. bool isClick;
  5. }Board;

二、代码

        1.头文件game.h 用来定义一些宏变量,声明函数,结构体。

  1. #pragma once
  2. #define ROW 10
  3. #define COL 10
  4. #define n 10 //炸弹数
  5. #define WIN 1
  6. #define LOSE -1
  7. #define SPACE_Y " | "
  8. #define SPACE_X "——-"
  9. #define SPACE " "
  10. #include <iostream>
  11. using namespace std;
  12. typedef struct Board
  13. {
  14. int Bombs;
  15. bool isClick;
  16. }Board;
  17. void ini(Board board[ROW][COL], int N, int row, int col);//N为炸弹数
  18. void show(Board board[ROW][COL], int row, int col);
  19. void Click(Board board[ROW][COL], int& x, int& y, int row, int col,int& left_cell);//输入的坐标,剩余格子都需要外部保存
  20. int isOver(Board board[ROW][COL], int x, int y, int left_cell, int N);
  21. void extend(Board board[ROW][COL], int x, int y, int row, int col, int& left_cell);
  22. void cntBombs(Board board[ROW][COL], int x, int y, int row, int col);

        2.menu函数

  1. void menu() {
  2. int input;
  3. do {
  4. cout << "1.Start game"<<endl<<"0.Quit game"<<endl;
  5. cin >> input;
  6. switch (input)
  7. {
  8. case 1:
  9. game();
  10. break;
  11. default:
  12. break;
  13. }
  14. } while (input);
  15. }

        3.game函数

                局部变量 用了 left_cells 表示剩余格子数,x ,y 表示输入坐标,res为游戏结果用来判定

                用{0}给结构体数组board [ROW][COL] 初始化。

  1. void game() {
  2. //每把设置一个新时间种子
  3. srand(time(NULL));
  4. //局部变量
  5. int x, y;//输入坐标
  6. int res;//结果
  7. int left_cells = ROW * COL;//记录当前剩余格子
  8. //初始化
  9. Board board[ROW][COL] = { 0 };
  10. ini(board, n, ROW, COL);
  11. show(board,ROW,COL);
  12. //玩家回合
  13. do {
  14. Click(board,x,y, ROW, COL,left_cells);
  15. show(board, ROW, COL);
  16. res = isOver(board, x, y, left_cells, n);
  17. } while (!res);//游戏未结束时循环
  18. switch (res)
  19. {
  20. case 1:
  21. cout << " WIN ! !" << endl;
  22. break;
  23. case -1:
  24. cout<<" BOOM ! ! !"<<endl;
  25. break;
  26. //如果想在结束后展现所有炸弹,需要一开始记录一串炸弹坐标的数组
  27. default:
  28. break;
  29. }
  30. }

        4.ini函数 

                初始化布局 X * Y,并随机生成 N 个炸弹,以当前雷为参数,cntBombs累加周围炸弹

  1. //随机生成{ N }个炸弹布局{ X * Y}根据炸弹计算每格数字 (初始化)
  2. void ini(Board board[ROW][COL], int N,int row,int col) {
  3. //全部 memset为0,直接在外初始化了,貌似不太好
  4. while (N--) {
  5. //随机生成N个 x,y 雷 循环判断是否重复雷
  6. int x, y;
  7. do {
  8. x = rand() % ROW;
  9. y = rand() % COL;
  10. } while (board[x][y].Bombs == -1);//如果随机到的xy是有炸弹的,重新生成
  11. //没有重复 设置为雷
  12. board[x][y].Bombs = -1;
  13. //炸弹周围格子++
  14. cntBombs(board, x, y, row, col);
  15. }
  16. }

        5.show函数

  1. //打印(渲染)
  2. void show(Board board[ROW][COL],int row, int col) {
  3. system("cls");
  4. for (int i = -1; i < row; i++) {//-1是为了打印轴
  5. for (int j = -1; j < col; j++) {
  6. //打印横纵轴
  7. //打印首行横坐标 第j列
  8. if (i==-1) {
  9. if (j==-1) {
  10. cout << " ";//开头空两格
  11. continue;
  12. }
  13. cout << SPACE << j << SPACE;//输出横坐标
  14. continue;
  15. }
  16. //当j已经不是第一行,每行首打印纵坐标 第i行
  17. if (j == -1) {
  18. cout << i << " ";
  19. continue;
  20. }
  21. //打印横纵轴↑
  22. //判断是否点击 打印
  23. Board tmpBoard= board[i][j];
  24. if (tmpBoard.isClick) {
  25. switch (tmpBoard.Bombs)
  26. {
  27. case -1://炸弹
  28. cout <<SPACE_Y<< "X" << SPACE_Y;
  29. break;
  30. case 0://周围没有炸弹
  31. cout << SPACE_Y << " " << SPACE_Y;
  32. break;
  33. default:
  34. cout << SPACE_Y << tmpBoard.Bombs <<SPACE_Y;
  35. break;
  36. }
  37. }
  38. else
  39. cout << SPACE_Y << "*"<<SPACE_Y;
  40. }
  41. cout << endl<< endl;
  42. }
  43. }

        click函数

                玩家输入一个坐标,直到合法,非炸弹就展开,雷设置点开。

  1. // 玩家点击
  2. void Click(Board board[ROW][COL],int &x,int &y, int row, int col,int& left_cell) {
  3. //是否合法循环判断
  4. while (1) {
  5. cin >> y>> x;//实际游戏x,y是反的,所以调了顺序
  6. //判断y,x是否合法
  7. if (x <0 || x >= row || y < 0 || y >= col) {
  8. cout << "非法坐标"<<endl;
  9. continue;
  10. }
  11. if (board[x][y].isClick) {
  12. cout << "重复了" << endl;
  13. continue;
  14. }
  15. break;
  16. }
  17. //合法,当点击的坐标不是雷时,扩展
  18. if (board[x][y].Bombs != -1)
  19. extend(board, x, y, row, col,left_cell);
  20. //是雷,把雷点开
  21. else
  22. board[x][y].isClick = 1;
  23. }

        isOver函数

  1. //判定
  2. int isOver(Board board[ROW][COL], int x, int y,int left_cell,int N) {
  3. //输了,雷格子的状态为点击
  4. if (board[x][y].isClick == 1 && board[x][y].Bombs == -1)
  5. return LOSE;
  6. //赢了,剩余格子数等于雷的数量——需要提前统计剩余格子数
  7. if (left_cell == N)
  8. return WIN;
  9. //没输没赢,继续进行
  10. return 0;
  11. }

        extend函数

                递归打开非雷区,参考了c语言扫雷递归展开非雷位置tangke121的博客-CSDN博客

  1. //扩展非雷
  2. void extend(Board board[ROW][COL],int x,int y, int row, int col,int &left_cell) {
  3. //因为是向外扩展的,有可能是炸弹,只有不是雷才能设置Click为1
  4. //每次迭代,看有无点击过;
  5. //不是炸弹就点开自己:有若干雷不扩展;周围0个雷时拓展;当自己是炸弹时 啥也不做
  6. //是否点击过,点过跳过
  7. if (board[x][y].isClick) return;
  8. //没点过,且不是雷
  9. if (board[x][y].Bombs >= 0) {
  10. board[x][y].isClick = 1;
  11. left_cell--;//剩余减少一格
  12. //非雷向各方位拓开
  13. if (!board[x][y].Bombs) {
  14. for (int i = x - 1; i <= x + 1; i++) {
  15. for (int j = y - 1; j <= y + 1; j++) {
  16. if (i >= 0 && i < row && j>=0 && j < col)
  17. extend(board, i, j, row, col,left_cell);
  18. }
  19. }
  20. }
  21. }
  22. //全部情况都跳过,说明是雷,啥也不用做
  23. }

        cntBombs函数

                让雷的周围格子增加雷计数,遍历周围8个让其属性Bombs自增1。

  1. //计数周围的雷
  2. void cntBombs(Board board[ROW][COL], int x, int y, int row, int col) {
  3. for(int i = x - 1; i <= x + 1; i++) {
  4. for (int j = y - 1; j <= y + 1; j++) {
  5. if (i == x && j == y) continue;//跳过自己 不能让自己++
  6. if (i >= 0 && i < row && j >= 0 && j < col)//界限判断
  7. board[i][j].Bombs++;//每个周围++
  8. }
  9. }
  10. }

三、结果

         这里我把雷数设置成了2,方便演示。

WIN

LOSE

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

闽ICP备14008679号