从零到一快速学会扫雷

简介: 从零到一快速学会扫雷

前言


扫雷这个游戏想必大家都不陌生吧,规则我就不多说了,我们今天就来用C语言来简单实现它。


一、游戏分析


ea5dd3fb6c48460ca8bd0eb286452d0c.png

游戏左上角的数字是雷的数量,上图显示的数字是数字周围一圈含雷的个数,由图我们可以创建一个 9*9 的数组来模拟方格,如果我选择最外的一圈的格子,那么周围格子就没有一圈了,怎么办呢?


6b839e03fcb8412ea0dadde3d47fee10.png


就像上图,2周围只有3个格子,怎么样才能让它周围也有8个格子呢?

我们可以多加2行、2列,这样图中每个格子周围都有8个格子,好判断。

那我们就创建一个11*11的数组。用1表示雷,0表示非雷。

问题又来了,如果格子周围只有一个雷,那它把1存进去显示1,那判断的时候岂不是变成雷了,那我们可以再创建一个数组,专门存放显示的数字。


1、创建2个数组,一个数组(a)用来存放布置好的雷的信息,另一个数组(b)存放排查出的雷的信息。

2、a 数组初始化为 ’ 0 ’ ,布置雷的时候改为 ’ 1 ’ 。

3、b 数组初始化为 ’ * ’ ,排除雷后,具体位置改为数字字符,如 ’ 3 ’ 。


二、游戏的实现


1、菜单


void menu()
{
  printf("*****************************\n"); 
  printf("*******    1.play    ********\n"); 
  printf("*******    0.exit    ********\n");
  printf("*****************************\n");
}


2、主函数


首先,我们思考一下,本次游戏应该最少执行一次,在执行过程中进行选择,那么我们应该使用 do while 循环来实现。根据选择不同,来执行相应的程序,那么应该使用 switch 语句。

下面我们来看代码:


int main()
{
  int input = 0;
  do
  {
  menu();                        //每次在选择前打印菜单
  printf("请选择:>");
  scanf("%d", &input);
  switch (input)
  {
  case 1:
    game();                    //开始游戏
    break;
  case 0:
    printf("退出游戏\n");
    break;
  default:
    printf("选择错误,重新选择!\n");
    break;
  }
  } while (input);                //根据输入的值来确定是否进行循环,0则退出循环
  return 0;                       //这也是为什么在菜单中把退出游戏设置成0的原因
}


3、game函数的实现


3.1、创建数组并初始化


#define M 11
#define N 11
void game()
{
  //设计两个数组存放信息
  char a[M][N] = { 0 };
  char b[M][N] = { 0 };
  // 初识化棋盘   
  // a数组初始化为'0'
  // b数组初始化为'*'
  chu_shi(a, M, N, '0');   //将 0 和 * 传过去方便初始化
  chu_shi(b, M, N, '*');
}
void chu_shi(char p[M][N], int m, int n, char w)
{
  int i = 0;
  int j = 0;
  for (i = 0; i < m; i++)
  for (j = 0; j < n; j++)
    p[i][j] = w;
}


3.2、打印棋盘


void game()
{
  //设计两个数组存放信息
  char a[M][N] = { 0 };
  char b[M][N] = { 0 };
  //初识化棋盘   
  // a数组初始化为'0'
  // b数组初始化为'*'
  chu_shi(a, M, N, '0');
  chu_shi(b, M, N, '*');
  //打印棋盘
  da_yin(a, M - 2, N - 2);      //M-2,N-2就是9,因为我们的游戏是9*9的,所以传9过去,方便打印
  da_yin(b, M - 2, N - 2);
}
void da_yin(char p[M][N], int m, int n)
{
  int i = 0;
  int j = 0;
  for (j = 0; j <= n; j++)    //打印列号
  printf("%d ", j);
  printf("\n");
  for (i = 1; i <= m; i++)
  {
  printf("%d ", i);      //打印行号
  for (j = 1; j <= n; j++)
    printf("%c ", p[i][j]);     //注意:数组p是char型,用%c打印每个元素
  printf("\n");
  }
}


结果:


195046feea574bc5b7a6b0f4989501e4.png


打印结果能够一目了然,哪个元素是几行几列,我们棋盘打印已经完成下一步就是布置雷了。


3.3、布置雷


我们要布置10个雷在数组 a 里,怎么样才能做到随机生成呢?

我们可以生成随机数,来达到效果。

随机数的生成:


#include<stdio.h>
#include<stdlib.h>
#include<time.h>
int main()
{
  srand((unsigned int)time(NULL));    //设置一个随机数的生成器 
  int m = rand()%9;                 //因为 rand 生成随机数范围0~32767
  printf("%d",m);                   //所以 %9 使随机数生成范围为0~8
}


#include<stdio.h>
#include<stdlib.h>
#include<time.h>
srand((unsigned int)time(NULL));     //我们需要放在 main 函数中
void game()
{
  char a[M][N] = { 0 };
  char b[M][N] = { 0 };
  chu_shi(a, M, N, '0');
  chu_shi(b, M, N, '*');
  //布置雷
  bu_lei(a, M - 2, N - 2);
  da_yin(a, M - 2, N - 2);
}
void bu_lei(char p[M][N], int m, int n)
{
  int c = 10;
  while (c)
  {
  int x = rand() % m + 1;
  int y = rand() % n + 1;
  if (p[x][y] == '0')      //避免雷的重复
  {
    p[x][y] = '1';
    c--;
  }
  }
}


输出:


4fa2772384504dd2a1da7614def87cf0.png


我们可以观察到10个雷已经布置成功,接下来就是排雷了。


3.4、排雷


首先,我们排雷是一步一步排的,这样我们就需要一个while循环来首先,我们输入一个行和列都是1到9的坐标,然后显示出这个坐标旁边8个格子的雷的个数,这样我们便可以写出如下代码:


int ji_shu(char a[M][N], int x, int y)
{
  return (a[x - 1][y] +
      a[x - 1][y - 1] +
      a[x][y - 1] +
      a[x + 1][y - 1] +
      a[x + 1][y] +
      a[x + 1][y + 1] +
      a[x][y + 1] +
      a[x - 1][y + 1] - 8 * '0');     
}             //每个数字字符减去一个‘0’即可得到相应数字
void pai_lei(char a[M][N], char b[M][N], int m, int n)
{
  int x = 0;
  int y = 0;
  while (1)
  {
  printf("请输入坐标:>");
  scanf("%d %d", &x, &y);
  if (x >= 1 && x <= 9 && y >= 1 && y <= 9)
  {
    int k = ji_shu(a, x, y);   //计算旁边8个格子的雷的个数
    b[x][y] = k + '0';         //因为字符0的ASCII码值为48,加上对应数字0到9就能得到对应的数字字符
    da_yin(b, M - 2, N - 2);   //每次输入完后打印棋盘b
  }
  else
    printf("坐标非法,请重新输入:>\n");
  }
}


1812a57a28b44f638898f24de79b8860.png


如果排到雷了,我们应该让游戏结束,添加一个if 语句即可:


void pai_lei(char a[M][N], char b[M][N], int m, int n)
{
  int x = 0;
  int y = 0;
  while (1)
  {
  printf("请输入坐标:>");
  scanf("%d %d", &x, &y);
  if (x >= 1 && x <= 9 && y >= 1 && y <= 9)
  {
    if (a[x][y] == '1')    //排到雷了
    {
    printf("你被炸死了\n");
    da_yin(a, M - 2, N - 2);  //让你看看雷的位置
    break;                   //退出 while 循环
    }
    else
    {
    int k = ji_shu(a, x, y);
    b[x][y] = k + '0';
    da_yin(b, M - 2, N - 2);
    }
  }
  else
    printf("坐标非法,请重新输入:>\n");
  }
}


如果排完了,那我们应该要退出呀,我们应该控制 while 循环来退出来:


void pai_lei(char a[M][N], char b[M][N], int m, int n)
{
  int x = 0;
  int y = 0;
  int win = 0;
  while (win<(M-2)*(N-2)-10)      //排完71个格子退出循环
  {
  printf("请输入坐标:>");
  scanf("%d %d", &x, &y);
  if (x >= 1 && x <= 9 && y >= 1 && y <= 9)
  {
    if (a[x][y] == '1')
    {
    printf("你被炸死了\n");
    da_yin(a, M - 2, N - 2);
    break;
    }
    else
    {
    int k = ji_shu(a, x, y);
    b[x][y] = k + '0';
    da_yin(b, M - 2, N - 2);
    win++;
    }
  }
  else
    printf("坐标非法,请重新输入:>\n");
  }
  if (win == (M - 2) * (N - 2) - 10)
  {
  printf("恭喜你,排雷成功\n");
  da_yin(a, M-2, N-2);
  }
}


我们这个代码还是不够完善,当我们输入2 2后再输入2 2,它还是会输出,我们应该用 if 语句限制一下:


void pai_lei(char a[M][N], char b[M][N], int m, int n)
{
  int x = 0;
  int y = 0;
  int win = 0;
  while (win<(M-2)*(N-2)-10)
  {
  printf("请输入坐标:>");
  scanf("%d %d", &x, &y);
  if (x >= 1 && x <= 9 && y >= 1 && y <= 9)
  {
    if (b[x][y] == '*')      //防止重复排查
    {
    if (a[x][y] == '1')
    {
      printf("你被炸死了\n");
      da_yin(a, M - 2, N - 2);
      break;
    }
    else
    {
      int k = ji_shu(a, x, y);
      b[x][y] = k + '0';
      da_yin(b, M - 2, N - 2);
      win++;
    }
    }
    else
    printf("该坐标已经被排查过了\n");
  }
  else
    printf("坐标非法,请重新输入:>\n");
  }
  if (win == (M - 2) * (N - 2) - 10)
  {
  printf("恭喜你,排雷成功\n");
  da_yin(a, M-2, N-2);
  }
}


好了,我们游戏具体解析已经完成了,接下来就是游戏封装了。


4、游戏具体代码


test.c:扫雷游戏的测试逻辑

game.h:游戏函数的声明

game.c :游戏函数的实现


4.1、game.h


#pragma once
#include<stdio.h>
#include <stdlib.h>
#include <time.h>
#define M 11
#define N 11
//初始化棋盘
void chu_shi(char p[M][N], int m, int n, char w);
//打印棋盘
void da_yin(char p[M][N], int m, int n);
//布置雷
void bu_lei(char p[M][N], int m, int n);
//排雷
void pai_lei(char a[M][N], char b[M][N], int m, int n);


4.2、test.c


#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
void menu()
{
  printf("*****************************\n");
  printf("*******    1.play    ********\n");
  printf("*******    0.exit    ********\n");
  printf("*****************************\n");
}
void game()
{
  char a[M][N] = { 0 };
  char b[M][N] = { 0 };
  chu_shi(a, M, N, '0');
  chu_shi(b, M, N, '*');
  bu_lei(a, M - 2, N - 2);
  pai_lei(a, b, M - 2, N - 2);
}
int main()
{
  int input = 0;
  srand((unsigned int)time(NULL));
  do
  {
  menu();
  printf("请选择:>");
  scanf("%d", &input);
  switch (input)
  {
  case 1:
    game();
    break;
  case 0:
    printf("退出游戏\n");
    break;
  default:
    printf("选择错误,请重新选择\n");
    break;
  }
  } while (input);
  return 0;
}


4.3、game.c


#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
void chu_shi(char p[M][N], int m, int n, char w)
{
  int i = 0;
  int j = 0;
  for (i = 0; i < m; i++)
  for (j = 0; j < n; j++)
    p[i][j] = w;
}
void da_yin(char p[M][N], int m, int n)
{
  int i = 0;
  int j = 0;
  for (j = 0; j <= n; j++)
  printf("%d ", j);
  printf("\n");
  for (i = 1; i <= m; i++)
  {
  printf("%d ", i);
  for (j = 1; j <= n; j++)
    printf("%c ", p[i][j]);
  printf("\n");
  }
}
void bu_lei(char p[M][N], int m, int n)
{
  int c = 10;
  while (c)
  {
  int x = rand() % m + 1;
  int y = rand() % n + 1;
  if (p[x][y] == '0')
  {
    p[x][y] = '1';
    c--;
  }
  }
}
int ji_shu(char a[M][N], int x, int y)
{
  return (a[x - 1][y] +
      a[x - 1][y - 1] +
      a[x][y - 1] +
      a[x + 1][y - 1] +
      a[x + 1][y] +
      a[x + 1][y + 1] +
      a[x][y + 1] +
      a[x - 1][y + 1] - 8 * '0');
}
void pai_lei(char a[M][N], char b[M][N], int m, int n)
{
  int x = 0;
  int y = 0;
  int win = 0;
  while (win<(M-2)*(N-2)-10)
  {
  printf("请输入坐标:>");
  scanf("%d %d", &x, &y);
  if (x >= 1 && x <= 9 && y >= 1 && y <= 9)
  {
    if (b[x][y] == '*')
    {
    if (a[x][y] == '1')
    {
      printf("你被炸死了\n");
      da_yin(a, M - 2, N - 2);
      break;
    }
    else
    {
      int k = ji_shu(a, x, y);
      b[x][y] = k + '0';
      da_yin(b, M - 2, N - 2);
      win++;
    }
    }
    else
    printf("该坐标已经被排查过了\n");
  }
  else
    printf("坐标非法,请重新输入:>\n");
  }
  if (win == (M - 2) * (N - 2) - 10)
  {
  printf("恭喜你,排雷成功\n");
  da_yin(a, M-2, N-2);
  }
}


最后


跟三子棋一样,都是代码一大堆,看得令人头疼,其实不然,只要我们把它细分下来,就会发现其实都挺简单的,都是我们学过的,只是见的少罢了,这就要求我们多做练习提高见识,这样才能写出好代码。

扫雷游戏也就圆满完成了,希望大家都能有所收获,有所成长。

下期见啦~


相关文章
|
3月前
|
API C语言 C++
贪吃蛇游戏(必备知识篇)
贪吃蛇游戏(必备知识篇)
120 1
|
8月前
贪吃蛇项目实践!(下)
至此,我们的贪吃蛇项目就完结啦,我们下一个栏目见!
39 1
|
8月前
|
存储 程序员 定位技术
贪吃蛇项目实践!(上)
大家好,今天我带着大家从0构建起贪吃蛇项目的高楼大厦~ 要实现这个游戏,我们需要实现哪些功能呢? 实现基本的功能: • 贪吃蛇地图绘制 • 蛇吃⻝物的功能(上、下、左、右⽅向键控制蛇的动作) • 蛇撞墙死亡 • 蛇撞⾃⾝死亡 • 计算得分 • 蛇⾝加速、减速 • 暂停游戏
88 1
|
8月前
|
C语言
三子棋游戏(详解+代码)
三子棋游戏(详解+代码)
85 2
|
Serverless C语言
C项目(扫雷)
C项目(扫雷)
86 0
扫雷小游戏 万字全网最详细(可展开一片空白)下
扫雷小游戏 万字全网最详细(可展开一片空白)
74 0
|
C语言
从零到一快速学会三子棋
从零到一快速学会三子棋
74 1
设计一个三子棋游戏(下)
设计一个三子棋游戏(下)

相关实验场景

更多