[C语言初阶]扫雷小游戏

news2025/5/25 11:55:02

目录

  • 一、原理及问题分析
  • 二、代码实现
    • 2.1 分文件结构设计
    • 2.2 棋盘初始化与打印
    • 2.3 布置雷与排查雷
    • 2.4 游戏主流程实现
  • 三、后期优化方向

在上一篇文章中,我们实现了我们的第二个游戏——三子棋小游戏。这次我们继续结合我们之前所学的所有内容,制作出我们的第三个项目——扫雷小游戏。
在这里插入图片描述

一、原理及问题分析

说起扫雷,这是一个非常经典的小游戏。扫雷游戏的核心逻辑是通过玩家输入的坐标排查雷的位置,若踩雷则游戏结束,否则显示周围雷的数量。接下来我们先以结构化的方式来宏观分析整个扫雷游戏中的关键要点:

  1. 双棋盘设计

    • mine数组:存储雷的位置(1为雷,0为非雷)。
    • show数组:存储玩家可见的信息(初始为*,排查后显示周围雷数,因为是字符,所以两个数组都是char类型)。
    • 设计意义:若只创建一个数组,雷为1,不是雷为0,若这个坐标周围只有1个雷,则分不清是雷,还是排查出的雷的信息,有歧义,所以再创建一个额外数组,专门用来存放排查出的雷的信息,只打印这个数组即可,用%c打印。
  2. 边界处理

    • 实际使用11x11的数组(通过ROWSCOLS定义),但只操作中间的9x9区域(通过ROWCOL定义)。
    • 目的:排查雷时边界容易越界,所以要实现9x9棋盘实际是创建11x11的数组才不会越界,。 但不要直接写数字,而是定义行和列的符号,方便后期修改。
  3. 模块化设计

    • test.c:处理菜单、循环流程和用户输入。
    • game.c:实现游戏核心逻辑(初始化、布置雷、排查雷)。
    • game.h:声明函数和定义常量。
  4. 游戏流程(在三子棋和之前的猜数字小游戏中已实现过)

    • 使用do-while循环支持重复游玩。
    • 玩家输入坐标后,通过递归展开无雷区域(进阶功能需自行实现)。

二、代码实现

2.1 分文件结构设计

文件分工与核心函数

  • game.h:定义常量、声明函数。
// game.h
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

// 常量定义:实际操作的棋盘大小为9x9,扩展为11x11避免越界
#define ROW 9    
#define COL 9    
#define ROWS ROW+2
#define COLS COL+2
#define EASY 10  // 默认雷的数量

// 函数声明
void Start(char arr[ROWS][COLS], int rows, int cols, char get); // 初始化棋盘
void Display(char arr[ROWS][COLS], int row, int col);           // 打印棋盘
void Set(char arr[ROWS][COLS], int row, int col);               // 布置雷
int Choose(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col); // 排雷逻辑
  • test.c:主流程和菜单逻辑。
  • game.c:核心功能实现。

2.2 棋盘初始化与打印

1. 初始化函数 Start

  • 功能:将棋盘所有位置初始化为指定字符(mine初始为'0'show初始为'*')因为一个函数要实现两种不同内容初始化,所以多加一个参数。
// game.c
void Start(char arr[ROWS][COLS], int rows, int cols, char get) 
{
    for (int i = 0; i < rows; i++) 
    {
        for (int j = 0; j < cols; j++) 
        {
            arr[i][j] = get; // 将每个元素设置为传入的字符('0'或'*')
        }
    }
}

2. 打印函数 Display

  • 功能:打印棋盘,为了美化棋盘显示,优化玩家体验,我们添加了行列号和分隔线。
// game.c
void Display(char arr[ROWS][COLS], int row, int col)
 {
    printf("--------扫雷游戏--------\n");
    // 打印列号(顶部标签)
    printf("   "); // 对齐行号
    for (int i = 1; i <= col; i++)
     {
        printf("%d ", i);
    }
    printf("\n");

    // 打印分隔线
    printf("   ");
    for (int i = 1; i <= col; i++) 
    {
        printf("--");
    }
    printf("\n");

    // 打印棋盘内容(带行号)
    for (int i = 1; i <= row; i++) 
    {
        printf("%d |", i); // 行号+左侧竖线
        for (int j = 1; j <= col; j++) 
        {
            printf("%c ", arr[i][j]); // 打印棋盘元素
        }
        printf("\n");
    }
    printf("--------扫雷游戏--------\n");
}

运行效果

--------扫雷游戏--------
   1 2 3 4 5 6 7 8 9 
   -------------------
1 |* * * * * * * * * 
2 |* * * * * * * * * 
...(略)

2.3 布置雷与排查雷

1. 布置雷函数 Set

  • 功能:在9x9区域内随机生成雷。(关于rand函数的用法以及取余的技巧在之前的三子棋和猜数字小游戏中已经详细介绍过,这里不再赘述)
// game.c
void Set(char arr[ROWS][COLS], int row, int col)
 {
    int count = EASY; // 雷的数量
    while (count) 
    {
        int x = rand() % row + 1; // 生成1~9的随机坐标
        int y = rand() % col + 1;
        if (arr[x][y] == '0') {   // 仅当该位置无雷时布置
            arr[x][y] = '1';      // 标记为雷
            count--;
        }
    }
}

2. 计算周围雷数 get_mine

  • 功能:计算坐标(x,y)周围8个位置的雷数总和。 这个函数可以不用在game.h中声明,因为只是为了在排查雷的函数中临时用的,不会用在其他地方。
// game.c
int get_mine(char arr[ROWS][COLS], int x, int y) 
{
    // 周围8个坐标的字符值相加('0'或'1'),再减去8*'0'得到实际数字
    return arr[x-1][y-1] + arr[x-1][y] + arr[x-1][y+1] +
           arr[x][y-1]   +               arr[x][y+1]   +
           arr[x+1][y-1] + arr[x+1][y] + arr[x+1][y+1] - 8 * '0';
}

3. 排雷逻辑 Choose

  • 功能:处理玩家输入的坐标,判断是否踩雷或显示周围雷数。
// game.c
int Choose(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
 {
    int x = 0, y = 0;
    int Win = 0; // 记录已排查的非雷区域数量
    while (Win < ROW * COL - EASY) // 胜利条件:所有非雷区域均被排查
    { 
        printf("请选择排雷坐标(如2 3表示第二行第三列):>");
        scanf("%d %d", &x, &y);
        if (x >= 1 && y >= 1 && x <= row && y <= col)// 坐标合法性检查
         { 
            if (mine[x][y] == '1') // 踩雷
            { 
                printf("很遗憾,你被炸死了!\n");
                Display(mine, ROW, COL); // 展示雷的位置
                break; // 游戏结束
            } 
            else  // 安全坐标
            { 
                int count = get_mine(mine, x, y); // 计算周围雷数
                show[x][y] = count + '0'; // 转换为字符存储(例如3 -> '3')
                Display(show, ROW, COL);
                Win++;
            }
        } 
        else 
        {
            printf("坐标非法!\n");
        }
    }
    if (Win == ROW * COL - EASY) // 胜利条件达成
    { 
        printf("恭喜通关!\n");
        Display(mine, ROW, COL); // 展示雷的位置
    }
}

2.4 游戏主流程实现

test.c:菜单和主循环逻辑。

// test.c
#include "game.h"

void menu() {
    printf("*********************************\n");
	printf("*********************************\n");
	printf("***********扫雷小游戏************\n");
	printf("*********************************\n");
	printf("***********1.开始游戏************\n");
	printf("***********0.退出游戏************\n");
	printf("*********************************\n");
	printf("**********版本:Beta1.0***********\n");
	printf("**********作者:Yang210***********\n");
	printf("*********************************\n");
	printf("*********************************\n");
	printf("*********************************\n");
}

void game() {
    char mine[ROWS][COLS]; // 存储雷的棋盘
    char show[ROWS][COLS]; // 显示给玩家的棋盘
    Start(mine, ROWS, COLS, '0'); // 初始化雷棋盘为全'0'
    Start(show, ROWS, COLS, '*'); // 初始化显示棋盘为全'*'
    Set(mine, ROW, COL);          // 布置雷
    Display(show, ROW, COL);      // 打印初始棋盘
    Choose(mine, show, ROW, COL); // 进入排雷逻辑
}

int main() {
    srand((unsigned int)time(NULL)); // 设置随机数种子
    int input = 0;
    int add = 0; // 记录游戏次数
    do {
        menu();
        if (add == 0) {
            printf("请选择(输入1开始游戏,输入0退出游戏):>");
        } else {
            printf("是否继续游玩(输入1继续游玩,输入0退出游戏):>");
        }
        scanf("%d", &input);
        switch (input) {
            case 1:
                game();
                add++;
                break;
            case 0:
                printf("已退出游戏\n");
                break;
            default:
                printf("输入错误!\n");
        }
    } while (input); // input为0时退出循环
    return 0;
}

三、后期优化方向

  1. 递归展开:若排查坐标周围无雷(即雷数为0),自动展开相邻区域。
  2. 标记雷:允许玩家输入特殊指令(如m 3 4)标记可能为雷的位置。
  3. 难度调整:通过修改EASY的值实现不同难度的雷数设置。
  4. 界面优化:使用Windows API或第三方库(如EasyX)添加图形界面。

简单地总结一下,在这篇文章中,我们通过分文件设计和模块化的运用,将扫雷游戏的逻辑逐一地理清并且给出了后期扩展的方向。我们在代码中通过定义符号常量(如ROWEASY)提高可维护性,方便后期修改,这是一种很重要的编程习惯。我们通过我们现阶段所学的知识,做出了这个经典的游戏,这是对我们所学知识的肯定,也是我们对经典跨越时间的致敬。最后,我想送给大家一句话:"人生没有白走的路,每一步都算数。"我们的决定,决定了我们。在介绍完了两个C语言的项目之后,下一章,我们将回归C语言的知识学习,介绍一下操作符的相关知识,敬请期待。
请添加图片描述

作者其他文章链接:
[C语言初阶]三子棋小游戏
[C语言初阶]数组
[C语言初阶]递归
Gitee详细使用教程

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2385326.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

谷歌medgemma-27b-text-it医疗大模型论文速读:多语言大型语言模型医学问答基准测试MedExpQA

《MedExpQA: 多语言大型语言模型医学问答基准测试》论文解析 一、引言 论文开篇指出大型语言模型&#xff08;LLMs&#xff09;在医学领域的巨大潜力&#xff0c;尤其是在医学问答&#xff08;QA&#xff09;方面。尽管LLMs在医学执照考试等场景中取得了令人瞩目的成绩&#…

DeepSeek+白果AI论文:开启答辩PPT生成的「智能双引擎」时代

2025学术答辩革新&#xff1a;DeepSeek与白果AI论文的黄金协同方案 白果Ai论文&#xff0c;论文写作神器~ https://www.baiguoai.com/ 在学术答辩的「战场」上&#xff0c;「选题创新不足」「数据可视化低效」「PPT逻辑断裂」等痛点长期困扰研究者。DeepSeek与白果AI论文的深…

SDC命令详解:使用set_logic_dc命令进行约束

相关阅读 SDC命令详解https://blog.csdn.net/weixin_45791458/category_12931432.html?spm1001.2014.3001.5482 set_logic_dc命令可以将当前设计中的输入端口为不关心&#xff08;设置端口的driven_by_dont_care属性为true&#xff09;&#xff0c;该端口在综合是可以被认为是…

小程序涉及提供提供文本深度合成技术,请补充选择:深度合成-AI问答类目

一、问题描述 最近新项目AI咨询小程序审核上线&#xff0c;按照之前小程序的流程&#xff0c;之前审核&#xff0c;提示审核不通过&#xff0c;审核不通过的原因&#xff1a;小程序涉及提供提供文本深度合成技术 (如: AI问答) 等相关服务&#xff0c;请补充选择&#xff1a;深…

基于亚博K210开发板——lvgl 图形化实验

开发板 亚博K210开发板 实验目的 本次测试主要学习 K210 图形化操作界面的功能。 实验元件 LCD 显示屏、FT6236 触摸板 lvgl 图形化库简介 LVGL&#xff08;轻度综合图形界面库&#xff09;是一个免费开源图形库&#xff0c;具有使用方便&#xff0c;画面美观&#xff…

LABVIEW 通过节点属性动态改变数值显示控件的方法

在 LabVIEW 里&#xff0c;能够借助属性节点来改变数值输入控件的禁用状态。下面为你介绍具体的操作步骤&#xff1a; 1. 创建或开启前面板 要先创建一个数值输入控件&#xff0c;操作方法是&#xff1a;点击 "控件" 选板&#xff0c;接着选择 "新式→数值→数…

信息安全管理与评估2025上海卷

上海市“星光计划”第十一届职业院校技能大赛 &#xff08;高职组&#xff09; “信息安全管理与评估”赛项 任务书 一、 赛项时间共计4小时。二、 赛项信息 竞赛阶段 任务阶段 竞赛任务 竞赛时间 分值 第一阶段 平台搭建与安全设备 配置防护 任务1 网络平台搭建 2…

Linux目录介绍+Redis部署(小白篇)

目录 &#x1f451;Linux基础✨【目录】 &#x1f451;Redis 安装1.下载压缩包2.解压3.安装编译环境4.安装到本地5.设置开机自启 &#x1f451;Linux 自启服务 &#x1f451;Linux基础 虽然在大二的时候学过Linux&#xff0c;但是很多基础知识都忘了&#xff0c;想再次从基础捡…

Python 基础语法速查手册:从入门到精通

Python 作为最受欢迎的编程语言之一&#xff0c;以其简洁易读的语法和强大的功能吸引了大量开发者。本文全面汇总 Python 基础语法知识&#xff0c;帮助初学者快速掌握核心概念&#xff0c;并为后续深入学习打下坚实基础。 1. Python 基础语法结构 1.1 代码结构与缩进规则 Py…

论文阅读笔记——Emerging Properties in Unified Multimodal Pretraining

BAGEL 论文 商业闭源系统与学术/开源模型的差距很大&#xff0c;BAGEL 旨在通过开源统一架构大规模交错数据主要解决&#xff1a; 架构割裂&#xff1a;理解/生成分属两条网络&#xff0c;信息被压缩在少量条件 token 中&#xff0c;长上下文推理受限。数据贫乏&#xff1a;主…

JAVA批量发送邮件(含excel内容)

EmailSenderHtmlV1 是读取配置文件《批量发送邮件.xlsx》&#xff0c;配置sheet获取 发件人邮箱 邮箱账号 口令&#xff0c;发送excel数据sheet获取收件人邮箱 抄送人邮箱 邮件标题 第N行开始(N>1,N0默认表头) 第M行结束(M>1,M0默认表头) 附件文件夹…

Linux(Ubuntu)新建文件权限继承问题

当你在一个工作目权限为777的文件下&#xff0c;新建一个文件的时候&#xff0c;就有可能发生&#xff0c;新建的这个文件&#xff0c;权限和其他文件&#xff0c;或者工作目录不一致的问题&#xff0c;我们不可能每次新建一个文件&#xff0c;就要 sudo chmod -R 777 /PATH 所…

Java中的String的常用方法用法总结

1.1 String &#xff08;1&#xff09;声明 &#xff08;2&#xff09;字符串常量 存储字符串数据的容器&#xff1a;private final char value[] 字符串常量都存储在字符串常量池&#xff08;StringTable&#xff09;中 字符串常量池不允许存放两个相同的字符串常量 &#xff…

QGIS如何打开 ARCGIS的mxd工程文件

“SLYR”是一款由著名开源组织“北路开源”开发的一套QGIS兼容和转换ARCGIS样式、工程、设置信息的插件&#xff01;其主要功能为&#xff1a; 最近项目需要&#xff0c;我使用了一些功能&#xff0c;发现其对中文环境及中文信息支持不太好&#xff0c;还有一些其它BUG&#xf…

基于微信小程序的智能问卷调查系统设计与实现(源码+定制+解答)基于微信生态的问卷管理与数据分析系统设计

博主介绍&#xff1a; ✌我是阿龙&#xff0c;一名专注于Java技术领域的程序员&#xff0c;全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师&#xff0c;我在计算机毕业设计开发方面积累了丰富的经验。同时&#xff0c;我也是掘金、华为云、阿里云、InfoQ等平台…

React 如何封装一个可复用的 Ant Design 组件

文章目录 前言一、为什么需要封装组件&#xff1f;二、 仿antd组件的Button按钮三、封装一个可复用的表格组件 (实战)1. 明确需求2. 设计组件 API3. 实现组件代码4. 使用组件 三、封装组件的最佳实践四、进阶优化 总结 前言 作为一名前端开发工程师&#xff0c;在日常项目中&a…

Canvas SVG BpmnJS编辑器中Canvas与SVG职能详解

Canvas详解与常见API 一、Canvas基础 核心特性 • 像素级绘图&#xff1a;Canvas是基于位图的绘图技术&#xff0c;通过JavaScript操作像素实现图形渲染&#xff0c;适合动态、高性能场景&#xff08;如游戏、数据可视化&#xff09;。 • 即时模式&#xff1a;每次绘制需手动…

dify多实例部署,一台机器部署多个dify实例

dify多实例部署 目的 实现在一台机器上&#xff0c;部署多个dify的实例。比如一个部署1.2版本&#xff0c;一个部署1.3版本。废话没有&#xff0c;直接上干货。 前提 你的电脑已经部署了一个dify实例&#xff0c;并成功运行。比如已经部署成功0.15.3版本。 步骤如下&#…

ML 48.机器学习之临床生存树(rpartSurv)

简介机器学习中生存树&#xff08;Survival Tree&#xff09;的原理详解 生存树是结合决策树与生存分析的机器学习模型&#xff0c;主要用于处理带有时间-事件数据&#xff08;包含删失数据&#xff09;的预测问题。其核心目标是&#xff1a;通过树状结构对数据进行递归分割&am…

HarmonyOS 应用开发,如何引入 Golang 编译的第三方 SO 库

本指南基于笔者临时修复的 ohos_golang_go 项目fork&#xff0c;解决HO 应用导入 cgo编译产物时的 crash 问题。 1. 下载 ohos_golang_go git clone https://gitcode.com/deslord/ohos_golang_go.git&#x1f4cc; 该仓库为笔者临时修复版本&#xff0c;修复了 CGO 编译模式下…