手把手超详细教学用c语言实现扫雷小游戏

简介: 手把手超详细教学用c语言实现扫雷小游戏

1.分析问题需求和大致思路

       在开始设计之前,我们先分析一下,扫雷游戏大家可能都玩过,基本的信息都是呈现在一个10*10的方格上的。开始时我们应该打印一个菜单,让玩家选择是否进行游戏。

       然后是初始化的问题,用二维数组来的格子里面的信息的话,刚好非常契合,确定了用数组来存储以后,我们就可以思考一下怎么做初始化,我们可以用3种不同的符号来表示棋盘上的状态,没被玩家排查之前用#表示,在玩家查找以后要输出周围有多少炸弹,呈现出一个整数,呈现在屏幕上的是这些符号,因此我们在创建数组时就得注意用char型。具体的存储信息如下图:

       在完成初始化之后,我们要生成随机的地雷位置,可以用rand函数和srand函数以及time函数来保证生成数的随机性。对于以上3个函数有不了解的小伙伴们欢迎点击博主的这篇文章,里面对以上函数有非常详细的介绍和讲解:C语言实现猜数字小游戏以及如何生成真正的随机数

 在将地雷布置完成后,我们就可以构思扫雷部分的逻辑了,首先由玩家输入一个坐标,然后计算机进行判断,输入位置是否合法是否合理,在确认输入合理后,对玩家输入的坐标进行判断,如果有炸弹,就弹出失败的界面,然后退出游戏,如果没有炸弹,就使用一个函数来统计周围炸弹的数量并且打印出来,然后对以上做循环的封装处理,直到游戏胜利或者失败才跳出循环,完成循环后,我们就需要解决如何定义游戏胜利的条件,我们可以用所有的格子减去已经排除的格子,再减去剩余的炸弹数,也就是进行是否已经将所有格子排查的判断,在最后只剩10个炸弹时,结束游戏,跳出循环。


       为了保证程序的健全性和可读性,我们采用多文件的方法实现扫雷小游戏。用game.h存储头文件信息以及宏定义和函数声明,用board.c文件存储游戏里面的基本逻辑函数,用game.c文件存储游戏的主要功能以及主体

2.游戏主体逻辑实现以及代码

       这里#include包含的头文件是我们自定义的头文件,里面有我们需要的头文件和函数声明,首先我们定义一个input输入实现记录玩家对于是否开始游戏的选择,用do...while...循环来实现先运行循环体让玩家决定是否进入游戏,在判断玩家的输入,以便于让玩家重复输入以及重复的游玩游戏,其中的srand函数是生成随机数的种子,后文中会提及到,这里就不再继续赘述

include "game.h"
void game()
{
  char bomb[ROWS][COLS] = { 0 };
  char show[ROWS][COLS] = { 0 };
  //初始化棋盘
  initboard(bomb, ROWS, COLS, '0');
  initboard(show, ROWS, COLS, '#');
  //打印棋盘
  printboard(show, ROW, COL);
  //生成随机炸弹位置
  setbombs(bomb, ROWS, COLS);
  //开始扫雷
  findbombs(bomb, show, ROW, COL);
}
int main()
{
  int input = 0;
  srand((unsigned int)time(NULL));
  printf("请进行输入确认是否开始游戏\n");
  do
  {
    mune();//打印菜单
    scanf("%d", &input);
    switch(input)
    {
    case 1:
      printf("\t开始游戏\n");
      game();
      break;
    case 2:
      printf("\t退出游戏\n");
      break;
    default:
      printf("非法输入,请重试\n");
      break;
    }
  } while (input != 2);
  return 0;
}

3.游戏的初始化

       我们用俩个二维数组来做记录,一个用来保存我们实际上的地雷存储位置,一个用来打印在屏幕上让玩家观看,俩个数组同等大小,之所以使用11行和9行是为了方便后面判断周围的炸弹数,也是方便后面进行交换打印等等操作,但是实际上对玩家展示的只有1~9行和列,也就是最外边一圈不展示。这里利用传的参数(char ret)不同,来实现对俩个数组进行不同的初始化。至于ROW, ROWS, COL, COLS则是我们为了方便使用以及后期修改,对于行和列进行的宏定义

//定义行和列
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
  //初始化棋盘
  initboard(bomb, ROWS, COLS, '0');
  initboard(show, ROWS, COLS, '#');
//初始化
void initboard(char board[ROWS][COLS], int row, int col,char set)
{
  for (int i = 0; i < row; i++)
  {
    for (int j = 0; j < col; j++)
    {
      board[i][j] = set;
    }
  }
}

4.地雷位置的随机生成

       还是这张图,我们是只需要使用中间部分的格子的,也就是1~9行以及1~9列,所以在放置炸弹时需要注意,不能放在外围去了

rand函数对9取模,随机数的范围就成了0~8,加上1刚好就是1~9,将值付给xy就得到了随机的坐标,while循环则可以反复的判断在放置地雷之前得先判断这个位置是否为空,再用count计数保证放置10个炸弹

//宏定义炸弹的个数
#define bomb_count 10
//生成随机炸弹位置
void setbombs(char board[ROWS][COLS],int row,int col);
//随机生成地雷位置
void setbombs(char board[ROWS][COLS], int row, int col)
{
  int x = 0;
  int y = 0;
  int count = bomb_count;
  while (count > 0)
  {
    x = rand() % 9 + 1;
    y = rand() % 9 + 1;
    if (board[x + 1][y + 1] == '0')
    {
      board[x + 1][y + 1] = '1';
      count--;
    }
  }
}

5.打印棋盘

玩家是需要看见棋盘长什么样的,要给玩家提供一个可视化的界面,实现如下:

//打印棋盘
void printboard(char board[ROWS][COLS], int row, int col)
{
  printf("------扫雷游戏------\n");
  printf(" ");
  for (int i = 1; i <= col; i++)
  {
    printf(" %d", i);
  }
  printf("\n");
  for (int i = 1; i <= row; i++)
  {
    printf("%d ", i);
    for (int j = 1; j <= col; j++)
    {
      printf("%c ", board[i][j]);
    }
    printf("\n");
  }
  printf("------扫雷游戏------\n");
}

6.扫雷

       做好好一切准备工作后,就可以开始正式的扫雷了,首先让玩家输入一个坐标,用x和y进行保存记录,然后判断这个坐标是否在9*9的格子里面,如果不在就让玩家重新输入,可以用while循环实现重复的过程,拿到这个坐标以后判断是否踩雷,如果踩雷则弹出被炸死的信息,然后打印炸弹的位置,结束游戏,如果没有,则用一个函数来计算周围有多少个炸弹,定义个整数win来统计已经判断安全的位置,最后用所有的格子数减去炸弹数,再让win和这个数比较,就可以得到是否已经全部盘查完毕,如果是,就宣布游戏胜利,结束游戏,如果没有排查完,就继续游戏继续排查

//扫雷
void findbombs(char bombs[ROWS][COLS],char show[ROWS][COLS], int row, int col)
{
  int x = 0;
  int y = 0;
  int win = 0;
  while (win<(row*col- bomb_count))
  {
    printf("请输入你想排查的坐标: ");
    scanf("%d %d", &x, &y);
    if (x >= 1 && x <= row && y >= 1 && y <= col)
    {
      if (bombs[x][y] == '1')
      {
        printf("你被炸弹炸死了\n");
        printboard(bombs, ROW, COL);
        break;
      }
      else
      {
        int count = countbombs(bombs, x, y);
        show[ x ][ y ] = count + '0';
        printboard(show, ROW, COL);
        win++;
      }
    }
    else
    {
      printf("输入坐标不合法,请重新输入\n");
    }
  }
  if (win == (row * col - bomb_count))
  {
    printf("恭喜你,排掉了全部的炸弹,游戏胜利!!!\n");
    printboard(bombs, ROW, COL);
  }
}

这里我们定义一个函数来判断周围炸弹数量

//统计周围炸弹数量
int countbombs(char bombs[ROWS][COLS], int x, int y)
{
  int ret = 0;
  ret=bombs[x - 1][y - 1] + bombs[x - 1][y] + bombs[x - 1][y + 1] + bombs[x][y - 1] + bombs[x][y + 1] + bombs[x + 1][y - 1] + bombs[x + 1][y] + bombs[x + 1][y + 1] - 8 * '0';
  return ret;
}

 以上就完成了扫雷游戏的绝大部分内容,剩下的只需要稍微拼接,修补一下就可以得到完整的程序代码,以下完整的一下代码奉上

7.游戏的完整代码

1.头文件代码

#include<stdio.h>
#include<windows.h>
#include<stdlib.h>
#include<time.h>
//定义行和列
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
#define bomb_count 10
//打印菜单
void mune();
//游戏逻辑主程序
void game();
//棋盘初始化
void initboard(char board[ROWS][COLS],int row,int col,char temp);
//打印棋盘
void printboard(char board[ROWS][COLS], int row, int col);
//生成随机炸弹位置
void setbombs(char board[ROWS][COLS],int row,int col);
//扫雷
void findbombs(char bombs[ROWS][COLS], char show[ROWS][COLS], int row, int col);
//统计周围炸弹数量
int countbombs(char bombs[ROWS][COLS], int x, int y);

2.游戏逻辑代码

#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
//打印菜单
void mune()
{
  printf("--------------------------\n");
  printf("---------1.Play ----------\n");
  printf("--------------------------\n");
  printf("---------2.Esc  ----------\n");
  printf("--------------------------\n");
}
//初始化
void initboard(char board[ROWS][COLS], int row, int col,char set)
{
  for (int i = 0; i < row; i++)
  {
    for (int j = 0; j < col; j++)
    {
      board[i][j] = set;
    }
  }
}
//打印棋盘
void printboard(char board[ROWS][COLS], int row, int col)
{
  printf("------扫雷游戏------\n");
  printf(" ");
  for (int i = 1; i <= col; i++)
  {
    printf(" %d", i);
  }
  printf("\n");
  for (int i = 1; i <= row; i++)
  {
    printf("%d ", i);
    for (int j = 1; j <= col; j++)
    {
      printf("%c ", board[i][j]);
    }
    printf("\n");
  }
  printf("------扫雷游戏------\n");
}
//随机生成地雷位置
void setbombs(char board[ROWS][COLS], int row, int col)
{
  int x = 0;
  int y = 0;
  int count = bomb_count;
  while (count > 0)
  {
    x = rand() % 9 + 1;
    y = rand() % 9 + 1;
    if (board[x + 1][y + 1] == '0')
    {
      board[x + 1][y + 1] = '1';
      count--;
    }
  }
}
//统计周围炸弹数量
int countbombs(char bombs[ROWS][COLS], int x, int y)
{
  int ret = 0;
  ret=bombs[x - 1][y - 1] + bombs[x - 1][y] + bombs[x - 1][y + 1] + bombs[x][y - 1] + bombs[x][y + 1] + bombs[x + 1][y - 1] + bombs[x + 1][y] + bombs[x + 1][y + 1] - 8 * '0';
  return ret;
}
//扫雷
void findbombs(char bombs[ROWS][COLS],char show[ROWS][COLS], int row, int col)
{
  int x = 0;
  int y = 0;
  int win = 0;
  while (win<(row*col- bomb_count))
  {
    printf("请输入你想排查的坐标: ");
    scanf("%d %d", &x, &y);
    if (x >= 1 && x <= row && y >= 1 && y <= col)
    {
      if (bombs[x][y] == '1')
      {
        printf("你被炸弹炸死了\n");
        printboard(bombs, ROW, COL);
        break;
      }
      else
      {
        int count = countbombs(bombs, x, y);
        show[ x ][ y ] = count + '0';
        printboard(show, ROW, COL);
        win++;
      }
    }
    else
    {
      printf("输入坐标不合法,请重新输入\n");
    }
  }
  if (win == (row * col - bomb_count))
  {
    printf("恭喜你,排掉了全部的炸弹,游戏胜利!!!\n");
    printboard(bombs, ROW, COL);
  }
}

3.游戏主体代码

#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
void game()
{
  char bomb[ROWS][COLS] = { 0 };
  char show[ROWS][COLS] = { 0 };
  //初始化棋盘
  initboard(bomb, ROWS, COLS, '0');
  initboard(show, ROWS, COLS, '#');
  //打印棋盘
  printboard(show, ROW, COL);
  //生成随机炸弹位置
  setbombs(bomb, ROWS, COLS);
  //printboard(bomb, ROW, COL);
  //开始扫雷
  findbombs(bomb, show, ROW, COL);
}
int main()
{
  int input = 0;
  srand((unsigned int)time(NULL));
  printf("请进行输入确认是否开始游戏\n");
  do
  {
    mune();
    scanf("%d", &input);
    switch(input)
    {
    case 1:
      printf("\t开始游戏\n");
      game();
      break;
    case 2:
      printf("\t退出游戏\n");
      break;
    default:
      printf("非法输入,请重试\n");
      break;
    }
  } while (input != 2);
  return 0;
}
目录
相关文章
|
定位技术 C语言
c语言及数据结构实现简单贪吃蛇小游戏
c语言及数据结构实现简单贪吃蛇小游戏
|
存储 C语言
【C语言程序设计——函数】递归求斐波那契数列的前n项(头歌实践教学平台习题)【合集】
本关任务是编写递归函数求斐波那契数列的前n项。主要内容包括: 1. **递归的概念**:递归是一种函数直接或间接调用自身的编程技巧,通过“俄罗斯套娃”的方式解决问题。 2. **边界条件的确定**:边界条件是递归停止的条件,确保递归不会无限进行。例如,计算阶乘时,当n为0或1时返回1。 3. **循环控制与跳转语句**:介绍`for`、`while`循环及`break`、`continue`语句的使用方法。 编程要求是在右侧编辑器Begin--End之间补充代码,测试输入分别为3和5,预期输出为斐波那契数列的前几项。通关代码已给出,需确保正确实现递归逻辑并处理好边界条件,以避免栈溢出或结果
732 16
|
算法 C语言
【C语言程序设计——循环程序设计】求解最大公约数(头歌实践教学平台习题)【合集】
采用欧几里得算法(EuclideanAlgorithm)求解两个正整数的最大公约数。的最大公约数,然后检查最大公约数是否大于1。如果是,就返回1,表示。根据提示,在右侧编辑器Begin--End之间的区域内补充必要的代码。作为新的参数传递进去。这个递归过程会不断进行,直到。有除1以外的公约数;变为0,此时就找到了最大公约数。开始你的任务吧,祝你成功!是否为0,如果是,那么。就是最大公约数,直接返回。
394 18
|
Serverless C语言
【C语言程序设计——循环程序设计】利用循环求数值 x 的平方根(头歌实践教学平台习题)【合集】
根据提示在右侧编辑器Begin--End之间的区域内补充必要的代码,求解出数值x的平方根;运用迭代公式,编写一个循环程序,求解出数值x的平方根。注意:不能直接用平方根公式/函数求解本题!开始你的任务吧,祝你成功!​ 相关知识 求平方根的迭代公式 绝对值函数fabs() 循环语句 一、求平方根的迭代公式 1.原理 在C语言中,求一个数的平方根可以使用牛顿迭代法。对于方程(为要求平方根的数),设是的第n次近似值,牛顿迭代公式为。 其基本思想是从一个初始近似值开始,通过不断迭代这个公式,使得越来越接近。
413 18
|
C语言
【C语言程序设计——循环程序设计】统计海军鸣放礼炮声数量(头歌实践教学平台习题)【合集】
有A、B、C三艘军舰同时开始鸣放礼炮各21响。已知A舰每隔5秒1次,B舰每隔6秒放1次,C舰每隔7秒放1次。编程计算观众总共听到几次礼炮声。根据提示,在右侧编辑器Begin--End之间的区域内补充必要的代码。开始你的任务吧,祝你成功!
313 13
|
存储 安全 C语言
【C语言程序设计——选择结构程序设计】预测你的身高(头歌实践教学平台习题)【合集】
分支的语句,这可能不是预期的行为,这种现象被称为“case穿透”,在某些特定情况下可以利用这一特性来简化代码,但在大多数情况下,需要谨慎使用。编写一个程序,该程序需输入个人数据,进而预测其成年后的身高。根据提示,在右侧编辑器补充代码,计算并输出最终预测的身高。分支下的语句,提示用户输入无效。常量的值必须是唯一的,且在同一个。语句的作用至关重要,如果遗漏。开始你的任务吧,祝你成功!,程序将会继续执行下一个。常量都不匹配,就会执行。来确保程序的正确性。
495 10
|
小程序 C语言
【C语言程序设计——基础】顺序结构程序设计(头歌实践教学平台习题)【合集】
目录 任务描述 相关知识 编程要求 测试说明 我的通关代码: 测试结果: 任务描述 相关知识 编程编写一个程序,从键盘输入3个变量的值,例如a=5,b=6,c=7,然后将3个变量的值进行交换,使得a=6,b=7,c=5。面积=sqrt(s(s−a)(s−b)(s−c)),s=(a+b+c)/2。使用输入函数获取半径,格式指示符与数据类型一致,实验一下,不一致会如何。根据提示,在右侧编辑器补充代码,计算并输出圆的周长和面积。
375 10
|
存储 编译器 C语言
【C语言程序设计——函数】分数数列求和2(头歌实践教学平台习题)【合集】
函数首部:按照 C 语言语法,函数的定义首部表明这是一个自定义函数,函数名为fun,它接收一个整型参数n,用于指定要求阶乘的那个数,并且函数的返回值类型为float(在实际中如果阶乘结果数值较大,用float可能会有精度损失,也可以考虑使用double等更合适的数据类型,这里以float为例)。例如:// 函数体代码将放在这里函数体内部变量定义:在函数体中,首先需要定义一些变量来辅助完成阶乘的计算。比如需要定义一个变量(通常为float或double类型,这里假设用float。
634 3
|
存储 算法 安全
【C语言程序设计——函数】分数数列求和1(头歌实践教学平台习题)【合集】
if 语句是最基础的形式,当条件为真时执行其内部的语句块;switch 语句则适用于针对一个表达式的多个固定值进行判断,根据表达式的值与各个 case 后的常量值匹配情况,执行相应 case 分支下的语句,直到遇到 break 语句跳出 switch 结构,若没有匹配值则执行 default 分支(可选)。例如,在判断一个数是否大于 10 的场景中,条件表达式为 “num> 10”,这里的 “num” 是程序中的变量,通过比较其值与 10 的大小关系来确定条件的真假。常量的值必须是唯一的,且在同一个。
686 2
|
存储 编译器 C语言
【C语言程序设计——函数】回文数判定(头歌实践教学平台习题)【合集】
算术运算于 C 语言仿若精密 “齿轮组”,驱动着数值处理流程。编写函数求区间[100,500]中所有的回文数,要求每行打印10个数。根据提示在右侧编辑器Begin--End之间的区域内补充必要的代码。如果操作数是浮点数,在 C 语言中是不允许直接进行。的结果是 -1,因为 -7 除以 3 商为 -2,余数为 -1;注意:每一个数据输出格式为 printf("%4d", i);的结果是 1,因为 7 除以 -3 商为 -2,余数为 1。取余运算要求两个操作数必须是整数类型,包括。开始你的任务吧,祝你成功!
484 1