扫雷——C语言实现(三)

简介: 扫雷——C语言实现

实现爆炸展开效果

  • 我们看到,网页版的扫雷中,会出现点击一个区域就自动展开一片区域的情况,如图:

  • 要实现这一功能,那我们首先就需要知道什么条件下才会出现爆炸展开的情况。
  • 展开条件:如果排查的坐标(X,Y)周围地雷的总个数是0(既没有地雷),那么就自动排查它周围的八个区域(即坐标(X,Y-1), (X,Y+1), (X+1,Y), (X+1,Y+1), (X+1,Y-1), (X-1,Y), (X-1,Y+1), (X-1,Y-1)),对这八个坐标执行同样的操作,不断递归,直达每个区域的周围都至少有一个地雷(找到爆炸展开的边界)
  • 实现这个功能要注意以下几点:
  • 注意递归时数组不要越界
  • 注意递归时排查重复递归的情况
  • 如果排查区域周围地雷的个数为0,那么为了界面的简洁,就不再将0打印出,改为打印空格
  • Explode()的实现代码:
//x,y即用户输入的排查坐标
void Explode(char mine[][COLS], char show[][COLS], int x, int y)
{
    //如果该位置已经配排查(重复递归)或坐标无效,那么退出这个函数(不是结束递归)
  if (show[x][y] == ' ' || x < 1 || y < 1 || x > ROW || y > COL)
    return;
    //如果该位置周围的地雷个数为0,那么符合递归条件,继续排查
  if (MineNumber(mine, x, y) == 0)
    show[x][y] = ' ';
    //如果坐标有效但周围的地雷个数不为零,那么退出这个函数(不是结束递归)
  else
  {
    show[x][y] = MineNumber(mine, x, y) + '0';
    return;
  }
    //自动排查(X,Y)周围的8个坐标
  Explode(mine, show, x, y - 1);
  Explode(mine, show, x, y + 1);
  Explode(mine, show, x + 1, y + 1);
  Explode(mine, show, x + 1, y);
  Explode(mine, show, x + 1, y - 1);
  Explode(mine, show, x - 1, y + 1);
  Explode(mine, show, x - 1, y - 1);
  Explode(mine, show, x - 1, y);
}
  • 要对MineFind()函数做出相应的修改
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7sF9UEGD-1686494176819)(C:/Users/HUASHUO/Desktop/扫雷.5.gif)]void MineFind(char mine[][COLS], char show[][COLS], int row, int col)
{
  int x, y;
  while (1)
  {
    printf("请输入您要排查的坐标(用空格分隔):");
    scanf_s("%d %d", &x, &y);
    system("cls");
    if (show[x][y] == '*' && x > 0 && x <= row && y > 0 && y <= col)
    {
      if (mine[x][y] == '1')
      {
        printf("很遗憾,排雷失败\n");
        BoardDisplay(mine, row, col);
        return;
      }
      else
      {
        Explode(mine, show, x, y);
        if (MineFinish(show, row,col))
        {
          printf("恭喜你,排雷成功\n");
          BoardDisplay(mine, row, col);
          return;
        }
        BoardDisplay(show, row, col);
      }
    }
    else if (show[x][y] != '*' && x > 0 && x <= row && y > 0 && y <= col)
    {
      printf("该位置已经被检查,请重新输入:\n");
      BoardDisplay(show, row, col);
    }
    else
    {
      printf("坐标非法,请重新输入:\n");
      BoardDisplay(show, row, col);
    }
  }
}

实现效果

插旗功能

  • 我们假设旗子的标志是字符:‘$’
  • 注:用户如果在一个区域插上旗子,就说明用户认为这个区域是雷,即插旗是为了方便用户排雷
  • 实现逻辑并不复杂,至少需要注意细节的处理

插旗

void Flag_In(char show[][COLS])
{
  int row = 0, col = 0;
  printf("您想在哪个位置插入旗子:\n");
  printf("注:用空格分隔,输入0 0结束插旗\n");
  while(1)
  {
    scanf_s("%d %d", &row, &col);
    if (row == 0 && col == 0)
      break;
    if (row < 1 || row > ROW || col < 1 || col > COL)
    {
      printf("坐标非法,重新输入:");
      continue;
    }
    else if (show[row][col] != '*')
      printf("该位置不能插旗\n");
    else
    {
      system("cls");
      count++;  //旗子数目加一
      show[row][col] = '$';
      BoardDisplay(show, ROW, COL);
    }
  }
  while (getchar() != '\n');  //清空缓冲区
}

取消所插旗子

void Flag_Out(char show[][COLS])
{
  int row, col;
  printf("您想取消哪个位置的旗子:\n");
  printf("注:用空格分隔,输入0 0结束\n");
  while (1)
  {
    scanf_s("%d %d", &row, &col);
    if (row == 0 && col == 0)
      break;
    if (row < 1 || row > ROW || col < 1 || col > COL)
    {
      printf("坐标非法,重新输入:");
      continue;
    }
    else if (show[row][col] != '$')
      printf("该位置不是旗子\n");
    else
    {
      system("cls");
      show[row][col] = '*';
      BoardDisplay(show, ROW, COL);
    }
  }
}

调整MineFind()函数

void MineFind(char mine[][COLS], char show[][COLS], int row, int col)
{
  int x, y;
  char ch;
  while (1)
  {
    printf("请输入您要排查的坐标(用空格分隔):");
    scanf_s("%d %d", &x, &y);
    system("cls");
    if (show[x][y] == '*' && x > 0 && x <= row && y > 0 && y <= col)
    {
      if (mine[x][y] == '1')
      {
        printf("很遗憾,排雷失败\n");
        BoardDisplay(mine, row, col);
        return;
      }
      else
      {
        Explode(mine, show, x, y);
        if (MineFinish(show, row,col))
        {
          printf("恭喜你,排雷成功\n");
          BoardDisplay(mine, row, col);
          return;
        }
        BoardDisplay(show, row, col);
        getchar();
        printf("是否需要插旗(Y/N):\n");
        if((ch = getchar()) == 'Y')
          Flag_In(show);
        getchar();
        printf("是否需要取消所插的旗子(Y/N):\n");
        if ((ch = getchar()) == 'Y')
          Flag_Out(show);
      }
    }
    else if (show[x][y] != '*' && x > 0 && x <= row && y > 0 && y <= col)
    {
      printf("该位置已经被检查,请重新输入:\n");
      BoardDisplay(show, row, col);
    }
    else
    {
      printf("坐标非法,请重新输入:\n");
      BoardDisplay(show, row, col);
    }
  }
}

实现效果

拓展功能实现代码

#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<Windows.h>
#include<stdbool.h>
#define ROW 9
#define COL 9
#define ROWS ROW + 2
#define COLS COL + 2
#define MINENUMBER 10
void BoardInit(char board[][COLS], int row, int col, char set);
void BoardDisplay(char board[][COLS], int row, int col);
void MineSet(char board[][COLS], int row, int col);
int MineNumber(char board[][COLS], int x, int y);
void MineFind(char mine[][COLS], char show[][COLS], int row, int col);
bool MineFinish(char board[][COLS], int row, int col);
void Explode(char mine[][COLS], char show[][COLS], int x, int y);
void Flag_In(char show[][COLS]);
void Flag_Out(char show[][COLS]);
void meau()
{
  printf("****************\n");
  printf("*****1.Play*****\n");
  printf("*****0.Exit*****\n");
  printf("****************\n");
}
void game()
{
  //生成时间戳
  srand((unsigned int)time(NULL));
  //定义存放地雷的数组,和展示结果的数组
  char mineBoard[ROWS][COLS];
  char showBoard[ROWS][COLS];
  //对两个数组进行初始化
  BoardInit(mineBoard, ROWS, COLS, '0');
  BoardInit(showBoard, ROWS, COLS, '*');
  //设置地雷
  MineSet(mineBoard, ROW, COL);
  //BoardDisplay(mineBoard, ROW, COL);
  BoardDisplay(showBoard, ROW, COL);
  //排查地雷
  MineFind(mineBoard, showBoard, ROW, COL);
}
void BoardInit(char board[][COLS], int row, int col, char set)
{
  for (int i = 0; i < row; i++)
    for (int j = 0; j < col; j++)
      board[i][j] = set;
}
void BoardDisplay(char board[][COLS], int row, int col)
{
  for (int i = 0; i <= col; i++)
  {
    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 4 | 16);
    printf("%d ", i);
  }
  printf("\n");
  for (int i = 1; i <= row; i++)
  {
    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 4 | 16);
    printf("%d ", i);
    for (int j = 1; j <= col; j++)
    {
      SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7 | 16);
      if(board[i][j] == '$')
        SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 6 | 16);
      printf("%c ", board[i][j]);
    }
    printf("\n");
  }
  SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7 | 16);
}
void MineSet(char board[][COLS], int row, int col)
{
  int count = 0;
  while (count < MINENUMBER)
  {
    int x = rand() % row + 1;
    int y = rand() % col + 1;
    if (board[x][y] == '0')
    {
      board[x][y] = '1';
      count++;
    }
  }
}
void MineFind(char mine[][COLS], char show[][COLS], int row, int col)
{
  int x, y;
  char ch;
  while (1)
  {
    printf("请输入您要排查的坐标(用空格分隔):");
    scanf_s("%d %d", &x, &y);
    system("cls");
    if (show[x][y] == '*' && x > 0 && x <= row && y > 0 && y <= col)
    {
      if (mine[x][y] == '1')
      {
        printf("很遗憾,排雷失败\n");
        BoardDisplay(mine, row, col);
        return;
      }
      else
      {
        Explode(mine, show, x, y);
        if (MineFinish(show, row,col))
        {
          printf("恭喜你,排雷成功\n");
          BoardDisplay(mine, row, col);
          return;
        }
        BoardDisplay(show, row, col);
        getchar();
        printf("是否需要插旗(Y/N):\n");
        if((ch = getchar()) == 'Y')
          Flag_In(show);
        getchar();
        printf("是否需要取消所插的旗子(Y/N):\n");
        if ((ch = getchar()) == 'Y')
          Flag_Out(show);
      }
    }
    else if (show[x][y] != '*' && x > 0 && x <= row && y > 0 && y <= col)
    {
      printf("该位置已经被检查,请重新输入:\n");
      BoardDisplay(show, row, col);
    }
    else
    {
      printf("坐标非法,请重新输入:\n");
      BoardDisplay(show, row, col);
    }
  }
}
int MineNumber(char board[][COLS], int x, int y)
{
  return (board[x][y - 1] + board[x][y + 1]
    + board[x - 1][y] + board[x - 1][y - 1] + board[x - 1][y + 1]
    + board[x + 1][y] + board[x + 1][y - 1] + board[x + 1][y + 1]
    - 8 * '0');
}
bool MineFinish(char board[][COLS], int row, int col)
{
  int count = 0;
  for(int i = 1; i <= row; i++)
    for (int j = 1; j <= col; j++)
    {
      if (board[i][j] != '*')
      {
        count++;
        if (count == row * col - MINENUMBER)
          return true;
      }
    }
  return false;
}
void Explode(char mine[][COLS], char show[][COLS], int x, int y)
{
  if (show[x][y] == ' ' || x < 1 || y < 1 || x > ROW || y > COL)
    return;
  if (MineNumber(mine, x, y) == 0)
    show[x][y] = ' ';
  else
  {
    show[x][y] = MineNumber(mine, x, y) + '0';
    return;
  }
  Explode(mine, show, x, y - 1);
  Explode(mine, show, x, y + 1);
  Explode(mine, show, x + 1, y + 1);
  Explode(mine, show, x + 1, y);
  Explode(mine, show, x + 1, y - 1);
  Explode(mine, show, x - 1, y + 1);
  Explode(mine, show, x - 1, y - 1);
  Explode(mine, show, x - 1, y);
}
void Flag_In(char show[][COLS])
{
  int row = 0, col = 0;
  printf("您想在哪个位置插入旗子:\n");
  printf("注:用空格分隔,输入0 0结束插旗\n");
  while(1)
  {
    scanf_s("%d %d", &row, &col);
    if (row == 0 && col == 0)
      break;
    if (row < 1 || row > ROW || col < 1 || col > COL)
    {
      printf("坐标非法,重新输入:");
      continue;
    }
    else if (show[row][col] != '*')
      printf("给位置不能插旗\n");
    else
    {
      system("cls");
      show[row][col] = '$';
      BoardDisplay(show, ROW, COL);
    }
  }
}
void Flag_Out(char show[][COLS])
{
  int row, col;
  printf("您想取消哪个位置的旗子:\n");
  printf("注:用空格分隔,输入0 0结束\n");
  while (1)
  {
    scanf_s("%d %d", &row, &col);
    if (row == 0 && col == 0)
      break;
    if (row < 1 || row > ROW || col < 1 || col > COL)
    {
      printf("坐标非法,重新输入:");
      continue;
    }
    else if (show[row][col] != '$')
      printf("该位置不是旗子\n");
    else
    {
      system("cls");
      show[row][col] = '*';
      BoardDisplay(show, ROW, COL);
    }
  }
}
int main()
{
  system("color 17");
  int input;
  meau();
  printf("请输入您的选择:");
  while (1)
  {
    scanf_s("%d", &input);
    switch (input)
    {
    case 1:
      game();
      break;
    case 0:
      printf("退出游戏,感谢游玩\n");
      break;
    default :
      printf("输入错误,请重新输入:");
      break;
    }
    meau();
    printf("是否重新游玩:");
  }
  return 0;
}
相关文章
|
3月前
|
C语言
扫雷游戏(用C语言实现)
扫雷游戏(用C语言实现)
136 0
|
5月前
|
机器学习/深度学习 C语言
九/十:《初学C语言》— 扫雷游戏实现和函数递归基础
【8月更文挑战第5天】本篇文章用C语言采用多文件编写实现了一个基础的扫雷游戏(附源码),并讲解了关于函数递归的基础概念及其相对应的习题练习(附源码)
48 1
九/十:《初学C语言》— 扫雷游戏实现和函数递归基础
|
4月前
|
存储 安全 算法
C 语言——实现扫雷小游戏
本文介绍了使用二维数组创建棋盘并实现扫雷游戏的方法。首先,通过初始化数组创建一个9x9的棋盘,并添加行列标识以便操作。接着,利用随机数在棋盘上布置雷。最后,通过判断玩家输入的坐标来实现扫雷功能,包括显示雷的数量和处理游戏胜利或失败的情况。文中提供了完整的代码实现。
62 1
C 语言——实现扫雷小游戏
|
3月前
|
存储 算法 安全
C语言实现扫雷游戏
C语言实现扫雷游戏
|
3月前
|
C语言
初学者指南:使用C语言实现简易版扫雷游戏
初学者指南:使用C语言实现简易版扫雷游戏
60 0
|
3月前
|
C语言
C语言扫雷游戏(详解)
C语言扫雷游戏(详解)
46 0
|
3月前
|
存储 编译器 C语言
【C语言篇】数组和函数的实践:扫雷游戏(附源码)
【C语言篇】数组和函数的实践:扫雷游戏(附源码)
44 0
|
5月前
|
C语言
扫雷(C语言)
扫雷(C语言)
53 4
|
6月前
|
存储 编译器 C语言
|
7月前
|
C语言
【海贼王编程冒险 - C语言海上篇】怎样用C语言实现简单的扫雷游戏?
【海贼王编程冒险 - C语言海上篇】怎样用C语言实现简单的扫雷游戏?
45 1