扫雷进阶版(含递归实现,插旗)

简介: 扫雷进阶版(含递归实现,插旗)

一.Main函数(主题函数的构造)


#include"scan.h"//这个是头文件
//扫雷,首先实现一个简易版以#代替雷,以' '代替没有雷,本身是' '周围有雷就要计数
void game()
{
  //设置两个表,一个给用户看,一个自行查看
  char mine[Rows][Cols] = { 0 };
  char show[Rows][Cols] = { 0 };
  //初始化表格
  Initboard(mine, Rows, Cols, ' ');
  Initboard(show, Rows, Cols, '*');
  //设置地雷
  Setmine(mine,Row, Col);
  //打印表格
  once_scan(mine, show, Row, Col);
  Disboard(show, Row, Col);
  //这个是答案
  //Disboard(mine, Row, Col);
  //选定位置,开始扫雷
  Scanmine(mine, show, Row, Col);
}
int main()
{
  int input = 0;
  srand((unsigned int)time(NULL));
  do
  {
  Mainmenu();//先制作一个菜单
  scanf("%d", &input);
  switch (input)
  {
  case 1:
    printf("--------扫雷游戏--------\n");
    game();
    break;
  case 0:
    printf("退出成功\n");
    break;
  default:
    printf("选择错误,请重新选择\n");
    break;
  }
  } while (input);
  return 0;
}


二.函数构造


#include"scan.h"
void Mainmenu()
{
  printf("************************\n");
  printf("*****1.play  0.exit*****\n");
  printf("************************\n");
}
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++)
  {
    if (i >= 1 && i <= Row && j >= 1 && j <= Col)
    board[i][j] = set;
    else
    board[i][j] = '0';
  }
  }
}
void Setmine(char mine[Rows][Cols], int row, int col)
{
  int x = 0;
  int y = 0;
  int count = COUNT;
  while (count)
  {
  x = rand() % row + 1;
  y = rand() % col + 1;
  if (mine[x][y] == ' ')
  {
    mine[x][y] = '#';
    count--;
  }
  }
}
void Disboard(char board[Rows][Cols], int row, int col)
{
  int i, j;
  for (i = 0; i <= row; i++)
  {
  printf("%d ", i);
  }
  printf("\n");
  for (i = 1; i <= row; i++)
  {
  printf("%d ", i);
  for (j = 1; j <= col; j++)
  {
    printf("%c ", board[i][j]);
  }
  printf("\n");
  }
}
int Get_mine(char mine[Rows][Cols],int x, int y)
{
  int i, j;
  int count = 0;
  for (i = x - 1; i <= x + 1; i++)
  {
  for (j = y - 1; j <= y + 1; j++)
  {
    if (mine[i][j] == '#')
    count++;
  }
  }
  return count;
}
void invest(char mine[Rows][Cols],char show[Rows][Cols],int x, int y)
{
  int i, j;
  int count = 0;
  //编写一个统计雷的个数的函数
  for (i = x - 1; i <= x + 1; i++)
  {
  for (j = y - 1; j <= y + 1; j++)
  {
    if (mine[i][j] == ' ')
    {
    count = Get_mine(mine, i, j);
    //周围没有雷的才去递归
    if (count == 0)
    {
      if (show[i][j] == '*')
      {
      show[i][j] = ' ';
      invest(mine, show, i, j);
      }
    }
    else
    {
      show[i][j] = count+'0';
    }
    }
  }
  }
}
void once_scan(char mine[Rows][Cols], char show[Rows][Cols], int row, int col)
{
  int x, y;
  while (1)
  {
  x = rand() % row + 1;
  y = rand() % col + 1;
  if (mine[x][y] != '#')
  {
    //第一次自动递归
    //成功在于插旗,插旗和雷的个数一样多,插旗过后如果插旗的个数(判断那个坐标是否为雷)==雷的个数则胜利
    //如果不插旗,统计show棋盘上(*+$)的个数,如果(*+$)的个数等于雷的个数,那么说明成功.
    //关键是递归函数的编译.
    invest(mine, show, x, y);//递归
    break;
  }
  }
}
int is_win(char show[Rows][Cols], int row, int col)
{
  int i, j;
  int count = 0;
  for (i = 1; i <= row; i++)
  {
  for (j = 1; j <= col; j++)
  {
    if (show[i][j] == '*' || show[i][j] == '$')
    count++;
  }
  }
  return count;
}
void pflag(char show[Rows][Cols], int row, int col)
{
  int x, y,z;
  int count = COUNT;
  while (1)
  {
  if (count == 0)
  {
    printf("请注意,当前已无可用旗\n");
  }
  printf("请输入要标记/取消标记的坐标\n");
  scanf("%d%d", &x, &y);
  if (x >= 1 && x <= row && y >= 1 && y <= col)
  {
    if (show[x][y] == '*' &&(count > 0))
    {
    show[x][y] = '$';
    count--;
    Disboard(show, row, col);
    if (count == 0)
    {
      printf("不可继续标记\n");
      break;
    }
    else
    {
      printf("是否继续标记?:1.continue 其他:break\n");
      scanf("%d", &z);
      if (z == 1 && count> 0)
      {
      continue;
      }
      else
      {
      printf("退出标记成功\n");
      break;
      }
    }
    }
    else if (show[x][y] == '$')
    {
    show[x][y] = '*';
    count++;
    Disboard(show, row, col);
    printf("是否继续取消标记?:1.continue 其他:break\n");
    scanf("%d", &z);
    if (z == 1)
    {
      continue;
    }
    else
    {
      printf("继续游戏\n");
      break;
    }
    }
    else
    {
    printf("该坐标已经展开,请重新输入\n");
    }
  }
  else
  {
    printf("输入错误,请重新输入\n");
  }
  }
}
void Scanmine(char mine[Rows][Cols], char show[Rows][Cols], int row, int col)
{
  //开始扫雷
  int x, y,z;//插旗,拔旗
  while (1)
  {
  printf("请输入您要勘察的位置\n");
  scanf("%d%d", &x, &y);
  if (x >= 1 && x <= row && y >= 1 && y <= col)
  {
    //已经填过的数要是再次填,会如何?需要判断
    if (mine[x][y] == '#')
    {
    printf("很遗憾,你被炸死了\n");
    Disboard(mine, row, col);
    break;
    }
    else if (mine[x][y] == ' ' && (show[x][y] == '*'||show[x][y]=='$'))
    {
    invest(mine, show, x, y);
    Disboard(show, row, col);
    int ret = is_win(show, row, col);
    if (ret == COUNT)
    {
      printf("恭喜你,排雷成功\n");
      Disboard(mine, row, col);
      break;
    }
    printf("是否插旗/拔旗?:>1.插旗/拔旗 其他.No\n");
    scanf("%d", &z);
    if (z == 1)
    {
      pflag(show, row, col);
    }
    else
    {
      printf("继续游戏\n");
    }
    }
    else
    printf("该坐标已经被访问过,请重新输入\n");
  }
  else
  {
    printf("访问坐标非法,请重新输入\n");
  }
  }
}


①递归实现


void invest(char mine[Rows][Cols],char show[Rows][Cols],int x, int y)
{
  int i, j;
  int count = 0;
  //编写一个统计雷的个数的函数
  for (i = x - 1; i <= x + 1; i++)
  {
  for (j = y - 1; j <= y + 1; j++)
  {
    if (mine[i][j] == ' ')
    {
    count = Get_mine(mine, i, j);
    //周围没有雷的才去递归
    if (count == 0)
    {
      if (show[i][j] == '*')
      {
      show[i][j] = ' ';
      invest(mine, show, i, j);
      }
    }
    else
    {
      show[i][j] = count+'0';
    }
    }
  }
  }
}


②.插旗拔旗的构造


int is_win(char show[Rows][Cols], int row, int col)
{
  int i, j;
  int count = 0;
  for (i = 1; i <= row; i++)
  {
  for (j = 1; j <= col; j++)
  {
    if (show[i][j] == '*' || show[i][j] == '$')
    count++;
  }
  }
  return count;
}
void pflag(char show[Rows][Cols], int row, int col)
{
  int x, y,z;
  int count = COUNT;
  while (1)
  {
  if (count == 0)
  {
    printf("请注意,当前已无可用旗\n");
  }
  printf("请输入要标记/取消标记的坐标\n");
  scanf("%d%d", &x, &y);
  if (x >= 1 && x <= row && y >= 1 && y <= col)
  {
    if (show[x][y] == '*' &&(count > 0))
    {
    show[x][y] = '$';
    count--;
    Disboard(show, row, col);
    if (count == 0)
    {
      printf("不可继续标记\n");
      break;
    }
    else
    {
      printf("是否继续标记?:1.continue 其他:break\n");
      scanf("%d", &z);
      if (z == 1 && count> 0)
      {
      continue;
      }
      else
      {
      printf("退出标记成功\n");
      break;
      }
    }
    }
    else if (show[x][y] == '$')
    {
    show[x][y] = '*';
    count++;
    Disboard(show, row, col);
    printf("是否继续取消标记?:1.continue 其他:break\n");
    scanf("%d", &z);
    if (z == 1)
    {
      continue;
    }
    else
    {
      printf("继续游戏\n");
      break;
    }
    }
    else
    {
    printf("该坐标已经展开,请重新输入\n");
    }
  }
  else
  {
    printf("输入错误,请重新输入\n");
  }
  }
}

笔者颇为得意的地方在于递归的构造和插旗拔旗的操作.


三.头文件


#pragma once
#define Rows 11
#define Cols 11
#define Row  9
#define Col  9
#define COUNT 10 
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
void Mainmenu();
void Initboard(char board[Rows][Cols], int rows, int cols, char set);
void Setmine(char mine[Rows][Cols], int row, int col);
void Disboard(char board[Rows][Cols], int row, int col);
void Scanmine(char mine[Rows][Cols], char show[Rows][Cols], int row, int col);
void once_scan(char mine[Rows][Cols], char show[Rows][Cols], int row, int col);


四.结果预览


1669212847967.jpg

相关文章
三子棋小游戏思路及代码实现的详解
三子棋小游戏思路及代码实现的详解
59 0
|
1月前
|
机器学习/深度学习 Windows
AcWing 687. 扫雷(每日一题)
AcWing 687. 扫雷(每日一题)
|
4月前
|
存储 编译器 C语言
|
6月前
|
算法 C语言 C++
万字详解:C语言三子棋进阶 + N子棋递归动态判断输赢(一)
三子棋游戏设计的核心是对二维数组的把握和运用。
70 1
|
6月前
|
C语言
万字详解:C语言三子棋进阶 + N子棋递归动态判断输赢(二)
我们可以通过创建并定义符号常量NUMBER,来作为判断是否胜利的标准。如三子棋中,令NUMBER为3,则这八个方向中有任意一个方向达成3子连珠,则连珠的这个棋子所代表的玩家获胜。
62 1
|
6月前
|
编译器 C语言
C语言之扫雷小游戏的实现【含递归展开】
C语言之扫雷小游戏的实现【含递归展开】
|
6月前
|
C语言
C语言实现扫雷(递归实现一扫一片,附源码)
C语言实现扫雷(递归实现一扫一片,附源码)
|
C语言
扫雷小游戏 递归展开
扫雷小游戏 递归展开
|
算法 Java 测试技术
二分查找算法简单进阶
这里将对刷题笔记一文末提及的几道推荐二分法进阶题目进行说明介绍。一道简单题加了一定的文字修饰,一道中等题巧用二分查找,以下为刷题笔记一链接,题目链接在文末提供。
153 0
|
C语言
C语言——扫雷小游戏(递归展开版)
C语言——扫雷小游戏(递归展开版)
63 0