通过C语言代码制作“扫雷游戏se”

嵌入式技术

1367人已加入

描述

 

想必屏幕前的你,肯定玩过windows系统自带的那个游戏,扫雷

回想当年,我根本没看懂这个游戏是怎么玩的

C语言

比起扫雷,三维弹球对我更有吸引力

跑题了

本篇博客就让我们一起来试试,如何通过C语言代码,制作出一个“扫雷游戏se”

1.游戏程序主函数

在编写这类游戏代码时,我们要用到的主函数基本是一致的

扫雷游戏的主函数和猜数字游戏的主函数相差很小

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
void menu()//简易目录{  printf("***************************
");  printf("**** 1. play   0. exit*****
");  printf("***************************
");}
int main(){  int input = 0;  do  {    menu();    printf("请选择:>");    scanf("%d", &input);    switch (input)    {    case 1:      game();//实现游戏的函数      break;    case 0:      printf("退出游戏
");      break;    default:      printf("输入错误
");      break;    }  } while (input);  return 0;}

2.游戏实现原理

想写好一串代码,首先我们要知道扫雷游戏需要通过什么方式来实现

C语言

我们需要一个9x9的棋盘,用于生成我们的雷以及玩家的游玩

在c语言中当然无法直接产生这样的画面

但我们可以同符号*或者#来代替网格,用1和0来表示有无雷

如果我们只生成一个棋盘,那1和0会直接显示出来,达不到隐藏的效果

所以我们需要用二维数组生成两个棋盘,一个用于存放雷,一个用于玩家的游玩

  •  
  •  
  char mine[ROWS][COLS];//雷区布置  char show[ROWS][COLS];//玩家看到的界面 

扫雷游戏我们使用头文件+源文件的形式撰写代码

这样写代码的优点在于后续我们可以直接通过更改.h文件中的数组,从而更改我们的格子大小

如: 改成12x12的游玩界面,改变雷区布雷个数等等

所以我们需要在game.h中定义这些符号

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
#include #include #include 
#define ROW 9#define COL 9
#define ROWS ROW+2#define COLS COL+2

同时我们要在主函数的最上面引用这个自己写的头文件

只要把库函数头文件放入game.h文件,在其他源文件中只需引用game.h

不需要再次引用之类

  •  
#include 'game.h'

棋盘大小为什么需要11x11?

你可能注意到了,在生成数组的时候,我使用了ROWS,其值为ROW+2

我们最终展示的只是9x9的游戏界面,但生成的棋盘其实是11x11的

这是因为我们需要在mine数组中实现扫描雷区的操作

玩过扫雷游戏的你肯定知道:在你点击一个格子的时候,如果这个格子不是雷

它会显示一个数字,告诉你它周围的8个格子中有几颗雷

如图所示:

C语言

在C语言中,我们可以用函数统计周围8个格子中雷’1’的个数

但是如果你来到边缘,那就出现问题了

C语言

如果我们想统计边缘的格子周边有几颗雷,就会遇到这种溢出数组的情况

此时代码会报错

为了避免这个问题,我们可以在原来9x9的基础上在周围加一圈空白的格子

也就是代码所示的ROW(行)COL(列)都要+2的情况

  •  
  •  
  •  
  •  
  •  
#define ROW 9#define COL 9
#define ROWS ROW+2#define COLS COL+2

游戏过程

这里简单梳理一下我们的游戏过程

(1)玩家选择开始游戏

(2)生成两个棋盘,一个放置雷扫描雷,一个向玩家展示游戏界面

(3)玩家输入坐标,选择排雷位置

(4)有雷–>玩家被炸死,游戏结束;无雷–>显示周边有几颗雷,游戏继续

(5)所有雷被排出,游戏胜利

 

3.游戏代码实现

接下来就进入我们的游戏代码部分

3-1.初始化和打印

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  //初始化扫雷  InitBoard(mine, ROWS, COLS, '0');  InitBoard(show, ROWS, COLS, '*');
  //打印扫雷  DisplayBoard(mine, ROW, COL);  DisplayBoard(show, ROW, COL); 

我们需要初始化两个棋盘,其中雷区初始化为0(0代表无雷),展示区初始化为’*’,用代替界面

同时我们打印这两个棋盘,查看初始化效果

因为这是我们的自定义函数,所以需要在.h文件中定义函数,在另外一个.c文件中包含函数的实现

C语言

  •  
  •  
  •  
  •  
//初始化棋盘void InitBoard(char board[ROWS][COLS], int rows, int cols, char set);//打印void DisplayBoard(char board[ROWS][COLS], int row, int col);

初始化函数和打印函数比较简单,使用for语句达成我们的需求

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set){  int i = 0;  int j = 0;  for (i = 0; i < rows; i++)  {    for (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;  printf("------扫雷游戏------
");  //打印列号  for (i = 0; i <= col; i++)  {    printf("%d ", i);  }  printf("
");  for (i = 1; i <= row; i++)//只打印中心的99方格  {    printf("%d ", i);//打印行号    for (j = 1; j <= col; j++)//只打印中心的99方格    {      printf("%c ", board[i][j]);    }    printf("
");  }  printf("--------------------
");}

需要注意的是我们的最后打印棋盘的时候是从i=1开始的,这样就能避开添加的空白边缘区域,只打印中心的99方格

同时我们添加了列号和行号,这样能让玩家清除的知道自己应该输入什么坐标

C语言


3-2.布置雷区

  •  
  •  
  //布置雷  SetMine(mine, ROW, COL); 

同样的,我们需要在game.h中定义这个函数

  •  
  •  
//布置地雷void SetMine(char mine[ROWS][COLS], int row, int col);

在game.c中写入自定义函数的实现

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

这里面出现了一个前面没有提到的变量,EASY_COUNT

本来这个位置只是个10

但如果我们想更改布雷个数,那每次都需要更改这里的10,后面的代码中也需要更改,非常麻烦

所以我们改为使用一个自定义变量,在game.h中定义这个变量的值

  •  
#define EASY_COUNT 10

这个值就代表我们布置雷的个数了

3-3.玩家排查雷

  •  
  •  
  •  
  •  
  •  
//在主函数中引用这个函数  FindMine(mine,show, ROW, COL);//需要把mine数组中排查的雷放入show
//在game.h中定义这个函数void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS],int row, int col);

因为我们需要把mine数组中排查出的雷的个数放入show数组中打印出来

所以这里我们需要把两个数组都传送过去

1.输入排查的坐标

2.检查坐标处是不是雷

        ·是雷 -boom!炸死 -游戏结束

        ·不是雷 -统计坐标周围有几个雷-存储排雷的信息到show数组,游戏继续

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col){  int x = 0;  int y = 0;      while (1)  {    printf("请输入排雷坐标:> ");    scanf("%d%d", &x, &y);    //判断坐标是否正确    if (x >= 1 && x <= row && y >= 1 && y <= col)    {      if (mine[x][y] == '1')      {        printf("很遗憾,你被炸死了
");        DisplayBoard(mine, ROW, COL);        break;      }      else      {        //不是雷的情况下,统计坐标周围有几个雷        int count = get_mine_count(mine, x, y);        show[x][y] = count + '0';      }    }    else    {      printf("坐标错误,请重新输入 
");    }  }}

注意,这里面我们需要添加一个代码来判断坐标合法性

我们的棋盘是9x9,玩家要是输入一个(99,99)的坐标,那肯定不在数组中的,是无效的

我们需要提醒玩家他输错了

‘0’的作用

  •  
show[x][y] = count + '0';

你可能会对这行代码感到疑惑

为什么要在count后面+上一个‘0’?

这里就和我们ascii码表有关了

C语言

因为我们初始化数组和布置雷的时候,我们给数组传入的都是1和0这两个符号,并不是数字!

但是在show数组中我们需要给玩家显示一个数字的字符

C语言

这里面我们提供的是1的字符,并不是1它本身

而我们在计算周边雷的个数的时候,传回来的是一个具体的数字

观察表格,你会发现数字和对应的字符中间,都差了48

而48恰好是字符’0’对应的ASCII码值

所以我们需要用count加上字符’0’,以此在界面中向玩家展示周边8格有几颗雷

3-4. 系统扫描雷

如何把玩家选择的格子周边的雷扫描出来呢?

设玩家的选择的坐标为x和y

C语言

我们只需要把这些坐标全部在二维数组中键入,就能逐个扫描出雷的个数

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
//统计雷的个数static int get_mine_count(char mine[ROWS][COLS], int x, int y){  return mine[x - 1][y - 1] +    mine[x - 1][y] +    mine[x - 1][y + 1] +    mine[x][y - 1] +    mine[x][y + 1] +    mine[x + 1][y - 1] +    mine[x + 1][y] +    mine[x + 1][y + 1] - 8 * '0';}

这里因为我们扫描出来的也是‘1’的字符,系统中是字符1的ascii码值49

所以我们需要减去8个字符‘0’,这样就能得到雷的个数的数字

(然后在之前的那个函数中接受,count+‘0’,在show数组中显示)

这个函数是在玩家排查雷的函数之前的

因为在主函数中我们不需要使用这个自定义函数,所以不需要在game.h中定义

我们想让它只在game.c中生效,所以用static修饰它

static的作用

1.修饰局部变量

2.修饰全局变量

3.修饰函数

上面的代码其实还少了一个东西

我们需要判断玩家什么时候胜利——雷区的0(无雷方块)全部被玩家找出,玩家就胜利了

  •  
  •  
  int win = 0;  while (win< row * col - EASY_COUNT) 

这里我们需要更改的是whlie函数

其中 row * col - EASY_COUNT 指方格总数减去雷的个数,得到的是无雷方块的个数

玩家每成功排除一个无雷方块,win就会加一个数字

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  else  {    //不是雷的情况下,统计坐标周围有几个雷    int count = get_mine_count(mine, x, y);    show[x][y] = count + '0';    //显示排查出来的信息    DisplayBoard(show, ROW, COL);        win++;  } 

当win达到无雷方块个数的时候,whlie循环就会停止

随后我们判断玩家是否胜利,如果胜利,就打印棋盘,让玩家知道雷的位置

  •  
  •  
  •  
  •  
  •  
  if (win == row * col - EASY_COUNT)  {    printf("恭喜你,游戏胜利!
");    DisplayBoard(mine, ROW, COL);  } 

这里必须要判断,因为你失败了也是会跳出循环的!

到此,我们的扫雷代码就是完成了

4.查看结果

这里我作弊,将雷的个数设置为80并打印出布置雷之后的棋盘

输入最后一个雷的位置,系统提示我们游戏胜利

C语言

输入雷的坐标后,也会提示你被炸死了

C语言

到这里我们可以确认代码是编写成功了!

  审核编辑:汤梓红
 

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分