C/【扫雷】

简介: C/【扫雷】

 **本文是用C语言写的扫雷小游戏———一个C语言前期寓教于乐的小游戏。

 


image.gif

目录

一.游戏菜单的创建

二.游戏实现的思路

1.初始化雷盘

2.打印雷盘

3.布置雷

4.显示周围雷数

5.标记和取消标记雷

6.周围雷数为零,展开

7.扫雷并判断输赢

 完整代码

game.h

game.c

text.c


一.游戏菜单的创建

在我们进入游戏时,首先出现的就应该是我们的菜单界面。

我们选择使用“菜单函数”menu()来实现这一功能,提高程序的可重复性,确保代码块的函数分块使用。

游戏菜单应该实现这几个功能:

    1. 游戏的进入
    2. 游戏的退出

    接下来是我们实现这一功能的代码:

    void menu()
    {
      printf("┌-----------------------------┐\n");
      printf("├**********1.扫雷*************┤\n");
      printf("├**********0.退出*************┤\n");
      printf("└-----------------------------┘\n");
    }

    image.gif

    menu 2()为小游戏的拓展 方便进行标记雷操作。

    void menu2()
    {
      printf("┌-----------------------------┐\n");
      printf("├**********1.排雷*************┤\n");
      printf("├**********2.标记*************┤\n");
      printf("├**********3.取消标记*********┤\n");
      printf("└-----------------------------┘\n");
    }

    image.gif

    二.游戏实现的思路

    测试的逻辑——test.c

    游戏的实现——game.h

    游戏函数的声明——game.c

    1.初始化雷盘

    void Init(char board[ROWS][COLS], int rows, int cols, char set)
    {
      int i = 0;
      for (i = 0; i < rows; i++)
      {
        int j = 0;
        for (j = 0; j < cols; j++)
        {
          board[i][j] = set;
        }
      }
    }

    image.gif

    2.打印雷盘

    void DisplayBoard(char board[ROWS][COLS], int row, int col)
    {
      system("cls");//清屏操作,使界面更简洁
      printf("---------扫雷----------\n");
      int i = 0;
      int j = 0;
      for (j = 0; j <= col; j++)//打印列
      {
        printf("%d ", j);
      }
      printf("\n");
      for (i = 1; i <= row; i++)
      {
        printf("%d ", i);//打印行
        for (j = 1; j <= col; j++)
        {
          printf("%c ", board[i][j]);
        }
        printf("\n");
      }
      printf("---------扫雷----------\n");
    }

    image.gif

    3.布置雷

    void SetMine(char mine[ROWS][COLS], int row, int col)
    {
      int count = Easy_Count;
      while (count)
      {
        int i = rand() % row + 1;
        int j = rand() % col + 1;
        if (mine[i][j] == '0')
        {
          mine[i][j] = '1';
          count--;
        }
      }
    }

    image.gif

    4.显示周围雷数

    //法一:逐个遍历
    static int get_mine_count(char mine[ROWS][COLS], int x, int y)
    {
      return mine[x - 1][y] + mine[x - 1][y - 1] +
        mine[x - 1][y + 1] + mine[x][y - 1] +
        mine[x][y + 1] + mine[x + 1][y] +
        mine[x + 1][y - 1] + mine[x + 1][y + 1] - 8 * '0';
    }

    image.gif

    //法二:循环遍历
    static int get_mine_count2(char mine[ROWS][COLS], int x, int y)
    {
      int i = 0;
      int count = 0;
      for (i = -1; i <= 1; i++)
      {
        int j = 0;
        for (j = -1; j <= 1; j++)
        {
          if (mine[x + i][y + j] == '1')
            count++;
        }
      }
      return count;
    }

    image.gif

    5.标记和取消标记雷

    //标记雷
    void flag(char show[ROWS][COLS], int row, int col)
    {
      while (1)
      {
        int x = 0;
        int y = 0;
        printf("请输入标记坐标(输入:行 列 退出):>");
        scanf("%d %d", &x, &y);
        if (x >= 1 && x <= row && y >= 0 && y <= col)
        {
          if (show[x][y] != '#')
          {
            show[x][y] = '#';
            break;
          }
          else
          {
            printf("该坐标已经标记,请重新选择\n");
          }
        }
        else
        {
          printf("坐标越界,请重新输入\n");
        }
        if (x == y && x == 0)
          break;
      }
    }
    //取消标记雷
    static void cancel_flag(char show[ROWS][COLS], int row, int col)
    {
      while (1)
      {
        int x = 0;
        int y = 0;
        printf("请输入取消标记坐标(输入:0 0退出):>");
        scanf("%d %d", &x, &y);
        if (x >= 1 && x <= row && y >= 0 && y <= col)
        {
          if (show[x][y] == '#')//比较用双等号!!!
          {
            show[x][y] = '*';
            break;
          }
          else
          {
            printf("该坐标还未标记,请重新选择\n");
          }
        }
        else
        {
          printf("坐标越界,请重新输入\n");
        }
        if (x == y && x == 0)
          break;
      }
    }

    image.gif

    6.周围雷数为零,展开

    void Digit_boom(char show[ROWS][COLS], char mine[ROWS][COLS], int x, int y, int row, int col, int* win)
    {
      if (x >= 1 && x <= row && y >= 1 && y <= col)//判断坐标合法性
      {
        int ret = get_mine_count2(mine, x, y);//接受坐标周围雷的数量
        if (ret == 0)//递归条件--周围雷数为0
        {
          (*win)++;//每排查一个坐标,排查次数加1,为判断输赢做准备
          show[x][y] = '0';
          int i = 0;
          int j = 0;
          //用两个循环遍历周围8个坐标
          for (i = -1; i <= 1; i++)
          {
            for (j = -1; j <= 1; j++)
            {
              if (show[x + i][y + j] == '*')//递归的坐标必须是未排查过的坐标,防止死递归
              {
                Digit_boom(show, mine, x + i, y + j, row, col, win);
              }
            }
          }
        }
        else
        {
          //条件不满足退出递归
          (*win)++;//排查坐标,次数加1
          show[x][y] = ret + '0';
        }
      }
    }

    image.gif

    7.扫雷并判断输赢

    void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
    {
      int choice = -1;
      int x = 0;
      int y = 0;
      int win = 0;
      while (win < col * row - Easy_Count)
      {
        /*调用菜单2进行排雷和标记操作*/
        menu2();
        printf("请选择:>");
        scanf("%d", &choice);
        if (2 == choice) //标记雷
        {
          flag(show, ROW, COL);
          DisplayBoard(show, ROW, COL);
        }
        else if (3 == choice)//取消标记雷
        {
          cancel_flag(show, ROW, COL);
          DisplayBoard(show, ROW, COL);
        }
        else if (1 == choice)//进行排雷操作
        {
          printf("请输入排查坐标:>");
          scanf("%d%d", &x, &y);
          if (x >= 1 && x <= row && y >= 1 && y <= col)
          {
            if (mine[x][y] == '1')
            {
                        printf("很遗憾,你被炸死了!\n");
              DisplayBoard(mine, ROW, COL);
              break;
            }
            else if (show[x][y] == '*')
            {
              Digit_boom(show, mine, x, y, row, col, &win);//展开雷
              DisplayBoard(show, row, col);
            }
            else/*show[x][y] != '*' */
            {
              printf("该坐标已排查,请重新选择\n");
            }
          }
          else
          {
            printf("输入坐标错误,请重新输入\n");
          }
        }
        else
        {
          printf("坐标非法,重新输入\n");
        }
      }
      if (win == col * row - Easy_Count)
      {
        printf("恭喜你,排雷成功\n");
        DisplayBoard(mine, ROW, COL);
      }
    }

    image.gif

     完整代码

    game.h

    #pragma once
    #define _CRT_SECURE_NO_WARNINGS 1
    //包含头文件
    #include <stdio.h>
    #include <time.h>
    #include<string.h>
    #include<windows.h>
    #include<stdlib.h>
    //宏定义
    #define ROW 9
    #define COL 9
    #define ROWS ROW+2
    #define COLS COL+2
    #define Easy_Count 11
    //初始化雷盘
    void Init(char board[ROWS][COLS], int rows, int cols, char x);
    //打印雷盘
    void DisplayBoard(char board[ROWS][COLS], int row, int col);
    //布置雷
    void SetMine(char mine[ROWS][COLS], int row, int col);
    //排雷并判断输赢
    void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);

    image.gif

    game.c

    #include"game.h"
    //初始化雷盘
    void Init(char board[ROWS][COLS], int rows, int cols, char set)
    {
      int i = 0;
      for (i = 0; i < rows; i++)
      {
        int j = 0;
        for (j = 0; j < cols; j++)
        {
          board[i][j] = set;
        }
      }
    }
    //打印雷盘
    void DisplayBoard(char board[ROWS][COLS], int row, int col)
    {
      system("cls");//清屏操作,使界面更简洁
      printf("---------扫雷----------\n");
      int i = 0;
      int j = 0;
      for (j = 0; j <= col; j++)//打印列
      {
        printf("%d ", j);
      }
      printf("\n");
      for (i = 1; i <= row; i++)
      {
        printf("%d ", i);//打印行
        for (j = 1; j <= col; j++)
        {
          printf("%c ", board[i][j]);
        }
        printf("\n");
      }
      printf("---------扫雷----------\n");
    }
    //布置雷
    void SetMine(char mine[ROWS][COLS], int row, int col)
    {
      int count = Easy_Count;
      while (count)
      {
        int i = rand() % row + 1;
        int j = rand() % col + 1;
        if (mine[i][j] == '0')
        {
          mine[i][j] = '1';
          count--;
        }
      }
    }
    //显示周围雷数
    //法一:逐个遍历
    static int get_mine_count(char mine[ROWS][COLS], int x, int y)
    {
      return mine[x - 1][y] + mine[x - 1][y - 1] +
        mine[x - 1][y + 1] + mine[x][y - 1] +
        mine[x][y + 1] + mine[x + 1][y] +
        mine[x + 1][y - 1] + mine[x + 1][y + 1] - 8 * '0';
    }
    //法二:循环遍历
    static int get_mine_count2(char mine[ROWS][COLS], int x, int y)
    {
      int i = 0;
      int count = 0;
      for (i = -1; i <= 1; i++)
      {
        int j = 0;
        for (j = -1; j <= 1; j++)
        {
          if (mine[x + i][y + j] == '1')
            count++;
        }
      }
      return count;
    }
    //标记雷
    static void flag(char show[ROWS][COLS], int row, int col)
    {
      while (1)
      {
        int x = 0;
        int y = 0;
        printf("请输入标记坐标(输入:行 列 退出):>");
        scanf("%d %d", &x, &y);
        if (x >= 1 && x <= row && y >= 0 && y <= col)
        {
          if (show[x][y] != '#')
          {
            show[x][y] = '#';
            break;
          }
          else
          {
            printf("该坐标已经标记,请重新选择\n");
          }
        }
        else
        {
          printf("坐标越界,请重新输入\n");
        }
        if (x == y && x == 0)
          break;
      }
    }
    //取消标记雷
    static void cancel_flag(char show[ROWS][COLS], int row, int col)
    {
      while (1)
      {
        int x = 0;
        int y = 0;
        printf("请输入取消标记坐标(输入:0 0退出):>");
        scanf("%d %d", &x, &y);
        if (x >= 1 && x <= row && y >= 0 && y <= col)
        {
          if (show[x][y] == '#')//比较用双等号!!!
          {
            show[x][y] = '*';
            break;
          }
          else
          {
            printf("该坐标还未标记,请重新选择\n");
          }
        }
        else
        {
          printf("坐标越界,请重新输入\n");
        }
        if (x == y && x == 0)
          break;
      }
    }
    //如果排雷坐标周围雷数为零,递归展开
    static void Digit_boom(char show[ROWS][COLS], char mine[ROWS][COLS], int x, int y, int row, int col, int* win)
    {
      if (x >= 1 && x <= row && y >= 1 && y <= col)//判断坐标合法性
      {
        int ret = get_mine_count2(mine, x, y);//接受坐标周围雷的数量
        if (ret == 0)//递归条件--周围雷数为0
        {
          (*win)++;//每排查一个坐标,排查次数加1,为判断输赢做准备
          show[x][y] = '0';
          int i = 0;
          int j = 0;
          //用两个循环遍历周围8个坐标
          for (i = -1; i <= 1; i++)
          {
            for (j = -1; j <= 1; j++)
            {
              if (show[x + i][y + j] == '*')//递归的坐标必须是未排查过的坐标,防止死递归
              {
                Digit_boom(show, mine, x + i, y + j, row, col, win);
              }
            }
          }
        }
        else
        {
          //条件不满足退出递归
          (*win)++;//排查坐标,次数加1
          show[x][y] = ret + '0';
        }
      }
    }
    //扫雷菜单
    static void menu2()
    {
      printf("┌-----------------------------┐\n");
      printf("├**********1.排雷*************┤\n");
      printf("├**********2.标记*************┤\n");
      printf("├**********3.取消标记*********┤\n");
      printf("└-----------------------------┘\n");
    }
    //扫雷并判断输赢
    void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
    {
      int choice = -1;
      int x = 0;
      int y = 0;
      int win = 0;
      while (win < col * row - Easy_Count)
      {
        /*调用菜单2进行排雷和标记操作*/
        menu2();
        printf("请选择:>");
        scanf("%d", &choice);
        if (2 == choice) /*标记雷*/
        {
          flag(show, ROW, COL);
          DisplayBoard(show, ROW, COL);
        }
        else if (3 == choice)/*取消标记雷*/
        {
          cancel_flag(show, ROW, COL);
          DisplayBoard(show, ROW, COL);
        }
        else if (1 == choice)/*进行排雷操作*/
        {
          printf("请输入排查坐标:>");
          scanf("%d%d", &x, &y);
          if (x >= 1 && x <= row && y >= 1 && y <= col)
          {
            if (mine[x][y] == '1')
            {
                        printf("很遗憾,你被炸死了!\n");
              DisplayBoard(mine, ROW, COL);
              break;
            }
            else if (show[x][y] == '*')
            {
              Digit_boom(show, mine, x, y, row, col, &win);/*展开*/
              DisplayBoard(show, row, col);
            }
            else/*show[x][y] != '*' */
            {
              printf("该坐标已排查,请重新选择\n");
            }
          }
          else
          {
            printf("输入坐标错误,请重新输入\n");
          }
        }
        else
        {
          printf("坐标非法,重新输入\n");
        }
      }
      if (win == col * row - Easy_Count)
      {
        printf("恭喜你,排雷成功\n");
        DisplayBoard(mine, ROW, COL);
      }
    }

    image.gif

    text.c

    #include"game.h"
    //游戏菜单
    menu()
    {
      printf("┌-----------------------------┐\n");
      printf("├**********1.扫雷*************┤\n");
      printf("├**********0.退出*************┤\n");
      printf("└-----------------------------┘\n");
    }
    //扫雷游戏
    void game()
    {
      //创建扫雷棋盘
      char mine[ROWS][COLS];
      char show[ROWS][COLS];
      //初始化扫雷棋盘
      Init(mine, ROWS, COLS, '0');
      Init(show, ROWS, COLS, '*');
      //布置雷
      SetMine(mine, ROW, COL);
      //打印扫雷棋盘
      DisplayBoard(show, ROW, COL);
      //开始扫雷并判断输赢
      FindMine(mine, show, ROW, COL);
    }
    void test()
    {
      srand((unsigned int)time(NULL));
      int input = 0;
      do
      {
        menu();
        printf("请选择:>");
        scanf("%d", &input);
        switch (input)
        {
        case 1:
          game();
          break;
        case 0:
          printf("退出游戏\n");
          break;
        default:
          printf("选择错误,重新选择!\n");
          break;
        }
      } while (input);
    }   /*交互界面*/
    int main()
    {
      test();
      return 0;
    }

    image.gif


    相关文章
    |
    16天前
    |
    存储
    扫雷游戏的实现
    扫雷游戏的实现
    |
    5月前
    |
    C语言
    扫雷游戏的实现(上)
    扫雷游戏的实现
    20 0
    |
    8月前
    |
    Serverless C语言
    C项目(扫雷)
    C项目(扫雷)
    56 0
    |
    5月前
    扫雷游戏的实现(详解)
    扫雷游戏的实现(详解)
    43 0
    |
    5月前
    |
    存储
    扫雷小游戏
    扫雷小游戏
    53 0
    |
    5月前
    |
    C语言
    扫雷游戏的实现(下)
    扫雷游戏的实现(下)
    27 0
    |
    7月前
    |
    小程序
    扫雷小游戏详解
    扫雷小游戏详解
    39 0
    |
    8月前
    [SCOI2005]扫雷MINE
    [SCOI2005]扫雷MINE
    |
    8月前
    简易扫雷游戏
    简易扫雷游戏
    64 0