C语言扫雷游戏是如何实现的?

1.扫雷游戏制作框架

  在写代码开始前,我们应该创建两个.c文件,一个用来写游戏逻辑的代码,另一个用来写游戏的各个模块的代码,一个.h文件用来声明函数的,把不同的模块放在不同的文件中,能够更好的展现出游戏代码的逻辑。
  首先,我们应该创建一个棋盘,一个棋盘就行是一个平面坐标系,因此,我们应该创建二维数组的方式来模拟棋盘。在创建好二维数组之后,我们就可以对二维数组进行棋盘初始化
  之后,我们就可以来布置雷,布置雷可以采用生成随机数的方法来,生成雷的坐标位置,然后雷布置好之后就可以排除雷了,具体细节请向下翻阅。

2.游戏主函数的实现

  在代码开始前创建两个.c文件,一个.h文件。
例如:在这里插入图片描述
在文件test.c中写主函数。

int main()
{
return 0;
}

我们把我们需要包含的头文件方在.h文件中,方便使用。

#include<stdio.h>

test.c文件中我们就需要引入头文件了。

#include"game.h"
int main()
{
return 0;
}

之后我们需要的头文件都可以放在game.h文件中,需要时,直接引用#include"game.h"就可以使用了。
  在主函数中,我们可以使用do ...while();来循环游戏;封装一个表示游戏菜单的函数,因为菜单并不是游戏的核心部分,因此不必放在game.c文件中;
例如:

#include"game.h"
void menu()
{
  printf("****************\n");
  printf("*** 1 . play ***\n");//选择1,代表玩游戏;选择0,则代表推出游戏。
  printf("*** 0 . exit ***\n");
  printf("****************\n");
}
int main()
{
int input = 0;//创建变量,来存放用户的选择
do
  {
  menu();//游戏菜单,供用户选择玩游戏,还是退出游戏
  printf("请选择:>\n");
  scanf("%d",&input);
  switch(input)
  {
  case 1:
  printf("玩游戏\n");
  game();
  break;
  case 0:
  printf("退出游戏\n");
  break;
  default :
  printf("输入错误,请重新输入\n");
  }while(input);//如果用户输入的是1,游戏将会再次循环,如果用户输入的是0,游戏将会停止。
return 0;
}

  在大体写出了游戏框架后,应该简单测试一下,以免后面出现多个错误时,来重新检查。

3.初始化棋盘

  首先需要创建两个二维数组,用于存放数据,一个数组主要用来存放布置雷的信息,另一个数组用来存放排除雷的信息,两个二维数组的联合使用,能够更好的提高代码效率。
  存放布置雷信息的二维数组里面应该存放字符类型的的数据,在棋盘中,我们可以用'0';来表示不是雷,用'1';表示雷;存放排除雷信息的二维数组里面应该存放字符类型的的数据,初始化为'*'来表示。
在这里插入图片描述
布置雷信息的二维数组
在这里插入图片描述
存放排除雷信息的二维数组
但是,这里有一个不方便的地方,那就是在排除雷的时候,要计算坐标附近的八个位置上是否有雷,如果坐标是(9,9),那我们应该如计算呢?因此,为墨门可以创建一个11*11的棋盘,方便后续的使用。
在这里插入图片描述
布置雷信息的二维数组
在这里插入图片描述
存放排除雷信息的二维数组

这里需要注意的是:为了方便的调整棋盘的大小,我们可以对二维数组的行和列使用#define ,为了方便使用棋盘的行和列,#define应该放在game.h文件中。
例如:在game.h的头文件里

#define ROW 9
#define COL 9
#define EASY_COUNT 10
#define ROWS ROW+2
#define COLS COL+2

  为了方便,我们可以先创建11*11的二维数组, 因为第九行的坐标周围在9*9的规格中不够八个坐标,无法方便的统计雷的个数,因此我们需要使用11x11的棋盘.
在这里插入图片描述

#include"game.h"
void menu()
{
  printf("****************\n");
  printf("*** 1 . play ***\n");//选择1,代表玩游戏;选择0,则代表推出游戏。
  printf("*** 0 . exit ***\n");
  printf("****************\n");
}
void game()
{
//定义二维数组
char mine[ROWS][COLS] = { 0 };
char show[ROWS][COLS] = { 0 };
//初始化棋盘

}
int main()
{
int input = 0;//创建变量,来存放用户的选择
do
  {
  menu();//游戏菜单,供用户选择玩游戏,还是退出游戏
  printf("请选择:>\n");
  scanf("%d",&input);
  switch(input)
  {
  case 1:
  printf("玩游戏\n");
  game();
  break;
  case 0:
  printf("退出游戏\n");
  break;
  default :
  printf("输入错误,请重新输入\n");
  }while(input);//如果用户输入的是1,游戏将会再次循环,如果用户输入的是0,游戏将会停止。
return 0;
}

  初始化棋盘应该属于游戏的部分,因此,我们需要把初始化棋盘这一模块放在游戏函数game();中。

void game()
{
//定义二维数组
char mine[ROWS][COLS] = { 0 };
char show[ROWS][COLS] = { 0 };
//初始化棋盘
InitBoard(mine,ROWS,COLS,'0');//两个数组初始化内容不同,为了方便,我们可以将初始化的内容传过去
InitBoard(show,ROWS,COLS,'*');

}

  先在game()函数中写出初始化棋盘的函数,函数的定义放在game.c文件中,函数的声明放在game.h文件中。
例如:
game.h文件中

//初始化棋盘函数的声明
void InitBoard(char board[ROWS][COLS],int rows,int cols,char set);

game.c文件中

//初始化棋盘函数的定义
void InitBoard(char board[ROWS][COLS],ROWS,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;
   }
 }
}

4.打印棋盘

  在初始化棋盘后,为了检查棋盘是否初始化成功,我们可以创建一个函数来打印棋盘。
game()函数中

void game()
{
//定义二维数组
char mine[ROWS][COLS] = { 0 };
char show[ROWS][COLS] = { 0 };
//初始化棋盘
InitBoard(mine,ROWS,COLS,'0');//两个数组初始化内容不同,为了方便,我们可以将初始化的内容传过去
InitBoard(show,ROWS,COLS,'*');
DisplayBoard(mine,ROW,COL);//由于我们只想要展示9*9的棋盘,因此,我们需要使用ROW,COL
DisplayBoard(show,ROW,COL);
}

同样的,在game.h中进行函数声明

void DisplayBoard(char board[ROWS][COLS],int row,int col);

game.c文件中进行函数定义

void DisplayBoard(char board[ROWS][COLS],int row,int col)
{
 int i = 0;
 int j = 0;
 for(i = 1; i <= row;i++)
 {
   for(j = 1; j <= col;j++)
   {
     printf("%c ",board[i][j];
   }
    printf("\n");
 } 
}

在这里插入图片描述
为了使棋盘更加的好看,我们可以在打印棋盘的时候加上以下内容
例如:

void DisplayBoard(char board[ROWS][COLS],int row,int col)
{
int i = 0;
int j = 0;
printf("-----------扫雷----------\n);
 for(i = 0; i <= row; i++)
 {
 printf("%d ",i);
 }
 for(i = 1; i <= row;i++)
 {
   printf("%d ",i);
  for(j = 1; j <= col;j++)
   {
    printf("%c ",board[i][j];
   }
   printf("\n");
 } 
}

在这里插入图片描述
这样,我们的棋盘就布置好了。

5.布置雷

  在初始化棋盘和打印棋盘之后,我们就需要来布置雷了,在布置雷的时候,我们生成随机数的函数rand(),在使用这个函数之前,应该在主函数中添加srand(),用来初始化随机数的生成器。
例如:

int main()
{
srand((unsigned int )time(NULL));
int input = 0;//创建变量,来存放用户的选择
do
  {
  menu();//游戏菜单,供用户选择玩游戏,还是退出游戏
  printf("请选择:>\n");
  scanf("%d",&input);
  switch(input)
  {
  case 1:
  printf("玩游戏\n");
  game();
  break;
  case 0:
  printf("退出游戏\n");
  break;
  default :
  printf("输入错误,请重新输入\n");
  }while(input);//如果用户输入的是1,游戏将会再次循环,如果用户输入的是0,游戏将会停止。
return 0;

这个时候,我们就可以布置雷了。
game()函数中

SetMine(mine,ROW,COL);

game.h文件中

void SetMine(char board[ROWS][COLS],int row,int col);

game.c文件中

void SetMine(char board[ROWS][COLS],int row,int col)
{
  int x = 0;
  int y = 0;
  int count = EASY_COUNT;//为了使雷的数量容易更改,这里使用#define
  while(count)
  {
    x = rand() % r0w + 1;
    y = rand() % col + 1;
    if(board[x][y] != '1')
      {
        board[x][y] = '1';
        count--;
      }
  }
}

这样,我们的雷就布置好了,我们可以打印一下布置好雷的棋盘
例如:
game()函数中

void game()
{
//定义二维数组
char mine[ROWS][COLS] = { 0 };
char show[ROWS][COLS] = { 0 };
//初始化棋盘
InitBoard(mine,ROWS,COLS,'0');//两个数组初始化内容不同,为了方便,我们可以将初始化的内容传过去
InitBoard(show,ROWS,COLS,'*');
//DisplayBoard(mine,ROW,COL);//由于我们只想要展示9*9的棋盘,因此,我们需要使用ROW,COL
//DisplayBoard(show,ROW,COL);
SetMine(mine,ROW,COL);
DisplayBoard(mine,ROW,COL);
}

结果如图:
在这里插入图片描述

6.排除雷

  在排除雷的时候,我们需要在排除雷的函数中把两个二维数组传过去。如果在排除雷的过程大体会出现一下几种情况,一是用户坐标会输入错误;二是用户会输入存放了雷的坐标;三是用户会输入之前已经排查过的坐标;四是用户会输入正确的坐标,这时我们就应该打印棋盘,并在打印的棋盘中用户输入的坐标出显示出周围8个坐标雷的个数。
  我们应该把计算一个坐标附近的雷的坐标个数封装成一个函数。

GetMineCount(mine,ROWS,COLS);

game()函数中,先设计排除雷的函数

FindMine(mine,show,ROW,COl);

game.h文件中声明该函数

void FindMine(char mine[ROWS][COLS],char show[ROWS][COLS],int row,int col);
void  GetMineCount(char mine[ROWS][COLS],int rows,int cols);

game.c文件定义该函数

void FindMine(char mine[ROWS][COLS],char show[ROWS][COLS],int row,int col)
{
 int x = 0;
 int y = 0;
 int win = 0;
 while(win < ROW * COL - EASY_COUNT)//用户可以多次输入坐标,用循环,ROW * COL - EASY_COUNT是用户输入坐标的次数
 {
   printf("请输入需要排查的坐标:>");
   scanf("%d %d",&x,&y);
   if(x >= 1 && x <= row &&y >= 1 && y <= col)
   {
    if(mine[x][y] == '1')
      {
        printf("很遗憾,你踩到雷了\n");
        DisplayBoard(mine, ROW, COL);//游戏结束后,打印放置雷的棋盘
        break;
      }
      else
      {
       if(show[x][y] != '*')
       {
         printf("输入错误,请重新输入:>");
       }
       else
       {
         show[x][y] =  GetMineCount(mine,x ,y ) + '0';//函数用来数周围8个坐标雷的个数
         DisplayBoard(show, ROW, COL);//打印存放雷信息的棋盘
         win++;
       }
      }
   }
   else
   {
    printf("输入非法坐标,请重新输入:>");
   }
 }
 if(win == ROW * COL - EASY_COUNT)
 {
   printf("恭喜你,扫雷成功\n");
   DisplayBoard(mine, ROW, COL);//游戏结束后,打印放置雷的棋盘
 }
}

  在计算坐标周围的雷的个数的时候,我们可以采用'1' - '0'来表示;如果是雷的话,结果就为1,不是雷的话,结果为0。

game.c文件定义该函数

void  GetMineCount(char mine[ROWS][COLS],int x,int y)
{
 return mine[x - 1][y] + mine[x + 1][y] + mine[x - 1][y - 1] + mine[x][y - 1] + mine[x + 1][y - 1] + mine[x + 1][y + 1] + mine[x][y + 1] + mine[x + 1][y + 1] - 8*'0';
}

  这样我们的扫雷游戏就大体写成了,为了检验最后成功的那一部分代码,我们可以把win = 0;改成win = 70;这样循环一次,如果没有踩到雷,就挑战成功了。

  • 17
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值