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

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

一.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

相关文章
三子棋小游戏思路及代码实现的详解
三子棋小游戏思路及代码实现的详解
63 0
|
1月前
|
机器学习/深度学习 Windows
AcWing 687. 扫雷(每日一题)
AcWing 687. 扫雷(每日一题)
|
4月前
|
存储 编译器 C语言
|
6月前
|
C语言
万字详解:C语言三子棋进阶 + N子棋递归动态判断输赢(二)
我们可以通过创建并定义符号常量NUMBER,来作为判断是否胜利的标准。如三子棋中,令NUMBER为3,则这八个方向中有任意一个方向达成3子连珠,则连珠的这个棋子所代表的玩家获胜。
70 1
|
6月前
|
算法 C语言 C++
万字详解:C语言三子棋进阶 + N子棋递归动态判断输赢(一)
三子棋游戏设计的核心是对二维数组的把握和运用。
81 1
|
6月前
|
编译器 C语言
C语言之扫雷小游戏的实现【含递归展开】
C语言之扫雷小游戏的实现【含递归展开】
|
6月前
|
C语言
C语言实现扫雷(递归实现一扫一片,附源码)
C语言实现扫雷(递归实现一扫一片,附源码)
|
6月前
|
缓存 C语言
C语言实现扫雷(递归实现一扫一片,内含详解,附源码)
C语言实现扫雷(递归实现一扫一片,内含详解,附源码)
|
C语言
扫雷小游戏 递归展开
扫雷小游戏 递归展开
|
存储 算法 C语言
【C语言初阶】带你玩转C语言中的数组,并逐步实现冒泡排序,三子棋,扫雷2
【C语言初阶】带你玩转C语言中的数组,并逐步实现冒泡排序,三子棋,扫雷
83 0