扫雷小游戏 递归展开

简介: 扫雷小游戏 递归展开

相信大家对扫雷小游戏都不陌生,今天我们就用C语言来实现一下9*9的扫雷游戏


效果图:

在实习时我们会遇到两个问题

1.越界访问


因为要实现9*9的游戏棋盘,要使用9*9的二维数组,我们知道扫雷中会有统计周围8个空间雷数的步骤,当我统计第一行第一列周围雷数时,也就是数组 [0][0] 周围的雷数时,会导致越界访问,因为我们没有办法访问到该点上面的元素,所以在实现时我们实际上是使用的11*11的数组,数组最边上的元素我们不用,这样就不用担心越界访问了。


2.两个棋盘


在实现时我们需要使用两个棋盘,是因为我们在没有排雷之前是需要用 '*' 遮住整个棋盘的,而且我们还需要一个二位数组来存放雷的位置,是雷数组赋值为 '1' ,不是雷赋值为 '0'。所以一个棋盘是不够的


我们在最开始使用宏定义行和列,还有雷的数目。

#define COUNT 10//雷的数量
#define ROW 9  //行
#define COL 9  //列
#define ROWS ROW+2
#define COLS COL+2


1.定义棋盘

1. char mine[ROWS][COLS];//存放布置好的雷
2. char show[ROWS][COLS];//存放排除出雷的信息 ,显示给用户


2.初识化棋盘

InitBoard(mine, ROWS, COLS, '0');
InitBoard(show, ROWS, COLS, '*');
//为了俩个棋盘都能使用,我们传入要初始化的值
//不是雷为 ‘0’  是雷 ‘1’
//函数的定义
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;//初始化
    }
  }
}


3.打印棋盘

DisplayBoard(mine, ROW, COL);
DisplayBoard(show, ROW, COL);
//定义
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
  int i = 0;
  int j = 0;
  for (j = 0; j < col / 2; j++)
  {
    printf("****");
  }
  printf("扫雷游戏");
  for (j = 0; j < col / 2; j++)
  {
    printf("****");
  }
  if (col % 2 != 0)
    printf("*");
  printf("\n");
  for (j = 0; j < col + 1; j++)
  {
    printf("----");
  }
  printf("-\n");
  for (i = 0; i < row + 1; i++)
  {
    printf("| %d |", i);
    for (j = 1; j < col + 1; j++)
    {
      if (i == 0)
        printf(" %d |", j);//打印坐标
      else if (board[i][j] == '0')
      {
        printf("   |");
      }
      else
        printf(" %c |", board[i][j]);//打印棋盘数组元素
    }
    printf("\n");
    if(i<row)
    {
      for (j = 0; j < col + 1; j++)
      {
        printf("|---");
      }
      printf("|\n");
    }
  }
  for (j = 0; j < col + 1; j++)
  {
    printf("----");
  }
  printf("-\n");
}


4.布置雷

生成随机数

//布置雷
void SetMine(char mine[ROWS][COLS], int row, int col)
{
  int x = 0;
  int y = 0;
  int count = COUNT;//10
  while(count>0)//生成10个雷
  {
    x = rand() % row + 1;// 1到9
    y = rand() % col + 1;// 1到9
    if (mine[x][y] == '0')//确定这个位置不是雷
    {
      mine[x][y] = '1';//布雷成功
      count--;
    }
  }
}


5.排查雷

统计周围雷的数量我们可以使周围9个字符相加再加减去9个‘0’。

递归展开有三个限制条件

1.不能越界数组  if (x >= 1 && x <= row && y >= 1 && y <= col)


2.展开的前提是周围没有雷  if (ShowCount(mine, show, x, y) != '0')


3.展开的是还没有排查的坐标  if (show[i][j]=='*')


展开效果图:

//显示周围雷数
char ShowCount(char mine[ROWS][COLS], char show[ROWS][COLS], int x,int y)
{
  show[x][y] = '0';
  for (int i = x - 1; i <= x + 1; i++)
  {
    for (int j = y - 1; j <= y + 1; j++)
    {
      show[x][y] += mine[i][j];
    }
  }
  show[x][y] -= 9 * '0';
  return show[x][y];
}
//递归展开
void OpenUp(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col, int x, int y)
{
  if (x >= 1 && x <= row && y >= 1 && y <= col)
  {
    if (ShowCount(mine, show, x, y) != '0')
    {
      return;
    }
    else
    {
      for (int i = x - 1; i <= x + 1; i++)
      {
        for (int j = y - 1; j <= y + 1; j++)
        {
          if (show[i][j]=='*')
            OpenUp(mine, show, row, col, i, j);
        }
      }
    }
  }
  else {
    return;
  }
}
//排查雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
  int x = 0;
  int y = 0;
  int count = 0;
  while (1)
  {
    printf("请输入你要排查的坐标:>");
    scanf("%d %d", &x, &y);
    if (x <= row && x >= 1 && y <= col && y >= 1)
    {
      if (show[x][y] == '*')
      {
        if (mine[x][y] == '1')
        {
          system("cls");
          DisplayBoard(mine, ROW, COL);
          printf("很遗憾你被炸死了,游戏结束\n");
          system("pause");
          system("cls");
          break;
        }
        else
        {
          system("cls");
          OpenUp(mine, show, row, col, x, y);
          DisplayBoard(show, ROW, COL);
          //判断是否胜利
          count = 0;
          for (int i = 1; i < row + 1; i++)
          {
            for (int j = 1; j < col + 1; j++)
            {
              if (show[i][j] == '*')
                count++;
            }
          }
          if (count == COUNT)
          {
            system("cls");
            DisplayBoard(mine, ROW, COL);
            printf("恭喜你排雷成功\n");
            system("pause");
            system("cls");
            break;
          }
        }
      }
      else
      {
        printf("该坐标已被排查,请重新输入\n");
      }
    }
    else
    {
      printf("输入非法,请重新输入\n");
    }
  }
}


6.全部代码:

game.h文件

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#define 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 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文件

#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 row, int col)
{
  int i = 0;
  int j = 0;
  for (j = 0; j < col / 2; j++)
  {
    printf("****");
  }
  printf("扫雷游戏");
  for (j = 0; j < col / 2; j++)
  {
    printf("****");
  }
  if (col % 2 != 0)
    printf("*");
  printf("\n");
  for (j = 0; j < col + 1; j++)
  {
    printf("----");
  }
  printf("-\n");
  for (i = 0; i < row + 1; i++)
  {
    printf("| %d |", i);
    for (j = 1; j < col + 1; j++)
    {
      if (i == 0)
        printf(" %d |", j);//打印坐标
      else if (board[i][j] == '0')
      {
        printf("   |");
      }
      else
        printf(" %c |", board[i][j]);//打印棋盘数组元素
    }
    printf("\n");
    if(i<row)
    {
      for (j = 0; j < col + 1; j++)
      {
        printf("|---");
      }
      printf("|\n");
    }
  }
  for (j = 0; j < col + 1; j++)
  {
    printf("----");
  }
  printf("-\n");
}
//布置雷
void SetMine(char mine[ROWS][COLS], int row, int col)
{
  int x = 0;
  int y = 0;
  int count = COUNT;
  while(count>0)
  {
    x = rand() % row + 1;// 1到9
    y = rand() % col + 1;// 1到9
    if (mine[x][y] == '0')
    {
      mine[x][y] = '1';
      count--;
    }
  }
}
//显示周围雷数
char ShowCount(char mine[ROWS][COLS], char show[ROWS][COLS], int x,int y)
{
  show[x][y] = '0';
  for (int i = x - 1; i <= x + 1; i++)
  {
    for (int j = y - 1; j <= y + 1; j++)
    {
      show[x][y] += mine[i][j];
    }
  }
  show[x][y] -= 9 * '0';
  return show[x][y];
}
void OpenUp(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col, int x, int y)
{
  if (x >= 1 && x <= row && y >= 1 && y <= col)
  {
    if (ShowCount(mine, show, x, y) != '0')
    {
      return;
    }
    else
    {
      for (int i = x - 1; i <= x + 1; i++)
      {
        for (int j = y - 1; j <= y + 1; j++)
        {
          if (show[i][j]=='*')
            OpenUp(mine, show, row, col, i, j);
        }
      }
    }
  }
  else {
    return;
  }
}
//排查雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
  int x = 0;
  int y = 0;
  int count = 0;
  while (1)
  {
    printf("请输入你要排查的坐标:>");
    scanf("%d %d", &x, &y);
    if (x <= row && x >= 1 && y <= col && y >= 1)
    {
      if (show[x][y] == '*')
      {
        if (mine[x][y] == '1')
        {
          system("cls");
          DisplayBoard(mine, ROW, COL);
          printf("很遗憾你被炸死了,游戏结束\n");
          system("pause");
          system("cls");
          break;
        }
        else
        {
          system("cls");
          OpenUp(mine, show, row, col, x, y);
          DisplayBoard(show, ROW, COL);
          //判断是否胜利
          count = 0;
          for (int i = 1; i < row + 1; i++)
          {
            for (int j = 1; j < col + 1; j++)
            {
              if (show[i][j] == '*')
                count++;
            }
          }
          if (count == COUNT)
          {
            system("cls");
            DisplayBoard(mine, ROW, COL);
            printf("恭喜你排雷成功\n");
            system("pause");
            system("cls");
            break;
          }
        }
      }
      else
      {
        printf("该坐标已被排查,请重新输入\n");
      }
    }
    else
    {
      printf("输入非法,请重新输入\n");
    }
  }
}


test.c文件

#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];//存放布置好的雷
  char show[ROWS][COLS];//存放排除出雷的信息
  //初始化棋盘
  InitBoard(mine, ROWS, COLS, '0');
  InitBoard(show, ROWS, COLS, '*');
  //打印棋盘
  //DisplayBoard(mine, ROW, COL);
  DisplayBoard(show, 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("%d", &input);
    switch (input)
    {
    case 1:
      system("cls");
      printf("游戏开始\n");
      game();
      break;
    case 0:
      printf("退出游戏\n");
      break;
    default:
      printf("输入错误,请重新输入\n");
      system("pause");
      system("cls");
      break;
    }
  }while (input);
  return 0;
}


谢谢观看,希望对大家有帮助

相关文章
|
机器学习/深度学习 算法 Python
动态规划法和策略迭代在扫地机器人中确定状态值和动作值函数的策略评估(python实现 附源码 超详细)
动态规划法和策略迭代在扫地机器人中确定状态值和动作值函数的策略评估(python实现 附源码 超详细)
231 1
|
编解码
STM32:PWM驱动舵机(内含:1.接线原理图/实物图+2.代码部分+3.补充知识部分)
STM32:PWM驱动舵机(内含:1.接线原理图/实物图+2.代码部分+3.补充知识部分)
2608 1
STM32:PWM驱动舵机(内含:1.接线原理图/实物图+2.代码部分+3.补充知识部分)
|
机器学习/深度学习 人工智能
48小时封镜!这是一部完全由AI制作的科幻电影
在伦敦科幻电影节的“48小时电影挑战”,导演Oscar Sharp和AI研究员Ross Goodwin带来一部全部制作过程由AI导演的实验性影片《Zone Out》。影片采用“换脸”技术,使用神经网络生成的对话和配音等,整个制作过程都由被称为Benjamin的AI进行处理。
2582 0
|
11月前
|
SQL XML 关系型数据库
入门指南:利用NHibernate简化.NET应用程序的数据访问
【10月更文挑战第13天】NHibernate是一个面向.NET的开源对象关系映射(ORM)工具,它提供了从数据库表到应用程序中的对象之间的映射。通过使用NHibernate,开发者可以专注于业务逻辑和领域模型的设计,而无需直接编写复杂的SQL语句来处理数据持久化问题。NHibernate支持多种数据库,并且具有高度的灵活性和可扩展性。
226 2
|
12月前
|
人工智能 搜索推荐 安全
脑机接口技术:提升人机交互的前沿探索
【9月更文挑战第29天】脑机接口(BCI)技术借助人工智能与神经科学的进步,实现了人脑与外部设备的直接连接,开辟了人机交互新纪元。该技术通过捕捉并转化神经信号,使用户能直接控制设备或接收反馈,已在医疗、教育、娱乐等领域展现巨大潜力。例如,在医疗上,它帮助患者恢复运动和语言功能;在教育中,实现个性化学习;在娱乐领域,则提供沉浸式体验。尽管面临技术、伦理及隐私挑战,但其发展前景广阔,有望革新生活方式和社会结构。
|
数据可视化 前端开发 JavaScript
Echarts+JS实现农业指挥舱可视化大屏!!附源码!!
Echarts+JS实现农业指挥舱可视化大屏!!附源码!!
一文教你学会keil软件仿真
一文教你学会keil软件仿真
1956 1
|
存储 算法 C语言
蓝桥杯省赛冲刺(2)深度优先搜索
蓝桥杯省赛冲刺(2)深度优先搜索
292 0
|
Linux 数据安全/隐私保护 iOS开发
Linux的root用户,普通用户无法在根录中创建文件,一般在其HOME目录里是不受限的,一旦出了HOME目录,大多数地方,仅有读和执行的权限,ctrl + d回到上一个用户,Exit,su - ro
Linux的root用户,普通用户无法在根录中创建文件,一般在其HOME目录里是不受限的,一旦出了HOME目录,大多数地方,仅有读和执行的权限,ctrl + d回到上一个用户,Exit,su - ro
|
编解码 网络性能优化 芯片
如何用51单片机实现pwm调光+呼吸灯(超详细+源码)
如何用51单片机实现pwm调光+呼吸灯(超详细+源码)
1809 0
如何用51单片机实现pwm调光+呼吸灯(超详细+源码)