扫雷(升级版)

简介: 扫雷(升级版)

一、实现思路

  1. 创建一个与玩家交互的菜单
  2. 利用二维数组创建两个棋盘,分别为mine(雷盘)和show盘,mine盘不可见,而show盘可见
  3. 随机在雷盘上布置雷
  4. 以输入坐标的方式扫雷
  5. 选择标记雷区
  6. 选择取消对雷的标记
  7. 判断游戏是否结束

二、实现过程

1、创建菜单

选择 1 进行游戏

选择 0 退出游戏

2、创建、初始化以及展示mine盘和show盘

用宏定义的方法定义棋盘的行和列,方便后期维护

#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2

用二维数组的方式定义两个盘

  char mine[ROWS][COLS] = { 0 };//存放布置好的雷的信息
  char show[ROWS][COLS] = { 0 };//存放排查出的雷的信息

利用初始化函数对两个盘进行初始化,mine盘全部初始化为 ‘0’ ,show盘全部初始化为 ‘*’

  InitBoard(mine, ROWS, COLS, '0');
  InitBoard(show, ROWS, COLS, '*');

初始化函数

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

展示

void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
  int i = 0;
  int j = 0;
  printf("----—扫雷游戏—----\n");
  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");
}

效果

3、随机布雷

用宏定义的方式设置要布置的雷数,方便随时修改

#define EASY_COUNT 10

利用rand和srand函数以及时间戳生成随机雷

  //设置随机数生成起点
  srand((unsigned int)time(NULL));
void SetMine(char board[ROWS][COLS], int row, int col)
{
  int count = EASY_COUNT;
  while (count)
  {
    int x = rand() % row + 1;//1——9
    int y = rand() % col + 1;//1——9
    if (board[x][y] == '0')
    {
      board[x][y] = '1';
      count--;
    }
  }
}

3、 玩家排雷

玩家选择扫雷,通过输入坐标进行排雷

4、统计所选位置周围八个位置中雷的个数,并打印在show盘上

//获取四周的雷数
int get_mine_count(char board[ROWS][COLS], int x, int y)
{
//法一
  /*
  return board[x - 1][y] +
     board[x - 1][y - 1] +
     board[x][y - 1] +
     board[x + 1][y - 1] +
     board[x + 1][y] +
     board[x + 1][y + 1] + 
     board[x][y + 1] + 
     board[x - 1][y + 1] - 8 * '0';
  */
  //法2
  int count = 0;
  for (int i = -1; i <= 1; i++)
  {
    for (int j = -1; j <= 1; j++)
    {
      if (board[x + i][y + j] == '1')
      {
        count++;
      }
    }
  }
  return count ;
}

5、用递归的方法拓展周围不是雷的区域

用递归的方法拓展排雷

void broad(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y)
{
  //判断坐标是否越界
  if (x == 0 || y == 0 || x == ROWS - 1 || y == COLS - 1)
    return;
  //判断是否已经排查
  if (show[x][y] != '*')
    return;
  int count = get_mine_count(mine, x, y);
  if (count > 0)
  {
    show[x][y] = count + '0';
    return;
  }
  //拓展
  if (count == 0)
  {
    show[x][y] = '0';
    broad(mine, show, x - 1, y);
    broad(mine, show, x - 1, y - 1);
    broad(mine, show, x, y - 1);
    broad(mine, show, x + 1, y - 1);
    broad(mine, show, x + 1, y);
    broad(mine, show, x + 1, y + 1);
    broad(mine, show, x, y + 1);
    broad(mine, show, x - 1, y + 1);
  }
}

6、对认为是雷的位置用 !进行标记

int Flagmine(char show[ROWS][COLS], int row, int col,int flag_count)
{
  int x = 0;
  int y = 0;
  if (flag_count == EASY_COUNT)
  {
    printf("标记的雷数与实际雷数相等,无法再标记\n");
    return;
  }
  printf("请输入你要标记的位置:\n");
  scanf_s("%d %d", &x, &y);
  if (x > 0 && x <= row && y > 0 && y <= col)
  {
    //判断该位置是否被排除
    if (show[x][y] == '*')
    {
      show[x][y] = '!';
      flag_count++;
    }
    else
    {
      printf("该位置已经排除,无法再标记\n");
    }
  }
  else
  {
    printf("输入坐标非法,请重新输入:\n");
  }
  return flag_count;
}

7、取消标记

int CancelFlag(char show[ROWS][COLS], int row, int col, int flag_count)
{
  int x = 0;
  int y = 0;
  printf("请输入你要取消标记的位置:\n");
  scanf_s("%d %d", &x, &y);
  if (x > 0 && x <= row && y > 0 && y <= col)
  {
    //判断该位置是否被标记
    if (show[x][y] == '!')
    {
      show[x][y] = '*';
      flag_count--;
    }
    else
    {
      printf("该位置未被标记过,无法取消标记!\n");
    }
  }
  else
  {
    printf("输入坐标非法,请重新输入:\n");
  }
  return flag_count;
}

8、判断游戏是否结束

  1. 若踩雷,则游戏失败,游戏结束

  2. 排除所有的雷,获得胜利,游戏结束

遍历棋盘,如果show盘中剩下的 ‘*’ 和 ‘!’ 数量的和加起来对于雷的数量,则排雷成功

//遍历雷盘
int TravelBoard(char show[ROWS][COLS], int row, int col)
{
  int i = 0;
  int j = 0;
  int win = 0;
  for (i = 1; i <= row; i++)
  {
    for (j = 1; j <= col; j++)
    {
      if (show[i][j] == '*' || show[i][j] == '!')
      {
        win++;
      }
    }
  }
  return win;
}
  if (win == EASY_COUNT)
  {
    printf("恭喜你,排雷成功!\n");
    DisplayBoard(mine, ROW, COL);
  }

三、代码展示

1、game.h

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
#define EASY_COUNT 10
//初始化
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set);
//展示
void DisplayBoard(char board[ROWS][COLS], int row, int col);
//设置雷
void SetMine(char board[ROWS][COLS], int row, int col);
//排查雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
//拓展周围不是雷的区域
void broad(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y);
//标记
int Flagmine(char show[ROWS][COLS], int row, int col, int flag_count);
//取消标记
int CancelFlag(char show[ROWS][COLS], int row, int col, int flag_count);

2、game.c

#include"game.h"
//菜单2
void menu2()
{
  printf("**************************\n");
  printf("******* 1.扫    雷 *******\n");
  printf("******* 2.标    记 *******\n");
  printf("******* 3.取消标记 *******\n");
  printf("**************************\n");
}
//初始化
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set)
{
  int i = 0;
  int j = 0;
  for (i = 0; i < rows; i++)
  {
    for (j = 0; j < cols; j++)
    {
      board[i][j] =set;
    }
  }
}
//展示
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
  int i = 0;
  int j = 0;
  printf("----—扫雷游戏—----\n");
  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 board[ROWS][COLS], int row, int col)
{
  int count = EASY_COUNT;
  while (count)
  {
    int x = rand() % row + 1;//1——9
    int y = rand() % col + 1;//1——9
    if (board[x][y] == '0')
    {
      board[x][y] = '1';
      count--;
    }
  }
}
//遍历雷盘
int TravelBoard(char show[ROWS][COLS], int row, int col)
{
  int i = 0;
  int j = 0;
  int win = 0;
  for (i = 1; i <= row; i++)
  {
    for (j = 1; j <= col; j++)
    {
      if (show[i][j] == '*' || show[i][j] == '!')
      {
        win++;
      }
    }
  }
  return win;
}
//获取四周的雷数
int get_mine_count(char board[ROWS][COLS], int x, int y)
{
  //return board[x - 1][y] +
  //     board[x - 1][y - 1] +
  //     board[x][y - 1] +
  //     board[x + 1][y - 1] +
  //     board[x + 1][y] +
  //     board[x + 1][y + 1] + 
  //     board[x][y + 1] + 
  //     board[x - 1][y + 1] - 8 * '0';
  int count = 0;
  for (int i = -1; i <= 1; i++)
  {
    for (int j = -1; j <= 1; j++)
    {
      if (board[x + i][y + j] == '1')
      {
        count++;
      }
    }
  }
  return count ;
}
//拓展周围不是雷的区域
void broad(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y)
{
  //判断坐标是否越界
  if (x == 0 || y == 0 || x == ROWS - 1 || y == COLS - 1)
    return;
  //判断是否已经排查
  if (show[x][y] != '*')
    return;
  int count = get_mine_count(mine, x, y);
  if (count > 0)
  {
    show[x][y] = count + '0';
    return;
  }
  //拓展
  if (count == 0)
  {
    show[x][y] = '0';
    broad(mine, show, x - 1, y);
    broad(mine, show, x - 1, y - 1);
    broad(mine, show, x, y - 1);
    broad(mine, show, x + 1, y - 1);
    broad(mine, show, x + 1, y);
    broad(mine, show, x + 1, y + 1);
    broad(mine, show, x, y + 1);
    broad(mine, show, x - 1, y + 1);
  }
}
//标记
int Flagmine(char show[ROWS][COLS], int row, int col,int flag_count)
{
  int x = 0;
  int y = 0;
  if (flag_count == EASY_COUNT)
  {
    printf("标记的雷数与实际雷数相等,无法再标记\n");
    return;
  }
  printf("请输入你要标记的位置:\n");
  scanf_s("%d %d", &x, &y);
  if (x > 0 && x <= row && y > 0 && y <= col)
  {
    //判断该位置是否被排除
    if (show[x][y] == '*')
    {
      show[x][y] = '!';
      flag_count++;
    }
    else
    {
      printf("该位置已经排除,无法再标记\n");
    }
  }
  else
  {
    printf("输入坐标非法,请重新输入:\n");
  }
  return flag_count;
}
//取消标记
int CancelFlag(char show[ROWS][COLS], int row, int col, int flag_count)
{
  int x = 0;
  int y = 0;
  printf("请输入你要取消标记的位置:\n");
  scanf_s("%d %d", &x, &y);
  if (x > 0 && x <= row && y > 0 && y <= col)
  {
    //判断该位置是否被标记
    if (show[x][y] == '!')
    {
      show[x][y] = '*';
      flag_count--;
    }
    else
    {
      printf("该位置未被标记过,无法取消标记!\n");
    }
  }
  else
  {
    printf("输入坐标非法,请重新输入:\n");
  }
  return flag_count;
}
//扫雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
  int choice = 0;//选择
  int flag_count = 0;//标记雷的个数
  int win = 0;//判断是否赢
  while (1)
  {
    menu2();
    scanf_s("%d", &choice);
    if (choice == 1)
    {
      int x = 0;
      int y = 0;
      printf("请输入要排查的坐标:\n");
      scanf_s("%d %d", &x, &y);
      if (x >= 1 && x <= row && y >= 1 && y <= col)
      {
        if (show[x][y] != '*')
        {
          printf("改坐标已经被排查过了,不能重复排查!\n");
          system("pause");
        }
        else
        {
          //如果是雷
          if (mine[x][y] == '1')
          {
            printf("很遗憾,你被炸死了!!!\n");
            DisplayBoard(mine, ROW, COL);
            break;
          }
          else//如果不是雷
          {
            broad(mine, show, x, y);
            //统计mine数组中(x,y) 周围有几个雷
            DisplayBoard(show, ROW, COL);
          }
        }
      }
      else
      {
        printf("输入坐标非法,请重新输入\n");
      }
    }
    else if (choice == 2)
    {
      printf("请标记雷:\n");
      flag_count = Flagmine(show, ROW, COL,flag_count);
      DisplayBoard(show, ROW, COL);
    }
    else if (choice == 3)
    {
      flag_count = CancelFlag(show, ROW, COL, flag_count);
      DisplayBoard(show, ROW, COL);
    }
    else
    {
      printf("输入错误,请重新输入!\n");
    }
    win = TravelBoard(show, ROW, COL);
    if (win == EASY_COUNT)
    {
      break;
    }
  }
  if (win == EASY_COUNT)
  {
    printf("恭喜你,排雷成功!\n");
    DisplayBoard(mine, ROW, COL);
  }
}

3、test.c

#include"game.h"
//菜单
void menu()
{
  printf("************************\n");
  printf("******* 1. play ********\n");
  printf("******* 0. exit ********\n");
  printf("************************\n");
}
void game()
{
  char mine[ROWS][COLS] = { 0 };//存放布置好的雷的信息
  char show[ROWS][COLS] = { 0 };//存放排查出的雷的信息
  //初始化数组内容为指定的内容
  //mine 数组在没有布置雷的时候,都是'0'
  InitBoard(mine, ROWS, COLS, '0');
  //show 数组在没有排查雷的时候, 都是'*'
  InitBoard(show, ROWS, COLS, '*');
  DisplayBoard(show, ROW, COL);
  //DisplayBoard(mine, ROW, COL);
  //设置雷
  SetMine(mine, ROW, COL);
  //DisplayBoard(mine, ROW, COL);
  //排查雷
  FindMine(mine, show, ROW, COL);
}
int main()
{
  //设置随机数生成起点
  srand((unsigned int)time(NULL));
  int input = 0;
  do
  {
    menu();
    printf("请选择:");
    scanf_s("%d", &input);
    switch (input)
    {
    case 1:
      //printf("扫雷\n");
      system("cls");
      game();
      system("pause");
      system("cls");
      break;
    case 0:
      system("cls");
      printf("退出游戏\n");
      system("pause");
      break;
    default:
      printf("输入错误,请重新输入:\n");
      system("pause");
      system("cls");
      break;
    }
  } while (input);
  return 0;
}
目录
相关文章
|
1月前
|
算法 C语言 C++
【C语言-扫雷游戏全功能详解】
【C语言-扫雷游戏全功能详解】
53 1
|
1月前
|
存储
扫雷游戏讲解(第一版本)
扫雷游戏讲解(第一版本)
22 0
|
1月前
|
人工智能 算法 数据可视化
C语言”三子棋“升级版(模式选择+”模拟智能“下棋)
C语言”三子棋“升级版(模式选择+”模拟智能“下棋)
|
1月前
|
存储 Serverless C语言
扫雷游戏简易版的C语言实现
扫雷游戏简易版的C语言实现
44 0
|
1月前
|
C语言
探索经典游戏:扫雷小游戏
探索经典游戏:扫雷小游戏
59 0
|
6月前
|
存储
扫雷小游戏的优化!(不仅仅是展开功能哦)
扫雷小游戏的优化!(不仅仅是展开功能哦)
55 0
|
8月前
|
C语言
|
10月前
经典游戏扫雷详解--你也可以写出扫雷和玩好扫雷(下)
经典游戏扫雷详解--你也可以写出扫雷和玩好扫雷(下)