c语言实现扫雷

简介: c语言实现扫雷

游戏运行效果

初始界面

排雷界面

数据结构的分析

扫雷的过程中,布置的雷和排查出的雷的信息都需要存储,所以我们需一定的数据结构来存储这些信息。

因为我们需要在9*9的棋盘上布置雷的信息和排查雷,我们首先想到的就创建⼀个的数组来存放信息。

为了防止越界,我们在设计的时候,给数组扩大一圈,雷还是布置在中间的的坐标上,周围⼀圈不去布置雷就⾏,这样就解决了越界的问题。所以我们将存放数据的数组创建成11*11是比较合适。

为了避免混杂,这里我们采用这样的方案,我们专门给⼀个棋盘(对应⼀个数组mine)存放布置好的雷的信息,再给另外⼀个棋盘(对应另外⼀个数组show)存放排查出的雷的信息。这样就互不⼲扰了,把雷布置到mine数组,在mine数组中排查雷,排查出的数据存放在show数组,并且印show数组的信息给后期排查参考。

同时为了保持神秘,show数组开始时初始化为字符 ‘*’,为了保持两个数组的类型⼀致,可以使⽤同⼀套函数处理,mine数组最开始也初始化为字符’0’,布置雷改成’1’

1.char mine[11][11] = {0};//⽤来存放布置好的雷的信息
2.char show[11][11] = {0};//⽤来存放排查出的雷的个数信息

实现过及注意事项

文件结构

1.test.c //⽂件中写游戏的测试逻辑 
2.game.c //⽂件中写游戏中函数的实现等
3.game.h //⽂件中写游戏需要的数据类型和函数声明等

主函数

#include "game.h"
int main()
{
  int input = 0;
  srand((unsigned int)time(NULL));
  do
  {
    manu();
    printf("请选择:>");
    scanf("%d", &input);
    switch (input)
    {
    case 1:
      game();
      break;
    case 0:
      printf("退出\n");
      break;
    default:
      printf("选择错误,请重新选择:>\n");
      break;
    }
  } while (input);
  return 0;
}

菜单函数

void manu()
{
  printf("********************\n");
  printf("***   _1.play_   ***\n");
  printf("***   _0.exit_   ***\n");
  printf("********************\n");
}

具体的游戏执行流程

void game()
{
  char mine[ROWS][COLS]; // 存放雷信息的棋盘
  char show[ROWS][COLS]; //展示给玩家的棋盘
  //初始化棋盘  
  //mine棋盘全部初始化为'0'    show棋盘全部初始化为'*'
  InitBoard(mine, ROWS, COLS, '0');
  InitBoard(show, ROWS, COLS, '*');
  //打印棋盘
  //DisplayBoard(mine, ROWS, COLS);
  DisplayBoard(show, ROWS, COLS);
  //布置雷
  SetMine(mine, ROWS, COLS);
  //DisplayBoard(mine, ROWS, COLS);
  //排查雷
  FindMine(mine, show, ROW, COL);
}

棋盘初始化函数

我们通过InitBoard()函数对char mine[ROWS][COLS]char show[ROWS][COLS]进行初始化,前者放'0'后者放'*'

我们用两个for循环来遍历数组

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

棋盘打印函数

void DisplayBoard(char Board[ROWS][COLS], int rows, int cols)
{
  int i = 0;
  printf("\n");
  for (i = 0; i <= rows - 2; i++)
    printf("%d ", i);
  printf("\n");
  for (i = 1; i < rows-1; i++)
  {
    int j = 0;
    printf("%d ", i);
    for (j = 1; j < cols-1; j++)
    {
      printf("%c ", Board[i][j]);
    }
    printf("\n");
  }
}

布置雷函数

我们用rand()来生成随机数,用srand((unsigned int)time(NULL))确保了游戏的随机性。

void SetMine(char Board[ROWS][COLS], int rows, int cols)
{
  int n = EASY_COUNT;//雷的数量
  while (n)
  {
    int x = rand() % 9 + 1;
    int y = rand() % 9 + 1;
    if (Board[x][y] != '1')
    {
      Board[x][y] = '1';
      n--;
    }
  }
}

排查雷及判断输赢函数

void FindMine(char MineBoard[ROWS][COLS], char ShowBoard[ROWS][COLS], int row, int col)
{
  int count = row * col;//未知坐标的数量
  while (count > EASY_COUNT)
  {
    int x, y;
    printf("请输入你想排查的坐标:>");
    scanf("%d%d", &x, &y);
    if ((x >= 1 && x <= row) && (y >= 1 && y <= col))
    {
      if (MineBoard[x][y] == '1')
      {
        printf("很遗憾你踩到雷了,游戏结束\n");
        DisplayBoard(MineBoard, ROWS, COLS);
        break;
      }
      else
      {
        //统计周围雷的数量
        SearchAround(MineBoard, ShowBoard, x, y);
        DisplayBoard(ShowBoard, ROWS, COLS);
        count = JudgeCount(ShowBoard, row, col);
      }
    }
    else
    {
      printf("坐标非法,请重新输入!\n");
    }
  }
  if (count == EASY_COUNT)
  {
    printf("恭喜你扫雷成功:>\n");
    DisplayBoard(MineBoard, ROWS, COLS);
  }
}

返回周围雷数量函数

这里就体现了我们将数组初始化为'0',雷为'1'的好处。通过周围八格的和再减去8*'0'就是周围雷的数量了。

int GetMineCount(char Board[ROWS][COLS],int x,int y)
{
  return (Board[x - 1][y - 1] + Board[x - 1][y] + Board[x - 1][y + 1] +
    Board[x][y - 1] + Board[x][y + 1] +
    Board[x + 1][y - 1] + Board[x + 1][y] + Board[x + 1][y + 1] - 8 * '0');
}

需要注意的是:这里我们必须减去8*'0',否者会出现以下状况

因为这加起来的和是'?'的ASCII表中的值,减去8*'0'才是周围雷的数量

雷区展开函数

//如果排查位置没有雷,且周围位置也没有雷,返回周围一片
void SearchAround(char MineBoard[ROWS][COLS], char ShowBoard[ROWS][COLS], int x, int y)
{
  if (ShowBoard[x][y] == '*')//判断当前位置是否已经赋值
  {
    int arounds = GetMineCount(MineBoard, x, y);
    if (arounds != 0)
    {
      ShowBoard[x][y] = arounds + '0';
    }
    else
    {
      if ((x >= 1 && x <= ROW) && (y >= 1 && y <= COL))
      {
        ShowBoard[x][y] = arounds + ' ';
        SearchAround(MineBoard, ShowBoard, x - 1, y - 1);
        SearchAround(MineBoard, ShowBoard, x - 1, y);
        SearchAround(MineBoard, ShowBoard, x - 1, y + 1);
        SearchAround(MineBoard, ShowBoard, x, y - 1);
        SearchAround(MineBoard, ShowBoard, x, y + 1);
        SearchAround(MineBoard, ShowBoard, x + 1, y - 1);
        SearchAround(MineBoard, ShowBoard, x + 1, y);
        SearchAround(MineBoard, ShowBoard, x + 1, y + 1);
      }
    }
  }
}

这里我们需要注意两个易错点

1.这里必须判断一下当前位置是否赋值,否则将在两个相邻坐标间来回进入此函数,造成死循环;

2.当第一次进入SearchAround()函数时我们知道xy的取值都只是在1~9之间。那么不断递归后xy将越过此范围,造成错误。

未排查坐标数量函数

int JudgeCount(char ShowBoard[ROWS][COLS], int row, int col)
{
  int num = 0;
  for (int i = 1; i <= row; i++)
  {
    for (int j = 1; j <= col; j++)
    {
      if (ShowBoard[i][j] == '*')
        num++;
    }
  }
  return num;
}

源代码

头文件game.h

#define  _CRT_SECURE_NO_WARNINGS 1
#pragma once

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<time.h>

#define EASY_COUNT 10

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

//初始化棋盘
void InitBoard(char Board[ROWS][COLS], int rows, int cols, char set);
//打印棋盘
void DisplayBoard(char Board[ROWS][COLS], int rows, int cols);
//布置雷
void SetMine(char Board[ROWS][COLS], int rows, int cols);
//排查雷
void FindMine(char MineBoard[ROWS][COLS], char ShowBoard[ROWS][COLS], int row, int col);

测试文件test.c

#include "game.h"

void game()
{
  char mine[ROWS][COLS]; // 存放雷信息的棋盘
  char show[ROWS][COLS]; //展示给玩家的棋盘
  //初始化棋盘  
  //mine棋盘全部初始化为'0'    show棋盘全部初始化为'*'
  InitBoard(mine, ROWS, COLS, '0');
  InitBoard(show, ROWS, COLS, '*');
  //打印棋盘
  //DisplayBoard(mine, ROWS, COLS);
  DisplayBoard(show, ROWS, COLS);
  //布置雷
  SetMine(mine, ROWS, COLS);
  //DisplayBoard(mine, ROWS, COLS);
  //排查雷
  FindMine(mine, show, ROW, COL);
}

void manu()
{
  printf("********************\n");
  printf("***   _1.play_   ***\n");
  printf("***   _0.exit_   ***\n");
  printf("********************\n");
}

int main()
{
  int input = 0;
  srand((unsigned int)time(NULL));
  do
  {
    manu();
    printf("请选择:>");
    scanf("%d", &input);
    switch (input)
    {
    case 1:
      game();
      break;
    case 0:
      printf("退出\n");
      break;
    default:
      printf("选择错误,请重新选择:>\n");
      break;
    }
  } while (input);
  return 0;
}

函数实现文件game.c

#include "game.h"

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

//打印棋盘
void DisplayBoard(char Board[ROWS][COLS], int rows, int cols)
{
  int i = 0;
  printf("\n");
  for (i = 0; i <= rows - 2; i++)
    printf("%d ", i);
  printf("\n");
  for (i = 1; i < rows-1; i++)
  {
    int j = 0;
    printf("%d ", i);
    for (j = 1; j < cols-1; j++)
    {
      printf("%c ", Board[i][j]);
    }
    printf("\n");
  }
}

//布置雷
void SetMine(char Board[ROWS][COLS], int rows, int cols)
{
  int n = EASY_COUNT;//雷的数量
  while (n)
  {
    int x = rand() % 9 + 1;
    int y = rand() % 9 + 1;
    if (Board[x][y] != '1')
    {
      Board[x][y] = '1';
      n--;
    }
  }
}

//返回周围雷的数量
int GetMineCount(char Board[ROWS][COLS],int x,int y)
{
  return (Board[x - 1][y - 1] + Board[x - 1][y] + Board[x - 1][y + 1] +
    Board[x][y - 1] + Board[x][y + 1] +
    Board[x + 1][y - 1] + Board[x + 1][y] + Board[x + 1][y + 1] - 8 * '0');
}

//如果排查位置没有雷,且周围位置也没有雷,返回周围一片
void SearchAround(char MineBoard[ROWS][COLS], char ShowBoard[ROWS][COLS], int x, int y)
{
  if (ShowBoard[x][y] == '*')//判断当前位置是否已经赋值
  {
    int arounds = GetMineCount(MineBoard, x, y);
    if (arounds != 0)
    {
      ShowBoard[x][y] = arounds + '0';
    }
    else
    {
      if ((x >= 1 && x <= ROW) && (y >= 1 && y <= COL))
      {
        ShowBoard[x][y] = arounds + ' ';
        SearchAround(MineBoard, ShowBoard, x - 1, y - 1);
        SearchAround(MineBoard, ShowBoard, x - 1, y);
        SearchAround(MineBoard, ShowBoard, x - 1, y + 1);
        SearchAround(MineBoard, ShowBoard, x, y - 1);
        SearchAround(MineBoard, ShowBoard, x, y + 1);
        SearchAround(MineBoard, ShowBoard, x + 1, y - 1);
        SearchAround(MineBoard, ShowBoard, x + 1, y);
        SearchAround(MineBoard, ShowBoard, x + 1, y + 1);
      }
    }
  }
}

int JudgeCount(char ShowBoard[ROWS][COLS], int row, int col)
{
  int num = 0;
  for (int i = 1; i <= row; i++)
  {
    for (int j = 1; j <= col; j++)
    {
      if (ShowBoard[i][j] == '*')
        num++;
    }
  }
  return num;
}

//排查雷
void FindMine(char MineBoard[ROWS][COLS], char ShowBoard[ROWS][COLS], int row, int col)
{
  int count = row * col;//未知坐标的数量
  while (count > EASY_COUNT)
  {
    int x, y;
    printf("请输入你想排查的坐标:>");
    scanf("%d%d", &x, &y);
    if ((x >= 1 && x <= row) && (y >= 1 && y <= col))
    {
      if (MineBoard[x][y] == '1')
      {
        printf("很遗憾你踩到雷了,游戏结束\n");
        DisplayBoard(MineBoard, ROWS, COLS);
        break;
      }
      else
      {
        //统计周围雷的数量
        SearchAround(MineBoard, ShowBoard, x, y);
        DisplayBoard(ShowBoard, ROWS, COLS);
        count = JudgeCount(ShowBoard, row, col);
      }
    }
    else
    {
      printf("坐标非法,请重新输入!\n");
    }
  }
  if (count == EASY_COUNT)
  {
    printf("恭喜你扫雷成功:>\n");
    DisplayBoard(MineBoard, ROWS, COLS);
  }
}


目录
相关文章
|
3天前
|
C语言
【海贼王编程冒险 - C语言海上篇】怎样用C语言实现简单的扫雷游戏?
【海贼王编程冒险 - C语言海上篇】怎样用C语言实现简单的扫雷游戏?
5 1
|
3天前
|
存储 安全 Serverless
扫雷游戏C语言代码实现——万字长文超详细,手把手教你实现,新手也能学会
扫雷游戏C语言代码实现——万字长文超详细,手把手教你实现,新手也能学会
|
4天前
|
存储 C语言
C语言实战——扫雷游戏
C语言实战——扫雷游戏
9 0
|
5天前
|
C语言
扫雷游戏(C语言基础版)
扫雷游戏(C语言基础版)
5 0
|
7天前
|
C语言
·扫雷游戏(C语言版)
·扫雷游戏(C语言版)
|
7天前
|
存储 C语言
C语言---扫雷游戏的实现
C语言---扫雷游戏的实现
|
1月前
|
C语言
C语言实现扫雷
C语言实现扫雷
24 1
|
1月前
|
C语言
【C语言入门小游戏】扫雷
【C语言入门小游戏】扫雷
24 1
TU^
|
1月前
|
存储 C语言
C语言实现扫雷游戏
扫雷游戏是一款十分经典的游戏,运用到C语言中的数组,循环和条件语句,随机数的生成,函数,递归等知识点。
TU^
35 1
|
1月前
|
C语言
【用C语言轻松实现】- 扫雷【超详细教程】
【用C语言轻松实现】- 扫雷【超详细教程】