C语言小游戏之扫雷完整版

C语言题库

共 553字,需浏览 2分钟

 ·

2021-11-14 16:31


一.游戏介绍

看到这张图片,相信很多小伙伴都非常熟悉,很多小伙伴都玩过扫雷这个小游戏,扫雷是一款益智类游戏,在放松娱乐的同时可以锻炼各位小伙伴的智商。

image

游戏规则:如上图,玩家需要在不被炸死的前提下找出图中雷的位置,若能找出所有雷,则游戏胜利,若不幸踩到雷则被炸死。

注:先介绍程序实现的主要功能,后文会有完整代码

二.游戏步骤及实现的功能

(一) 游戏步骤

程序开始执行时玩家需要选择是否开始游戏,输入1则游戏开始,输入0则退出游戏

image

show地图出现后玩家开始选择进行选择,输入1则开始选择区域,输入2则可以标记自己认为是雷的区域,输入3则可以取消原先被标记的区域

image

当所有非雷区域全部被排出来后则游戏胜利

//遍历show地图,以便判断最后的胜利
int Travel(char show[ROWS][COLS], int row, int col)
{
 int i = 0;
 int j = 0;
 int win = 0;
 for (i = 1; i <= row; i++)
 {
  for (j = 1; j <= col; j++)
  {
   if (show[i][j] == '*' || show[i][j] == '!')
   {
    win++;
   }
  }
 }
 return win;
}

以下为效果图:

image

(二)实现的功能

  • 初始化雷盘
  • 打印雷盘
  • 随机布置雷
  • 玩家开始排雷
  • 防止玩家第一次被雷炸死.
  • 统计所选位置周围八个位置中雷的个数
  • 递归拓展已选位置周围的区域
  • 标记雷及取消标记

1.初始化雷盘

初始化雷盘时需要构造两个二维数组,一个数组(mine数组)里面是存放雷的,用于实现各种功能,另一个数组(show数组)是给玩家操作时看的,看不到雷的具体位置。

由于需要统计每个位置周围八个区域中雷的个数,在统计最边缘的位置时为了利于功能的实现,在初始化雷盘时构建的二维数组mine数组的行和列比show数组多两行两列。

//初始化雷盘
//主函数中函数的调用
//Initboard(mine, ROWS, COLS,'0');
//Initboard(show, ROWS, COLS, '*');
void Initboard(char board[ROWS][COLS], int rows, int cols,char set)
{
 int i = 0, j = 0;
 for (i = 0; i < rows; i++)
 {
  for (j = 0; j < cols; j++)
  {
   board[i][j] = set;
  }
 }
}

初始化雷盘时,mine数组全部初始化为字符‘0’,show数组全部初始化为字符‘*’。

2.打印雷盘

玩家需要通过打印出的show数组雷盘进行游戏,打印雷盘时将行号和列号全部打印出来有利于玩家进行操作

搜索公众号:C语言中文社区,关注免费领取300G编程资料

void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
 int i = 0, j = 0;
 //打印列号
 for (i = 0; i <= col; 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");
 }
}

雷盘打印如下:

image

3.随机布置雷

在show数组中,用字符‘0’表示无雷区域,用字符‘1’表示有雷区域,由于第一个步骤中已经将show数组全部初始化为字符‘0’了,故只需使用srand和rand函数生成随机数,使得雷的分布为随机位置。

//随机布置雷
void SetMine(char board[ROWS][COLS], int row, int col)
{
 int x = 0, y = 0;
 int count = EASY_COUNT;
 while (count)
 {
  x = rand() % row+1;
  y = rand() % col+1;
  if (board[x][y] != '1')
  {
   board[x][y] = '1';
   count--;
  }
 }
}

4.玩家排雷

玩家根据show数组展示出的地图开始排雷,选择自己认为不是雷的区域

void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
 int ch = 0;
 int flag_count = 0;
 int win = 0;
 int fch = 1;//用来标记玩家是否为第一次排雷
 while (1)
 {
  menu1();
  scanf("%d", &ch);
  if (ch == 1)
  {
   int x = 0, y = 0;
   printf("请开始排雷:>");
   scanf("%d%d", &x, &y);
   //判断坐标合法
   if (x <= row && x > 0 && y > 0 && y <= col)
   {
    //判断玩家是否是第一次排雷
    if (fch == 1 && mine[x][y] == '1')
    {
        //是第一次排雷
     ChangePlace(mine, row, col, x, y);
     fch++;
    }
    else 
    {
        //判断是否踩雷
     if (mine[x][y] == '1')
     {
      printf("游戏结束\n");
      printf("恭喜你,踩到雷了\n");
      DisplayBoard(mine, row, col);
      break;
     }
     else
     {
      broad(mine, show, x, y);
      DisplayBoard(show, row, col);
     }
     fch++;
    } 
   }
   else
   {
    printf("输入坐标不合法,请重新输入\n");
   }
  }
  else if (ch == 2)
  {
   printf("请开始标记雷:>\n");
   //标记雷的函数
   Flagmine(show, row, col, flag_count);
   DisplayBoard(show, row, col);
  }
  else if (ch == 3)
  {
   printf("请选择要取消标记的位置:>\n");
   //取消标记的函数
   Cancelflag(show, row, col, flag_count);
   DisplayBoard(show, row, col);
  }
  //遍历show地图(改进)
  win=Travel(show, row, col);
  if (win == EASY_COUNT)
   break;
 }
 if (win == EASY_COUNT)
 {
  printf("恭喜你,游戏胜利\n");
 }
}

5.防止玩家第一次被炸死

如果玩家第一次就踩雷,则提示玩家重新选择,并将该位置的雷重新随机布置。

//防止玩家第一次排雷被炸死
void ChangePlace(char mine[ROWS][COLS], int row, int col, int x, int y)
{
  x = rand() % row;
  y = rand() % col;
  mine[x][y] = '1';
  printf("第一次就踩雷了,重新选择\n");
}
image

6.统计所选位置周围八个位置中雷的个数

统计已选位置周围八个位置中含有雷的个数,并在该位置上数字的形式打印出来。

//计算坐标周围雷的个数
int get_mine(char mine[ROWS][COLS], int x, int y)
{
 return mine[x - 1][y] +
  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]-8*'0';
}

此处由于数组mine中存放的是字符’0’,而不是数字0,故当统计完八个位置后需要减去字符’0’之后返回为数字。

7.递归拓展已选位置周围的区域

以递归的方式拓展式排雷。

//拓展周围不是雷的区域
void broad(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y)
{
 //判断坐标是否越界
 if (x == 0 || y == 0 || x == ROWS - 1 || y == COLS - 1)
  return;
 //判断是否已经被排除
 if (show[x][y] != '*')
 {
  return;
 }
 int count = get_mine(mine, x, y);
 if (count > 0)
 {
  show[x][y] = count + '0';
  return;
 }
 //递归拓展地图
 else if (count == 0)
 {
  show[x][y] = '0';
  broad(mine, show, x - 1, y);
  broad(mine, show, x - 1, y - 1);
  broad(mine, show, x, y - 1);
  broad(mine, show, x + 1, y - 1);
  broad(mine, show, x + 1, y);
  broad(mine, show, x + 1, y + 1);
  broad(mine, show, x, y + 1);
  broad(mine, show, x - 1, y + 1);
 }
}

如果只能一个一个雷的排,将会使得此游戏无法进行,故当选择一个位置a后对a周围八个区域进行排除,若其中一个位置b周围八个位置仍没有雷,就继续对b周围的八个位置进行排雷,以此递归的方式不断排除。

「效果如下:」

image

8.标记雷及取消标记

玩家可以通过输入坐标对自己觉得是雷的位置进行标记,标记后为‘!’,如果觉得不是也可以取消标记,取消标记后恢复为‘*’。

//标记雷
void Flagmine(char show[ROWS][COLS], int row, int col,int flag_count)
{
 int x = 0, y = 0;
 //判断标记数与雷数是否相等
 if (flag_count == EASY_COUNT)
 {
  printf("标记的雷数和实际存在的雷数相等,无法再标记\n");
  return;
 }
 printf("请输入你要标记位置的坐标:>\n");
 scanf("%d%d", &x, &y);
 //判断坐标是否合法
 if (x > 0 && x <= row && y > 0 && y <= col)
 {
  //判断该坐标是否仍未被排除
  if (show[x][y]=='*')
  {
   show[x][y] = '!';
   flag_count++;
  }
  else 
  {
   printf("该位置不可能是雷,请重新输入\n");
  }
 }
 else
 {
  printf("该坐标不合法,请重新输入:>\n");
 }
}

//取消标记
void Cancelflag(char show[ROWS][COLS], int row, int col, int flag_count)
{
 int x = 0;
 int y = 0;
 scanf("%d%d", &x, &y);
 //判断坐标是否合法
 if (x > 0 && x <= row && y > 0 && y <= col)
 {
  //判断该位置是否被标记过
  if (show[x][y] == '!')
  {
   show[x][y] = '*';
   flag_count--;
  }
  else
   printf("该位置未被标记过,无需取消标记\n");
 }
 else
 {
  printf("该坐标不合法,请重新输入:>\n");
 }
}

图中‘!’即为标记区域

image

综上,此程序基本实现了扫雷小游戏的功能,有一定的娱乐性,各位小伙伴感兴趣的话可以玩一把。

「完整代码」

阿里云盘链接:https://www.aliyundrive.com/s/FFcnypRbGoQ

原文链接:https://blog.csdn.net/weixin_56372949/article/details/121152803

--- EOF ---
版权归原作者所有,如有侵权,请联系删除。

浏览 46
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报