扫雷——循环、函数、数组三位一体

简介: 🤖前言🤖正文🤖主函数部分(test.c)👾main函数👾menu函数👾game函数🤖自定义头文件部分(game.h)👾自定义头文件部分所需引用🤖功能实现函数部分(game.c)--- 基础版👾功能实现函数部分所需引用👾1.初始化函数👾 2.打印函数👾3.布置雷函数👾4.排查雷函数👾 5.统计雷函数-排查雷函数的辅助函数👾6.效果展示🤖主函数部分代码(test.c)🤖自定义头文件部分代码(game.h)🤖功能实现函数部分(game.c)🌌进阶版(屏幕清理、爆炸展开、雷点标记)🌏屏幕清理🌏爆炸展开🌏雷

目录

🤖前言

🤖正文

🤖主函数部分(test.c)

👾main函数

👾menu函数

👾game函数

👾主函数部分所需要的引用

🤖自定义头文件部分(game.h)

👾自定义头文件部分所需引用  

🤖功能实现函数部分(game.c)--- 基础版

👾功能实现函数部分所需引用

👾1.初始化函数

👾 2.打印函数

👾3.布置雷函数

👾4.排查雷函数

👾 5.统计雷函数-排查雷函数的辅助函数

👾6.效果展示

🤖主函数部分代码(test.c)

🤖自定义头文件部分代码(game.h)

🤖功能实现函数部分(game.c)

🌌进阶版(屏幕清理、爆炸展开、雷点标记)

🌏屏幕清理

🌏爆炸展开

🌏雷点标记

🌏效果

🌌功能实现函数部分(game.c)--- 进阶版代码

🤖总结


🤖前言


 💣扫雷,一款微软在上世纪九十年内置于windows的小游戏,玩法很简单,根据提示避开所有雷区即可获胜,原理也很简单:通过两个数组和功能实现函数的配合,实现踩雷结束,否则提示的基本逻辑。如今在win11上已经看不见这款小游戏了,根据第一性原则,没有我们就去创造,下面让我们一起看看扫雷是怎样诞生的😀。


905761ccd6f998301d93d65b63190d9.png

🤖正文


同样的我们会有三个文件:


test.c主函数源文件、game.h自定义头文件、game.c功能实现源文件


本文将会介绍两个版本:基础版🛩️和进阶版(屏幕清理+爆炸展开+雷点标记)✈️,建议选择根据自身能力食用更佳🌼。


因为进阶版是由基础版改变化而来,所以我们先系统性的介绍基础版。🎆


🤖主函数部分(test.c)


主函数部分是我们程序的入口,里面包含了main主函数、game游戏函数和菜单函数🏄‍♂️

3d401a37156093c337a80c1c8593c6e.png


👾main函数


不管什么程序,总是从main函数开始,再从main函数结束,所以我们先来看看main函数部分


18642d6af1d2c90cfc53e25333156cd.png

👾menu函数


上面的main函数中用到了这个函数,这个函数及其简单,就是负责打印出提示信息


1f18ccbf0f5590d5d619174706e92b4.png

👾game函数


game函数是功能实现函数控制中心,负责各项功能的调用,同时负责两个数组的创建


 9188023d9648ead8dc97ee9ba4a02fa.png

主函数部分就介绍完毕了,下面让我们来看看自定义头文件部分:


注意:为了保证文章的可阅读性,所涉及代码将会在文章后半部分统一展出。


👾主函数部分所需要的引用

好的功能少不了全的引用,因此头文件的引用也是很讲究的。🎟️🎟️🎟️🎟️🎟️🎟️🎟️🎟️🎟️


b52eda5e3795e78f3382f4132133743.png

🤖自定义头文件部分(game.h)


这个文件存在的意义就是架起一座主函数与功能实现函数沟通的桥梁,因此里面主要是各种常量的定义、头文件的引用及功能实现函数的声明。✨✨✨

7b83a222927a8e7fbae6e25811a1828.png

👾自定义头文件部分所需引用


6b9361f012587b6008aff39c4ccdc26.png


🤖功能实现函数部分(game.c)--- 基础版


这个部分是整个程序的灵魂所在,比较难理解的也是这个部分,里面包含了之前头文件中声明的所有函数,还有部分辅助函数,我们的进阶版主要就是对此部分进行改动,实现更复杂的功能。没关系,我们可以慢慢学🌠。


👾功能实现函数部分所需引用


跟主函数部分一模一样,甚至可以直接搬用上面的图😂

19d80d7fdd2d986aa024d0c776f573b.png


👾1.初始化函数


 0fd6215b70309ebc51b33e1908a8fd8.png

👾 2.打印函数


e2d5d11da737d5299d3242aa2f4730b.png

👾3.布置雷函数


3cc8f5bf53069a8cbdd507b40e62179.png

👾4.排查雷函数


96713b2bfd6fc354eecd9bdaadb6fd8.png

👾 5.统计雷函数-排查雷函数的辅助函数



57d2698fd715ae70df6de4996890f61.png

👾6.效果展示


852bdfd2dec66dc4c3216b272af95a1.png



🤖主函数部分代码(test.c)


#define _CRT_SECURE_NO_WARNINGS 1 
#include"game.h"
//扫雷
void menu()
{
  printf("------------------------\n");
  printf("         扫雷游戏        \n");
  printf("************************\n");
  printf("*******  1.Play  *******\n");
  printf("*******  0.Exit  *******\n");
  printf("************************\n");
}
void game()
{
  //真实雷区-mine
  //镜像雷区-show
  char mine[ROWS][COLS] = { 0 };//真实布置雷的数组
  char show[ROWS][COLS] = { 0 };//展示给玩家看的数组
  init_board(mine, ROWS, COLS, '0');//初始化真实雷区
  init_board(show, ROWS, COLS, '*');//初始化展示雷区
  //display_board(mine, ROW, COL);//打印真实雷区,大小变为9
  display_board(show, ROW, COL);//打印镜像雷区,大小变为9
  put_boom(mine, ROW, COL);//布置雷置真实雷区,大小为9
  //display_board(mine, ROW, COL);//打印真实雷区,大小变为9
  find_boom(mine, show, ROW, COL);//排查雷,两个数组都要用到
}
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;
}

🤖自定义头文件部分代码(game.h)


#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<windows.h>
#include<assert.h>
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
#define Boom 10
void init_board(char board[][COLS], 
  int rows, int cols, char ret);//初始化函数
void display_board(char board[][COLS], 
  int row, int col);//打印函数
void put_boom(char mine[][COLS],
  int row, int col);//布置雷置真实雷区,大小为9
void find_boom(char mine[][ROWS],char show[][COLS],
  int row, int col);//排查雷,两个数组都要用到

🤖功能实现函数部分(game.c)


//基础版本
void init_board(char board[][COLS],
  int rows, int cols, char ret)//初始化函数
{
  int i = 0;
  for (i = 0; i < rows; i++)
  {
    int j = 0;
    for (j = 0; j < cols; j++)
    {
      board[i][j] = ret;
      //因情况而定,初始为'0'或'*'
    }
  }
}
void display_board(char board[][COLS], int row, int col)//打印函数
{
  int i = 0;
  int j = 0;
  for (j = 0; j <= row; j++)
  {
    printf("%d ", j);//打印提示行
  }
  printf("\n");
  for (i = 1; i <= row; i++)
  {
    printf("%d ", i);//打印提示列
    for (j = 1; j <= col; j++)
    {
      printf("%c ", board[i][j]);
    }
    printf("\n");
  }
}
void put_boom(char mine[][COLS],
  int row, int col)//布置雷置真实雷区,大小为9
{
  int count = Boom;
  while (count)
  {
    int x = rand() % row + 1;//模9不超过9,+1确保能在正确位置
    int y = rand() % col + 1;
    if (mine[x][y] == '0')
    {
      mine[x][y] = '1';
      count--;
    }
  }
}
int sta_boom(char mine[][COLS], int x, int y)//统计雷
{
  int i = 0;
  int j = 0;
  int count = 0;
  for (i = -1; i < 2; i++)
  {
    for (j = -1; j < 2; j++)
    {
      if (mine[x + i][y + j] == '1')
        count++;
    }
  }
  return count;
}
void find_boom(char mine[][ROWS], char show[][COLS],
  int row, int col)//排查雷,两个数组都要用到
{
  int x = 0;
  int y = 0;
  int count = row*col-Boom;
  while (count)
  {
    printf("请开始排查雷:>");
    scanf("%d %d", &x, &y);
    if (x >= 1 && x <= row && y >= 1 && y <= col)
    {
      if (show[x][y] == '*')
      {
        if (mine[x][y] == '1')
        {
          printf("很遗憾你被炸死了\n");
          display_board(mine, ROW, COL);
          //打印真实雷区,大小变为9
          printf("游戏结束!\n");
          break;
        }
        show[x][y]=sta_boom(mine, x, y) + '0';
        //传过来的数需要转成ASCII
        display_board(show, ROW, COL);
        //打印镜像雷区,大小变为9
        count--;
      }
      else
        printf("坐标已被排查过了\n");
    }
    else
      printf("坐标非法\n");
  }
  if (!count)
  {
    printf("恭喜,所有雷已被排除\n");
    display_board(mine, ROW, COL);
    //打印真实雷区,大小变为9
  }
}

🧱🧱🧱🧱🧱🧱🧱🧱🧱🧱🧱🧱🧱🧱🧱🧱🧱🧱🧱🧱🧱🧱🧱🧱🧱🧱🧱🧱🧱🧱🧱


接下来有请进阶版登场!🎊🎊🎊🎊🎊🎊🎊🎊🎊🎊🎊🎊🎊🎊🎊🎊🎊🎊🎊🎊🎊


🌌进阶版(屏幕清理、爆炸展开、雷点标记)


进阶版比多了几个功能,而这几个功能都是在功能实现函数部分(game.c)中实现的,其他部分与基础版一模一样,因此我们不做过多赘述,挑出有改变的部分讲,当然结尾我也会把功能实现函数部分(game.c)--- 进阶版的代码展示出来。


🌏屏幕清理


这个可不是说从物理成面把我们的电脑屏幕清理干净😂,而是从软件层面,也就是我们的控制台,将不需要的部分清理干净,这样会给我们一种动态的感觉,界面也更舒服。


这里利用的是windows指令-cls,清空屏幕中的一切东西,在使用时只需要把windows.h这个头文件引好

cb51c9e9554e96cd5e0b2ac7e165303.png

🌏爆炸展开


正宗的扫雷都是点一个位置,从这个位置出发,展开一大片,我们的程序是否可以实现这一效果呢?当然可以,这里需要用到递归,我称这个过程为碰壁(碰雷)。就行了。


27f6a7021f316bb20585ed94bcd70e4.png

🌏雷点标记


雷点标记就是把自己认为有雷的坐标输入,然后将其镜像雷区的对应值赋为 '#' ,和雷 '*' 区分开来,是否进行标记的决定权在于自己。

1d2fd685b1a508e2471036de7557cbf.png



🌏效果


下面让我们来看看效果如何!

2dc51b1211888bc09102b5394fec23c.png


很不错,可以愉快的玩耍了,对于基础版的提示还是很大的,尤其是游玩体验上,至少不需要像基础版一样输入几十次坐标排查。,一次爆炸展开,就可以节省很多步骤🚀🚀🚀!

🌌功能实现函数部分(game.c)--- 进阶版代码


#define _CRT_SECURE_NO_WARNINGS 1 
#include"game.h"
//进阶版本
void init_board(char board[][COLS], 
  int rows, int cols, char ret)//初始化函数
{
  int i = 0;
  for (i = 0; i < rows; i++)
  {
    int j = 0;
    for (j = 0; j < cols; j++)
    {
      board[i][j] = ret;
      //因情况而定,初始为'0'或'*'
    }
  }
}
void display_board(char board[][COLS], int row, int col)//打印函数
{
  int i = 0;
  int j = 0;
  for (j = 0; j <= row; j++)
  {
    printf("%d ", j);//打印提示行
  }
  printf("\n");
  for (i = 1; i <= row; i++)
  {
    printf("%d ", i );//打印提示列
    for (j = 1; j <= col; j++)
    {
      printf("%c ", board[i][j]);
    }
    printf("\n");
  }
}
void put_boom(char mine[][COLS],
  int row, int col)//布置雷置真实雷区,大小为9
{
  int count = Boom;
  while (count)
  {
    int x = rand() % row + 1;//模9不超过9,+1确保能在正确位置
    int y = rand() % col + 1;
    if (mine[x][y] == '0')
    {
      mine[x][y] = '1';
      count--;
    }
  }
}
int sta_boom(char mine[][COLS], int x, int y)//统计雷
{
  int i = 0;
  int j = 0;
  int count = 0;
  for (i = -1; i < 2; i++)
  {
    for (j = -1; j < 2; j++)
    {
      if (mine[x + i][y + j] == '1')
        count++;
    }
  }
  return count;
}
void exp_spr(char mine[][COLS], char show[][COLS],
  int row, int col, int x, int y,int* pc)//爆炸展开
{
  if (x >= 1 && x <= row && y >= 1 && y <= col)
  {
    int num = sta_boom(mine, x, y);
    if (num == 0)
    {
      (*pc)--;
      show[x][y] = ' ';
      int i = 0;
      int j = 0;
      for (i = -1; i < 2; i++)
      {
        for (j = -1; j < 2; j++)
        {
          if (show[x + i][y + j] == '*')
          {
            exp_spr(mine, show, ROW, COL,
              x + i, y + j, pc);//递归
          }
        }
      }
    }
    else
    {
      (*pc)--;
      show[x][y] = num + '0';
    }
  }
  //鸣谢CSDN博主 野猪佩奇` 的代码分享
}
void boom_mark(char show[][ROWS], int row, int col)//雷点标记
{
  int input = 0;
  while (1)
  {
    printf("是否需要进行雷点标记?(1/0)");
    scanf("%d", &input);
    if (1 == input)
    {
      int x = 0;
      int y = 0;
      printf("请输入想标记的坐标:>");
      scanf("%d %d", &x, &y);
      show[x][y] = '#';
      break;
    }
    else if (0 == input)
    {
      printf("不做标记\n");
      break;
    }
    else
      printf("选择错误,请重新选择\n");
  }
}
void find_boom(char mine[][ROWS], char show[][COLS],
  int row, int col)//排查雷,两个数组都要用到
{
  int x = 0;
  int y = 0;
  int count = row*col-Boom;
  int ret = 0;
  int input = 0;
  while (count)
  {
    printf("请开始排查雷:>");
    scanf("%d %d", &x , &y);
    if (x >= 1 && x <= row && y >= 1 && y <= col)
    {
      if (show[x][y] == '*')
      {
        if (mine[x][y] == '1')
        {
          printf("很遗憾你被炸死了\n");
          display_board(mine, ROW, COL);//打印真实雷区,大小变为9
          printf("游戏结束!\n");
          break;
        }
        exp_spr(mine, show, ROW, COL, x, y,&count);//爆炸展开
        display_board(show, ROW, COL);//打印镜像雷区,大小变为9
        boom_mark(show, ROW, COL);//雷点标记
        system("cls");//屏幕清除
        display_board(show, ROW, COL);//打印镜像雷区,大小变为9
      }
      else
        printf("坐标已被排查过了\n");
    }
    else
      printf("坐标非法\n");
  }
  if (!count)
  {
    printf("恭喜,所有雷已被排除\n");
    display_board(mine, ROW, COL);//打印真实雷区,大小变为9
  }
}

🤖总结

 从学习分支到学习数组,再到扫雷小游戏的实现,中间经历漫长的时间,最后我花了一下午的时间,将扫雷双版本写成博客分享给大家。现在回头来看这个小游戏,无非就是分支与循环、函数、数组这三个章节的内容,连指针都很少出现,关于cls、rand、time这样的知识,只需要打开软件,搜索关键字就可以轻松学会,因此再有限的知识也有它的适用范围,比如我们的扫雷以及前面的三子棋,多练习、多理解,我们都可以写出这样的游戏!所以赶快去学习吧,C语言的世界正等着我们去探索!🛬🛬🛬🛫🛫🛫✈️✈️✈️🚀


 如果本文有不足或错误的地方,随时欢迎指出,我会在第一时间改正!


 如果觉得作者写的还不错的话,可以点一个小小的赞,你们的支持将会是我更新的最大动力!

ae4830e3f82414cd53d4c25e434434f.png


目录
相关文章
|
运维 关系型数据库 MySQL
"MySQL运维精髓:深入解析数据库及表的高效创建、管理、优化与备份恢复策略"
【8月更文挑战第9天】MySQL是最流行的开源数据库之一,其运维对数据安全与性能至关重要。本文通过最佳实践介绍数据库及表的创建、管理与优化,包括示例代码。涵盖创建/删除数据库、表结构定义/调整、索引优化和查询分析,以及数据备份与恢复等关键操作,助您高效管理MySQL,确保数据完整性和系统稳定运行。
879 0
|
5天前
|
云安全 人工智能 安全
AI被攻击怎么办?
阿里云提供 AI 全栈安全能力,其中对网络攻击的主动识别、智能阻断与快速响应构成其核心防线,依托原生安全防护为客户筑牢免疫屏障。
|
15天前
|
域名解析 人工智能
【实操攻略】手把手教学,免费领取.CN域名
即日起至2025年12月31日,购买万小智AI建站或云·企业官网,每单可免费领1个.CN域名首年!跟我了解领取攻略吧~
|
9天前
|
安全 Java Android开发
深度解析 Android 崩溃捕获原理及从崩溃到归因的闭环实践
崩溃堆栈全是 a.b.c?Native 错误查不到行号?本文详解 Android 崩溃采集全链路原理,教你如何把“天书”变“说明书”。RUM SDK 已支持一键接入。
603 214
|
存储 人工智能 监控
从代码生成到自主决策:打造一个Coding驱动的“自我编程”Agent
本文介绍了一种基于LLM的“自我编程”Agent系统,通过代码驱动实现复杂逻辑。该Agent以Python为执行引擎,结合Py4j实现Java与Python交互,支持多工具调用、记忆分层与上下文工程,具备感知、认知、表达、自我评估等能力模块,目标是打造可进化的“1.5线”智能助手。
840 61
|
7天前
|
人工智能 移动开发 自然语言处理
2025最新HTML静态网页制作工具推荐:10款免费在线生成器小白也能5分钟上手
晓猛团队精选2025年10款真正免费、无需编程的在线HTML建站工具,涵盖AI生成、拖拽编辑、设计稿转代码等多种类型,均支持浏览器直接使用、快速出图与文件导出,特别适合零基础用户快速搭建个人网站、落地页或企业官网。
1239 157
|
4天前
|
编解码 Linux 数据安全/隐私保护
教程分享免费视频压缩软件,免费视频压缩,视频压缩免费,附压缩方法及学习教程
教程分享免费视频压缩软件,免费视频压缩,视频压缩免费,附压缩方法及学习教程
238 138
|
7天前
|
存储 安全 固态存储
四款WIN PE工具,都可以实现U盘安装教程
Windows PE是基于NT内核的轻量系统,用于系统安装、分区管理及故障修复。本文推荐多款PE制作工具,支持U盘启动,兼容UEFI/Legacy模式,具备备份还原、驱动识别等功能,操作简便,适合新旧电脑维护使用。
517 109