扫雷游戏简单实现

简介: 扫雷游戏简单实现

 目录

定义的一些变量

设计思路

为什么设计两个数组棋盘?

为什么游戏是9*9但设计数组要设计11*11?

初始化函数

为什么要把雷的棋盘初始化为0?

打印函数

布置雷

排除雷

解释为什么先前初始化记数字棋盘时选择0和1:

可以存在的优化

递归函数实现展开

借助图形库可视化能力更强

全部源码


定义的一些变量

为了代码的可读性和可操作性,开始前要定义一些值,后续有讲解:

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

image.gif


设计思路

我们要创建两个字符串二维数组,一个用来存储雷的位置,一个用来给玩家提示信息的位置,玩家输入一个坐标,如果这个坐标是雷,就提示玩家被炸了,如果这个坐标不是雷,则提示玩家周围雷的数量,供玩家进行排雷。

为什么设计两个数组棋盘?

如果设计一个棋盘,则排雷和提示用户雷容易被干扰,代码可读性不强,而假设选择两个数组,把存储雷和排雷分开放,就可以在完成项目的同时还能使得代码可读性增强。

为什么游戏是9*9但设计数组要设计11*11?

在统计数量时,我们统计的是以该点为中心周围八个点的雷的个数,如果数组设置为9*9,那么在统计周围雷的个数时会导致越界访问,产生不必要的麻烦,因此在设计时选择11*11可以避免这样的问题。


初始化函数

棋盘被创建好了,那么就该进行初始化了,初始化后的内容就是要让用户看到的内容,在本实验的思路中,我们选择的是让用户看到的棋盘被*覆盖,但用来存放的棋盘也需要被初始化,于是初始化函数中可以加入新的参数。

为什么要把雷的棋盘初始化为0?

便于统计个数,后续的代码实现中会发现这样设置的优越性。

函数的实现:

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

image.gif

打印函数

棋盘被设置和初始化后,就可以进行打印棋盘的函数实现了,只需要打印出数组的内容即可,要注意的是为了可读性,要打印出行和列对应的数字,代码实现如下:

void Displayboard(char board[][COLS], int row, int col)
{
  for (int i = 0; i <= row; i++)
  {
    if (i == 0)
      printf("%d|",i);
    else
        printf("%d ", i);
  }
  printf("\n");
  for (int i = 0; i < row; i++)
  {
    printf("--");
  }
  printf("\n");
  for (int i = 1; i <= row; i++)
  {
    printf("%d|", i);
    for (int j = 1; j <= col; j++)
    {
      printf("%c ", board[i][j]);
    }
    printf("\n");
  }
  printf("\n");
}

image.gif

布置雷

开头定义中我们定义了雷的个数,那么在实现函数时,基本思路是运用while循环,如果布置成功了就让雷的个数减一,直到雷的个数为0,此时判断结果为假,则此时就跳出循环,在进行判断时增加一些限制条件,判断坐标合法性等,综合考量就能得出下面的代码实现原理:

void Setmine(char mineboard[][COLS], int row, int col)
{
  int num = Set;
  while (num)
  {
    int x = rand() % row + 1;
    int y = rand() % col + 1;
    if (mineboard[x][y] == '0')
    {
      mineboard[x][y] = '1';
      num--;
    }
  }
}

image.gif


排除雷

来看实现的基本思路,玩家输入坐标,如果恰好是雷的位置那么玩家就被淘汰出局,如果不是雷的位置就显示周围雷的个数。

解释为什么先前初始化记数字棋盘时选择0和1:

在统计雷的个数的时候,统计的是周围八个格子的数据,如果先前我们选择的是#等作为雷的标记,那么在统计雷的时候就非常麻烦,但如果选择的是0和1,只需要把这些数据加起来最后减去一个'0'即可,这样就能把char类型的数据转换成int类型的数据,再返回到函数中即可。

那么具体的实现为:

int Count(char board[][COLS], int x, int y)
{
  return (board[x - 1][y] + board[x - 1][y - 1] + board[x - 1][y + 1] + board[x][y - 1] +
    board[x][y + 1] + board[x + 1][y] + board[x + 1][y - 1] + board[x + 1][y + 1]- 8*'0');
}
void FindSets(char mineboard[][COLS], char showboard[][COLS], int row, int col)
{
  int x=0, y=0;
  int nums = row * col - Set;
  while (nums)
  {
    printf("请输入坐标:-->");
    scanf("%d %d", &x, &y);
    if (x >= 1 && x <= 9 && y >= 1 && y <= 9)
    {
      if (mineboard[x][y] == '1')
      {
        printf("被炸死了\n");
        break;
      }
      else
      {
        int ret = Count(mineboard, x, y);
        showboard[x][y] = ret + '0';
        Displayboard(showboard, ROW, COL);
        nums--;
      }
    }
    else
    {
      printf("坐标不合法,重新输入\n");
    }
  }
  if (nums == 0)
  {
    printf("扫雷成功,游戏结束\n");
  }
}

image.gif

可以存在的优化

递归函数实现展开

在实际的游戏过程中,在玩家点击一块没有雷的方格时,会将周围的部分都展开,而本文写的这个代码游戏不能达成这个效果,这里可以进行一定程度的优化,可以使用递归函数进行每个九宫格的展开。

借助图形库可视化能力更强

在实际游戏中是用了图形库的,这里只是一个简单的游戏实现,不包括图形库,图形库也可以作为代码的优化。

全部源码

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
#define Set 10
void Initboard(char board[][COLS], int rows, int cols, char c)
{
  for (int i = 0; i < rows; i++)
  {
    for (int j = 0; j < cols; j++)
      board[i][j] = c;
  }
}
void Displayboard(char board[][COLS], int row, int col)
{
  for (int i = 0; i <= row; i++)
  {
    if (i == 0)
      printf("%d|",i);
    else
        printf("%d ", i);
  }
  printf("\n");
  for (int i = 0; i < row; i++)
  {
    printf("--");
  }
  printf("\n");
  for (int i = 1; i <= row; i++)
  {
    printf("%d|", i);
    for (int j = 1; j <= col; j++)
    {
      printf("%c ", board[i][j]);
    }
    printf("\n");
  }
  printf("\n");
}
void Setmine(char mineboard[][COLS], int row, int col)
{
  int num = Set;
  while (num)
  {
    int x = rand() % row + 1;
    int y = rand() % col + 1;
    if (mineboard[x][y] == '0')
    {
      mineboard[x][y] = '1';
      num--;
    }
  }
}
int Count(char board[][COLS], int x, int y)
{
  return (board[x - 1][y] + board[x - 1][y - 1] + board[x - 1][y + 1] + board[x][y - 1] +
    board[x][y + 1] + board[x + 1][y] + board[x + 1][y - 1] + board[x + 1][y + 1]- 8*'0');
}
void FindSets(char mineboard[][COLS], char showboard[][COLS], int row, int col)
{
  int x=0, y=0;
  int nums = row * col - Set;
  while (nums)
  {
    printf("请输入坐标:-->");
    scanf("%d %d", &x, &y);
    if (x >= 1 && x <= 9 && y >= 1 && y <= 9)
    {
      if (mineboard[x][y] == '1')
      {
        printf("被炸死了\n");
        break;
      }
      else
      {
        int ret = Count(mineboard, x, y);
        showboard[x][y] = ret + '0';
        Displayboard(showboard, ROW, COL);
        nums--;
      }
    }
    else
    {
      printf("坐标不合法,重新输入\n");
    }
  }
  if (nums == 0)
  {
    printf("扫雷成功,游戏结束\n");
  }
}
void menu()
{
  printf("*****************************\n");
  printf("*********  1.game  **********\n");
  printf("*********  0.exit  **********\n");
  printf("*****************************\n");
}
void game()
{
  srand((unsigned int)time(NULL));
  char mineboard[ROWS][COLS];
  char showboard[ROWS][COLS];
  Initboard(mineboard, ROWS, COLS, '0');
  Initboard(showboard, ROWS, COLS, '*');
  Displayboard(showboard, ROW, COL);
  Setmine(mineboard, ROW, COL);
  FindSets(mineboard, showboard, 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");
    }
  } while (input);
  return 0;
}

image.gif


相关文章
|
1月前
贪吃蛇游戏(代码篇)
贪吃蛇游戏(代码篇)
77 0
|
6月前
|
存储
数组和函数实践:扫雷游戏
数组和函数实践:扫雷游戏
|
6月前
扫雷游戏(优化版)
扫雷游戏(优化版)
60 0
扫雷游戏(优化版)
扫雷的简单实现
扫雷的简单实现
51 0
|
C语言
C/关于扫雷小游戏的创建
C/关于扫雷小游戏的创建
|
6月前
|
C语言
探索经典游戏:扫雷小游戏
探索经典游戏:扫雷小游戏
96 0
|
C语言
井字棋的简单实现
井字棋的简单实现
56 0
|
C语言
经典游戏扫雷详解--你也可以写出扫雷和玩好扫雷(上)
经典游戏扫雷详解--你也可以写出扫雷和玩好扫雷(上)
153 0