【C语言】实现简单扫雷游戏(详解)

简介: 【C语言】实现简单扫雷游戏

一、扫雷游戏规则

相信小伙伴们都玩过扫雷游戏,了解一定的简单逻辑规则,如果小伙伴忘记了或者不知道的小伙伴我们先了解一下游戏规则吧。


游戏规则:


在一块N*N的网格中,随机会布置N个雷,左键随机点击一个方格,若方格是雷会显示“被炸死”,方格不是雷,方格即被打开并显示出方格中的数字;方格中数字则表示其周围的8个方格隐藏了几颗雷;如果点开的格子为空白格,即其周围有0颗雷,则其周围格子自动打开;如果其周围还有空白格,则会引发连锁反应;在你认为有雷的格子上,点击右键即可标记雷。

image.png

网页版扫雷游戏:扫雷游戏网页版  点击网页版扫雷,了解游戏逻辑。

二、代码文件的设计

image.png

首先,我们用VS2019编译器在编写小游戏之前,需要创建一个源(.h)文件和两个.c文件。


test.c文件:主要用于整体逻辑的测试


game.c文件:用于编写游戏相关的函数实现


game.h文件:用于编写游戏相关的函数声明及其头文件包含、定义标识符


三、游戏逻辑的设计


image.png

image.png

预先说明:我们这里实现的简单扫雷游戏,并不能实现点击功能,只能根据坐标输入形式进行排雷。


逻辑分析:我们先需要一个N*N的棋盘,这里我们用9*9的棋盘为例,随机放置10个雷,而棋盘的存储需要一个二维数组,我们考虑用“1”布置雷,“0”则表示非雷。为什么不用像“*”、“#”之类的字符,(因为后面判断统计雷的个数情况较复杂,这里预先考虑“0”或者“1”。)观察以下图片,假设🔴是我们排查的雷的坐标(1,1),🔴的周围有1个“1”,代表我们目前排雷的坐标不是雷,且周围有1个雷,那么我们需要统计周围的雷,雷的个数为1,那么是将🔴的坐标的“0”置换为“1”吗,此时被置换为“1”后,不又布置了1个雷吗,这不就冲突了吗?此时我要的是统计周围雷的个数,所以我们需要创建两个二维数组,一个二维数组用来存储“0”或“1”的数据,另一个用来统计周围有若干个雷的数据。再次观察 🔴周围的三个蓝色坐标部分为有效部分,那么,访问并统计周围其他五个坐标时,不就属于数组越界访问了吗?针对这个问题,我们将数组的行和列分别都加上2,这样在统计时以免越界访问,我们暂且称之为虚拟棋盘的大小,而数据的存放和打印我们仅使用蓝色部分的棋盘,我们暂且称之为实际棋盘的大小。


我们逻辑理清 后,再一步步编写代码。


image.png

image.png

🔴 表示选中的坐标;绿色数组表示坐标序号;红方框表示的都是“1”,布置的10个雷,以便分析方便观察;


1.设置游戏菜单

我们从test.c文件开始编写,游戏开始前,需要有一个菜单页面,我们编写到menu()函数之中。


我们希望玩一把不过瘾,想接着继续玩,考虑使用do……while循环结构,选择“1”,我们Play游戏(先写个game()函数);当不想玩了,我们选择“0”,退出游戏,跳出循环;输入其他值,显示“输入有误,请重新选择。”让你重新选择。所以考虑循环里面嵌套一个switch语句。

image.png

 test.c文件

#define  _CRT_SECURE_NO_WARNINGS 
//用于整体逻辑的测试
#include "game.h"
void menu()
{
  printf("********************\n");
  printf("******扫雷游戏******\n");
  printf("******1.Play********\n");
  printf("******0.Exit********\n");
  printf("********************\n");
}
void game()
{
}
int main()
{
  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);
  return 0;
}

2.存储棋盘数据及初始化棋盘

首先我们需要先编写一个mine数组,来存放雷的相关信息,数组元素是“0”和“1”。编写另一个数组show数组,用来表示排查出雷的信息,该数组全部遍历为“*”,以保持隐匿,当排查不是雷的时候,周围的雷的个数就会替换“*”,所以两个数组元素类型我们统一用char类型的数组,两个数组的元素个数我们统一用虚拟棋盘大小来算。


1.存储数据:我们定义标识符常量ROW、COL为实际棋盘的大小,ROWS、COLS为虚拟棋盘的大小,EASY_COUNT为放置雷的个数(简单版本)。


2.我们创建一个InitBoard()来初始化棋盘,初始化两个数组,我们分别传进两个数组,虚拟棋盘大小,以及要初始化的元素(“0”和“*”)。

#define  _CRT_SECURE_NO_WARNINGS 
//用于整体逻辑的测试
#include "game.h"
void menu()
{
  printf("********************\n");
  printf("******扫雷游戏******\n");
  printf("******1.Play********\n");
  printf("******0.Exit********\n");
  printf("********************\n");
}
void game()
{
  //存储数据 
  char mine[ROWS][COLS] = { 0 };
  char show[ROWS][COLS] = { 0 };
  //初始化棋盘
  InitBoard(mine,ROWS,COLS,'0');
  InitBoard(show,ROWS,COLS,'*');
}
int main()
{
  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);
  return 0;
}

game.h文件

#define  _CRT_SECURE_NO_WARNINGS
//用于游戏相关函数的声明及头文件包含
#include<stdio.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);

game.c文件

#define  _CRT_SECURE_NO_WARNINGS 
//用于游戏相关函数的具体实现
#include"game.h"
//初始化棋盘
void InitBoard(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;
    }
  }
}

2.打印棋盘

紧接着,我们创建写一个DisplayBoard()函数来打印棋盘。我们试着先打印mine数组和show数组,需要打印的是实际棋盘的大小,所以传入ROWCOL就行。

test.c文件

#define  _CRT_SECURE_NO_WARNINGS 
//用于整体逻辑的测试
#include "game.h"
void menu()
{
  printf("********************\n");
  printf("******扫雷游戏******\n");
  printf("******1.Play********\n");
  printf("******0.Exit********\n");
  printf("********************\n");
}void game()
{
  //存储数据 
  char mine[ROWS][COLS] = { 0 };
  char show[ROWS][COLS] = { 0 };
  //初始化棋盘
  InitBoard(mine,ROWS,COLS,'0');
  InitBoard(show,ROWS,COLS,'*');
  //打印棋盘
  DisplayBoard(show, ROW, COL);
    DisplayBoard(mine, ROW, COL);
}
int main()
{
  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);
  return 0;
} game.h文件

game.h文件

#define  _CRT_SECURE_NO_WARNINGS
//用于游戏相关函数的声明 及头文件包含
#include<stdio.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);

game.c文件

#define  _CRT_SECURE_NO_WARNINGS 
//用于游戏相关函数的具体实现
#include"game.h"
//初始化棋盘
void InitBoard(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)
{
  printf("*****-- 扫雷 --*****\n");  //作分隔栏,以免观察混淆
  int i = 0;
  for (i = 0; i <= row; i++)
  {
    printf("%d ", i);  //打印列号
  }
  printf("\n");
  for (i = 1; i <= row; i++)
  {
    printf("%d ", i);  //每打印一行之前打印行号。
    int j = 0;
    for (j = 1; j <= col; j++)
    {
      printf("%c ", board[i][j]); //打印初始化元素
    }
    printf("\n");
  }
}

代码打印如下

image.png

3.放置雷

接下来,我们需要设置随机10个雷的遍布,我们编写一个SetMine()函数,需要传入mine数组,需要用到实际棋盘的大小,传入ROWCOL即可。

test.文件

#define  _CRT_SECURE_NO_WARNINGS 
//用于整体逻辑的测试
#include "game.h"
void menu()
{
  printf("********************\n");
  printf("******扫雷游戏******\n");
  printf("******1.Play********\n");
  printf("******0.Exit********\n");
  printf("********************\n");
}void game()
{
  //存储数据 
  char mine[ROWS][COLS] = { 0 };
  char show[ROWS][COLS] = { 0 };
  //初始化棋盘
  InitBoard(mine,ROWS,COLS,'0');
  InitBoard(show,ROWS,COLS,'*');
  //打印棋盘
  DisplayBoard(show, ROW, COL);
  //放置雷
  SetMine(mine,ROW,COL);
}
int main()
{
  int input = 0;
    srand((unsigned int)time(NULL));
  do {
    menu();
    printf("请选择:>");
    scanf("%d", &input);
    switch (input)
    {
    case 1:
      game();
      break;
    case 0:
      printf("退出游戏\n");
      break;
    default:
      printf("输入有误,请重新输入\n");
      break;
    }
  } while (input);
  return 0;
}

game.h文件

SetMine()函数需要用到库函数rand()srand(),因此需要引用头文件<stdlib.h><time.h>

#define  _CRT_SECURE_NO_WARNINGS
//用于游戏相关函数的声明 及头文件包含
#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 mine[ROWS][COLS], int row, int col);

game.c文件

#define  _CRT_SECURE_NO_WARNINGS 
//用于游戏相关函数的具体实现
#include"game.h"
//初始化棋盘
void InitBoard(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)
{
  printf("*****-- 扫雷 --*****\n");
  int i = 0;
  for (i = 0; i <= row; i++)
  {
    printf("%d ", i);
  }
  printf("\n");
  for (i = 1; i <= row; i++)
  {
    printf("%d ", i);
    int j = 0;
    for (j = 1; j <= col; j++)
    {
      printf("%c ", board[i][j]);
    }
    printf("\n");
  }
}
//放置雷
void SetMine(char mine[ROWS][COLS], int row, int col)
{
  int count = EASY_COUNT; //将雷的个数放进计数变量
  while (count)
  {
    int x = rand() % row + 1;  //余数范围 1 ~ row
    int y = rand() % col + 1;  //余数范围 1 ~ col
    if (mine[x][y] == '0') //'0'为非雷
    {
      mine[x][y] = '1'; //当坐标为非雷,放置雷
      count--; //每放置一次雷,count--
    }
  }
}

在写完SetMine()函数,我们再次调用DisplayBoard()函数,发现棋盘随机放置了十个“1”,说明放置雷成功!

image.png

4.排查雷

我们随机放置雷成功后,接下来需要写一个FindMine()函数来排查雷,设计到mine数组和show数组,需要按9*9的序号输入坐标,判断坐标的非法性,所以我们传入ROWCOL

test.c文件

#define  _CRT_SECURE_NO_WARNINGS 
//用于整体逻辑的测试
#include "game.h"
void menu()
{
  printf("********************\n");
  printf("******扫雷游戏******\n");
  printf("******1.Play********\n");
  printf("******0.Exit********\n");
  printf("********************\n");
}void game()
{
  //存储数据 
  char mine[ROWS][COLS] = { 0 };
  char show[ROWS][COLS] = { 0 };
  //初始化棋盘
  InitBoard(mine,ROWS,COLS,'0');
  InitBoard(show,ROWS,COLS,'*');
  //打印棋盘
  DisplayBoard(show, ROW, COL);
  //放置雷
  SetMine(mine,ROW,COL);
  DisplayBoard(mine, ROW, COL);
  //排查雷
  FindMine(mine, show, ROW, COL);
}
int main()
{
  int input = 0;
  srand((unsigned int)time(NULL));
  do {
    menu();
    printf("请选择:>");
    scanf("%d", &input);
    switch (input)
    {
    case 1:
      game();
      break;
    case 0:
      printf("退出游戏\n");
      break;
    default:
      printf("输入有误,请重新输入\n");
      break;
    }
  } while (input);
  return 0;
}

game.h文件

#define  _CRT_SECURE_NO_WARNINGS
//用于游戏相关函数的声明 及头文件包含
#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 mine[ROWS][COLS], int row, int col);
//排查雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);

这里我们需要再编写一个GetMineCount()函数,用于统计该位置(该位置不是雷的情况下)旁边8个坐标雷的个数。但是我们发现统计雷的个数时,“1”是char字符类型,而不是整型数字啊,于是我们考虑将每个字符减去一个‘0’,不就转换为整型了吗?(“1” - “0” = 1,字符“1”的ASCII码值为49,‘0’的ASCII码值为48,相减就得到了1)


game.c文件

#define  _CRT_SECURE_NO_WARNINGS 
//用于游戏相关函数的具体实现
#include"game.h"
//初始化棋盘
void InitBoard(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)
{
  printf("*****-- 扫雷 --*****\n");
  int i = 0;
  for (i = 0; i <= row; i++)
  {
    printf("%d ", i);
  }
  printf("\n");
  for (i = 1; i <= row; i++)
  {
    printf("%d ", i);
    int j = 0;
    for (j = 1; j <= col; j++)
    {
      printf("%c ", board[i][j]);
    }
    printf("\n");
  }
}
//布置雷
void SetMine(char mine[ROWS][COLS], int row, int col)
{
  int count = EASY_COUNT;
  while (count)
  {
    int x = rand() % row + 1;
    int y = rand() % col + 1;
    if (mine[x][y] == '0')
    {
      mine[x][y] = '1';
      count--;
    }
  }
}
//获取该位置周围雷的个数
int GetMineCount(char mine[ROW][COLS], int x, int y)
{
  return (mine[x - 1][y - 1] +
    mine[x][y - 1] +
    mine[x + 1][y - 1] +
    mine[x + 1][y] +
    mine[x + 1][y + 1] +
    mine[x][y + 1] +
    mine[x - 1][y + 1] +
    mine[x - 1][y] - 8 * '0');
}
//排查雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
  int x = 0;
  int y = 0;
  int count = 0;
  int win = 0;
  while (win < row*col - EASY_COUNT) //非雷的地方一直排查
  {
    printf("请输入要排查的坐标:>");
    scanf("%d %d", &x, &y);
    if (x >= 1 && x <= row && y >= 1 && y <= col)  //判断坐标的合法性
    {
      if (show[x][y] == '*') //当show数组为*时,我们进行排雷
      {
        if (mine[x][y] == '1')
        {
          printf("很遗憾,你被炸死了\n");
          DisplayBoard(mine, ROW, COL); //再次显示棋盘,自己如何被炸死的
          break;
        }
        else
        {
                    //该坐标不是雷,就统计周围有几个雷
          count = GetMineCount(mine, x, y); 
          show[x][y] = count + '0'; //再次转换为char类型
          DisplayBoard(show, ROW, COL); //显示周围雷的信息
          win++; //每排查一次成功win++
        }
       }
      else 
      {
        printf("该位置已经被排查\n");  //非*时,说明已经被排查过了
      }
    }
    else
    {
      printf("坐标非法,请重新输入\n");
    }
  }
    //非雷的位置都排查完了 while循环跳出来判断游戏结束
  if (win == row * col - EASY_COUNT) 
  {
    printf("恭喜你,排雷成功!\n");
  }
}

5.测试代码

这里我们定义10个雷不好作测试,如果一个个去排查,会有一定的难度。所以我们暂且直接将EASY_COUNT改为80个,我们将showmine数组都用DisplayBoard()打印出来,以方便测试。

test.c文件

#define  _CRT_SECURE_NO_WARNINGS 
//用于整体逻辑的测试
#include "game.h"
void menu()
{
  printf("********************\n");
  printf("******扫雷游戏******\n");
  printf("******1.Play********\n");
  printf("******0.Exit********\n");
  printf("********************\n");
}void game()
{
  //存储数据 
  char mine[ROWS][COLS] = { 0 };
  char show[ROWS][COLS] = { 0 };
  //初始化棋盘
  InitBoard(mine,ROWS,COLS,'0');
  InitBoard(show,ROWS,COLS,'*');
  //打印棋盘
  DisplayBoard(show, ROW, COL);
  //布置雷
  SetMine(mine,ROW,COL);
  DisplayBoard(mine, ROW, COL);
  //排查雷
  FindMine(mine, show, ROW, COL);
}
int main()
{
  int input = 0;
  srand((unsigned int)time(NULL));
  do {
    menu();
    printf("请选择:>");
    scanf("%d", &input);
    switch (input)
    {
    case 1:
      game();
      break;
    case 0:
      printf("退出游戏\n");
      break;
    default:
      printf("输入有误,请重新输入\n");
      break;
    }
  } while (input);
  return 0;
}

game.h文件

#define  _CRT_SECURE_NO_WARNINGS
//用于游戏相关函数的声明 及头文件包含
#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 80
//初始化棋盘
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 mine[ROWS][COLS], int row, int col);
//排查雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);

game.c文件

#define  _CRT_SECURE_NO_WARNINGS 
//用于游戏相关函数的具体实现
#include"game.h"
//初始化棋盘
void InitBoard(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)
{
  printf("*****-- 扫雷 --*****\n");
  int i = 0;
  for (i = 0; i <= row; i++)
  {
    printf("%d ", i);
  }
  printf("\n");
  for (i = 1; i <= row; i++)
  {
    printf("%d ", i);
    int j = 0;
    for (j = 1; j <= col; j++)
    {
      printf("%c ", board[i][j]);
    }
    printf("\n");
  }
}
//布置雷
void SetMine(char mine[ROWS][COLS], int row, int col)
{
  int count = EASY_COUNT;
  while (count)
  {
    int x = rand() % row + 1;
    int y = rand() % col + 1;
    if (mine[x][y] == '0')
    {
      mine[x][y] = '1';
      count--;
    }
  }
}
//获取该位置周围雷的个数
int GetMineCount(char mine[ROW][COLS], int x, int y)
{
  return (mine[x - 1][y - 1] +
    mine[x][y - 1] +
    mine[x + 1][y - 1] +
    mine[x + 1][y] +
    mine[x + 1][y + 1] +
    mine[x][y + 1] +
    mine[x - 1][y + 1] +
    mine[x - 1][y] - 8 * '0');
}
//排查雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
  int x = 0;
  int y = 0;
  int count = 0;
  int win = 0;
  while (win < row*col - EASY_COUNT) //非雷的地方一直排查
  {
    printf("请输入要排查的坐标:>");
    scanf("%d %d", &x, &y);
    if (x >= 1 && x <= row && y >= 1 && y <= col)  //判断坐标的合法性
    {
      if (show[x][y] == '*') //当show数组为*时,我们进行排雷
      {
        if (mine[x][y] == '1')
        {
          printf("很遗憾,你被炸死了\n");
          DisplayBoard(mine, ROW, COL); //再次显示棋盘,自己如何被炸死的
          break;
        }
        else
        {
                    //该坐标不是雷,就统计周围有几个雷
          count = GetMineCount(mine, x, y); 
          show[x][y] = count + '0'; //再次转换为char类型
          DisplayBoard(show, ROW, COL); //显示周围雷的信息
          win++; //每排查一次成功win++
        }
       }
      else 
      {
        printf("该位置已经被排查\n");  //非*时,说明已经被排查过了
      }
    }
    else
    {
      printf("坐标非法,请重新输入\n");
    }
  }
    //非雷的位置都排查完了 while循环跳出来判断游戏结束
  if (win == row * col - EASY_COUNT) 
  {
    printf("恭喜你,排雷成功!\n");
  }
}

代码写完后,我们测试代码,排查唯一一个没有雷的地方(2,9),最终显示“恭喜你,排雷成功!” ,代码测试完成。

5.4.png

四、完整代码

棋盘9*9的大小,雷随机放置10个的简易扫雷游戏代码,将三个代码文件的完整代码,放置如下

test.c文件

#define  _CRT_SECURE_NO_WARNINGS 
//用于整体逻辑的测试
#include "game.h"
void menu()
{
  printf("********************\n");
  printf("******扫雷游戏******\n");
  printf("******1.Play********\n");
  printf("******0.Exit********\n");
  printf("********************\n");
}void game()
{
  //存储数据 
  char mine[ROWS][COLS] = { 0 };
  char show[ROWS][COLS] = { 0 };
  //初始化棋盘
  InitBoard(mine,ROWS,COLS,'0');
  InitBoard(show,ROWS,COLS,'*');
  //打印棋盘
  DisplayBoard(show, ROW, COL);
  //放置雷
  SetMine(mine,ROW,COL);
  //DisplayBoard(mine, ROW, COL);
  //排查雷
  FindMine(mine, show, ROW, COL);
}
int main()
{
  int input = 0;
  srand((unsigned int)time(NULL));
  do {
    menu();
    printf("请选择:>");
    scanf("%d", &input);
    switch (input)
    {
    case 1:
      game();
      break;
    case 0:
      printf("退出游戏\n");
      break;
    default:
      printf("输入有误,请重新输入\n");
      break;
    }
  } while (input);
  return 0;
}

game.h文件

#define  _CRT_SECURE_NO_WARNINGS
//用于游戏相关函数的声明 及头文件包含
#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 mine[ROWS][COLS], int row, int col);
//排查雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);

game.c文件

#define  _CRT_SECURE_NO_WARNINGS 
//用于游戏相关函数的具体实现
#include"game.h"
//初始化棋盘
void InitBoard(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)
{
  printf("*****-- 扫雷 --*****\n");
  int i = 0;
  for (i = 0; i <= row; i++)
  {
    printf("%d ", i);
  }
  printf("\n");
  for (i = 1; i <= row; i++)
  {
    printf("%d ", i);
    int j = 0;
    for (j = 1; j <= col; j++)
    {
      printf("%c ", board[i][j]);
    }
    printf("\n");
  }
}
//布置雷
void SetMine(char mine[ROWS][COLS], int row, int col)
{
  int count = EASY_COUNT;
  while (count)
  {
    int x = rand() % row + 1;
    int y = rand() % col + 1;
    if (mine[x][y] == '0')
    {
      mine[x][y] = '1';
      count--;
    }
  }
}
//获取该位置周围雷的个数
int GetMineCount(char mine[ROW][COLS], int x, int y)
{
  return (mine[x - 1][y - 1] +
    mine[x][y - 1] +
    mine[x + 1][y - 1] +
    mine[x + 1][y] +
    mine[x + 1][y + 1] +
    mine[x][y + 1] +
    mine[x - 1][y + 1] +
    mine[x - 1][y] - 8 * '0');
}
//排查雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
  int x = 0;
  int y = 0;
  int count = 0;
  int win = 0;
  while (win < row*col - EASY_COUNT) //非雷的地方一直排查
  {
    printf("请输入要排查的坐标:>");
    scanf("%d %d", &x, &y);
    if (x >= 1 && x <= row && y >= 1 && y <= col)  //判断坐标的合法性
    {
      if (show[x][y] == '*') //当show数组为*时,我们进行排雷
      {
        if (mine[x][y] == '1')
        {
          printf("很遗憾,你被炸死了\n");
          DisplayBoard(mine, ROW, COL); //再次显示棋盘,自己如何被炸死的
          break;
        }
        else
        {
                    //该坐标不是雷,就统计周围有几个雷
          count = GetMineCount(mine, x, y); 
          show[x][y] = count + '0'; //再次转换为char类型
          DisplayBoard(show, ROW, COL); //显示周围雷的信息
          win++; //每排查一次成功win++
        }
       }
      else 
      {
        printf("该位置已经被排查\n");  //非*时,说明已经被排查过了
      }
    }
    else
    {
      printf("坐标非法,请重新输入\n");
    }
  }
    //非雷的位置都排查完了 while循环跳出来判断游戏结束
  if (win == row * col - EASY_COUNT) 
  {
    printf("恭喜你,排雷成功!\n");
  }
}

最后,该代码还有值得被优化的地方,比如,如果点开的格子不是雷,即其周围有0颗雷,则其周围格子自动打开;如果其周围还有‘0’,则会引发连锁反应;在你认为有雷的格子上,点击右键即可标记雷;游戏计时等诸多功能。有兴趣的话,小伙伴们,可以尝试着优化一下噢~

目录
相关文章
|
11月前
|
C语言
C语言之斗地主游戏
该代码实现了一个简单的斗地主游戏,包括头文件引入、宏定义、颜色枚举、卡牌类、卡牌类型类、卡牌组合类、玩家类、游戏主类以及辅助函数等,涵盖了从牌的生成、分配、玩家操作到游戏流程控制的完整逻辑。
326 8
|
12月前
|
C语言
扫雷游戏(用C语言实现)
扫雷游戏(用C语言实现)
222 0
|
11月前
|
存储 算法 C语言
用C语言开发游戏的实践过程,包括选择游戏类型、设计游戏框架、实现图形界面、游戏逻辑、调整游戏难度、添加音效音乐、性能优化、测试调试等内容
本文探讨了用C语言开发游戏的实践过程,包括选择游戏类型、设计游戏框架、实现图形界面、游戏逻辑、调整游戏难度、添加音效音乐、性能优化、测试调试等内容,旨在为开发者提供全面的指导和灵感。
408 2
|
11月前
|
C语言 Windows
C语言课设项目之2048游戏源码
C语言课设项目之2048游戏源码,可作为课程设计项目参考,代码有详细的注释,另外编译可运行文件也已经打包,windows电脑双击即可运行效果
106 1
|
12月前
|
存储 C语言
揭秘C语言:泊舟的猜数字游戏
揭秘C语言:泊舟的猜数字游戏
190 2
|
12月前
|
编译器 C语言
猜数字游戏实现#C语言
猜数字游戏实现#C语言
214 1
|
12月前
|
存储 算法 安全
C语言实现扫雷游戏
C语言实现扫雷游戏
|
12月前
|
C语言
初学者指南:使用C语言实现简易版扫雷游戏
初学者指南:使用C语言实现简易版扫雷游戏
158 0
|
12月前
|
C语言
C语言扫雷游戏(详解)
C语言扫雷游戏(详解)
107 0
|
12月前
|
程序员 C语言
初识C语言之三子棋游戏
初识C语言之三子棋游戏
89 0