小游戏:拓展版扫雷

在这里插入图片描述

🌈这里是say-fall分享,感兴趣欢迎三连与评论区留言
🔥专栏:《C语言从零开始到精通》
《C语言编程实战》

《数据结构与算法》

《小游戏与项目》

💪格言:做好你自己,你才能吸引更多人,并与他们共赢,这才是你最好的成长方式。


前言:

之前发过一个简易版本的扫雷了,最近又写了一个拓展版本( 包括周围无雷会自动检查四周的坐标以及手动标记雷区 ),如果对拓展版扫雷感兴趣的话,欢迎大家阅读这篇文章!



拓展版扫雷游戏:经典玩法的升级与实现细节

扫雷作为一款经典的单人益智游戏,自诞生以来就深受玩家喜爱。本文将介绍一款基于C语言实现的拓展版扫雷游戏,它不仅保留了经典扫雷的核心玩法,还增加了更灵活的操作方式和人性化的交互设计。我们将从游戏功能、代码实现和玩法说明三个方面进行详细介绍。

游戏功能与特色

这款拓展版扫雷在传统扫雷基础上进行了多处优化,主要特点包括:

  • 标准9x9游戏棋盘:经典的9×9格子布局,包含10个地雷,符合大多数玩家的操作习惯
  • 完整的游戏流程:从游戏启动、棋盘展示到胜负判定,形成完整的游戏闭环
  • 丰富的操作选项:提供扫雷、标记地雷、取消标记和中途退出四种核心操作
  • 智能扩展功能:当玩家点击到周围无地雷的格子时,会自动扩展显示周围安全区域
  • 清晰的视觉反馈:通过符号区分未探索区域(*)、标记区域(#)和已探索区域(数字)
  • 完善的边界检查:对玩家输入的坐标进行有效性验证,防止误操作

核心代码解析

1. 头文件与宏定义

首先定义了游戏所需的常量和函数声明,通过宏定义可以方便地修改游戏难度(棋盘大小和地雷数量):

#define _CRT_SECURE_NO_WARNINGS 1

#include<stdio.h>
#include<stdlib.h>
#include<time.h>

// 游戏常量定义
#define MINE 10          // 地雷数量
#define ROW 9            // 棋盘行数
#define COL 9            // 棋盘列数
#define ROWS ROW+2       // 含边界的行数(便于边界检查)
#define COLS COL+2       // 含边界的列数(便于边界检查)

// 函数声明
void game();
void menu();
void Init_Board(char arr[ROWS][COLS], int row, int col, char set);
void Set(char arr[ROWS][COLS], int row, int col, int mine);
void Print_Board(char arr[ROWS][COLS], int row, int col);
void Check_mine_a(char arr[ROWS][COLS], char arr1[ROWS][COLS], int x, int y, int row, int col, int mine);
void Check_mine(char arr[ROWS][COLS], char arr1[ROWS][COLS], int row, int col, int mine, int* win);
void Sign_mine(char arr[ROWS][COLS], char arr1[ROWS][COLS], int row, int col, int mine);
void unSign_mine(char arr[ROWS][COLS], char arr1[ROWS][COLS], int row, int col, int mine);
void Option(char arr[ROWS][COLS], char arr1[ROWS][COLS], int row, int col, int mine);

2. 菜单与初始化功能

菜单函数用于展示游戏入口,初始化函数则负责设置棋盘初始状态:

// 游戏菜单
void menu()
{
    printf("************************\n");
    printf("*******  扫雷  *******\n");
    printf("******* 1.play *******\n");
    printf("******* 0.exit *******\n");
    printf("************************\n");
}

// 初始化棋盘
void Init_Board(char arr[ROWS][COLS], int row, int col, char set)
{
    for (int i = 0; i < row; i++)
    {
        for (int j = 0; j < col; j++)
        {
            arr[i][j] = set;  // 用指定字符填充棋盘
        }
    }
}

这里我们使用了两个棋盘:

  • mine数组:存储地雷位置信息('1’表示地雷,'0’表示安全)
  • show数组:展示给玩家的棋盘('*‘表示未探索,’#'表示标记,数字表示周围地雷数)

3. 地雷布置算法

地雷布置采用随机数生成算法,确保地雷位置随机且不重复:

// 埋雷
void Set(char arr[ROWS][COLS], int row, int col, int mine)
{
    srand((unsigned int)time(NULL));  // 初始化随机数种子
    while (mine > 0)  // 直到布置完所有地雷
    {
        // 生成1~row和1~col范围内的随机坐标
        int x = 1 + rand() % row;
        int y = 1 + rand() % col;
        
        // 确保该位置还没有地雷
        if (arr[x][y] != '1')
        {
            arr[x][y] = '1';  // 标记地雷
            mine--;  // 剩余地雷数减1
        }
    }
}

4. 棋盘打印功能

打印函数负责将当前游戏状态展示给玩家,包含坐标提示以便玩家输入:

// 打印棋盘
void Print_Board(char arr[ROWS][COLS], int row, int col)
{
    // 打印列坐标
    for (int i = 0; i <= ROW; 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 ", arr[i][j]);  // 打印格子内容
        }
        printf("\n");
    }
    printf("\n");
}

5. 自动扩展功能实现

这是本游戏的核心特色之一,当玩家点击到周围无地雷的格子时,会自动递归扩展显示周围区域:

// 自动检查(递归扩展)
void Check_mine_a(char arr[ROWS][COLS], char arr1[ROWS][COLS], int x, int y, int row, int col, int mine)
{
    // 检查坐标是否在有效范围内
    if (x >= 1 && x <= row && y >= 1 && y <= col)
    {
        // 计算周围8个格子的地雷总数
        int ret = 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';  // 转换为数字
        
        arr1[x][y] = ret + '0';  // 转换为字符存储
        
        // 如果周围没有地雷,则递归检查周围8个方向
        if (arr1[x][y] == '0')
        {
            if (arr1[x - 1][y - 1] == '*')
                Check_mine_a(arr, arr1, x - 1, y - 1, row, col, mine);
            if (arr1[x - 1][y] == '*')
                Check_mine_a(arr, arr1, x - 1, y, row, col, mine);
            if (arr1[x - 1][y + 1] == '*')
                Check_mine_a(arr, arr1, x - 1, y + 1, row, col, mine);
            if (arr1[x][y - 1] == '*')
                Check_mine_a(arr, arr1, x, y - 1, row, col, mine);
            if (arr1[x][y + 1] == '*')
                Check_mine_a(arr, arr1, x, y + 1, row, col, mine);
            if (arr1[x + 1][y - 1] == '*')
                Check_mine_a(arr, arr1, x + 1, y - 1, row, col, mine);
            if (arr1[x + 1][y] == '*')
                Check_mine_a(arr, arr1, x + 1, y, row, col, mine);
            if (arr1[x + 1][y + 1] == '*')
                Check_mine_a(arr, arr1, x + 1, y + 1, row, col, mine);
        }
    }
    else 
    {
        return;  // 坐标无效则返回
    }
}

6. 扫雷核心逻辑

处理玩家的扫雷操作,包括判断是否踩雷、计算周围地雷数和判定胜利条件:

// 检查雷
void Check_mine(char arr[ROWS][COLS], char arr1[ROWS][COLS], int row, int col, int mine, int* win)
{
    int x, y;
    printf("请输入您要检查的坐标(例如:x,y):\n");
    scanf("%d,%d", &x, &y);
    
    // 检查坐标有效性
    if (1 <= x && x <= row && 1 <= y && y <= col)
    {
        // 判断是否踩雷
        if (arr[x][y] == '1')
        {
            printf("此位置有雷,游戏结束\n");
            // 展示所有地雷位置
            for (int i = 1; i <= row; i++)
            {
                for (int j = 1; j <= col; j++)
                {
                    if (arr[i][j] == '1')
                        arr1[i][j] = '1';  // 显示地雷
                }
            }
            Print_Board(arr1, ROW, COL);
            *win = row * col - mine;  // 结束游戏循环
        }
        else  // 未踩雷
        {
            // 检查是否是未探索区域
            if (arr1[x][y] == '*')
            {
                // 计算周围地雷数
                int ret = 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';
                arr1[x][y] = ret + '0';
                
                // 如果周围没有地雷,触发自动扩展
                if (arr1[x][y] == '0')
                {
                    Check_mine_a(arr, arr1, x, y, row, col, mine);
                }
                
                // 打印更新后的棋盘
                Print_Board(arr1, ROW, COL);
                
                // 计算已探索区域数量,判断是否胜利
                *win = 0;
                for (int i = 1; i <= row; i++)
                {
                    for (int j = 1; j <= col; j++)
                    {
                        if (arr1[i][j] != '*' && arr1[i][j] != '#')
                        {
                            (*win)++;
                        }
                    }
                }
                printf("还剩下%d处未检查\n", row * col - mine - *win);
                
                // 判断是否胜利
                if (*win == row * col - mine)
                {
                    printf("恭喜您,排雷成功!\n");
                }
            }
            else
            {
                printf("输入重复或者已经标记,请重新输入:\n");
            }
        }
    }
    else
    {
        printf("输入错误,重新输入\n");
    }
}

7. 标记与取消标记功能

实现地雷标记功能,帮助玩家记录怀疑有地雷的位置:

// 标记雷
void Sign_mine(char arr[ROWS][COLS], char arr1[ROWS][COLS], int row, int col, int mine)
{
    int x, y;
    printf("请输入您要标记的坐标(例如:x,y):\n");
    scanf("%d,%d", &x, &y);
    
    // 检查坐标有效性
    if (1 <= x && x <= row && 1 <= y && y <= col)
    {
        // 只能标记未探索区域
        if (arr1[x][y] == '*')
        {
            arr1[x][y] = '#';  // 用#表示标记
            Print_Board(arr1, ROW, COL);
        }
        else
        {
            printf("输入错误,该位置无法标记,请重新输入\n");
        }
    }
    else
    {
        printf("输入错误,坐标超出范围,请重新输入\n");
    }
}

// 取消标记
void unSign_mine(char arr[ROWS][COLS], char arr1[ROWS][COLS], int row, int col, int mine)
{
    int x, y;
    printf("请输入您要取消标记的坐标(例如:x,y):\n");
    scanf("%d,%d", &x, &y);
    
    // 检查坐标有效性
    if (1 <= x && x <= row && 1 <= y && y <= col)
    {
        // 只能取消已标记的区域
        if (arr1[x][y] == '#')
        {
            arr1[x][y] = '*';  // 恢复为未探索状态
            Print_Board(arr1, ROW, COL);
        }
        else
        {
            printf("输入错误,该位置没有标记,请重新输入\n");
        }
    }
    else
    {
        printf("输入错误,坐标超出范围,请重新输入\n");
    }
}

8. 游戏主循环

处理玩家的操作选择,控制游戏流程:

// 操作选择
void Option(char arr[ROWS][COLS], char arr1[ROWS][COLS], int row, int col, int mine)
{
    int win = 0;
    // 游戏循环,直到胜利或失败
    do
    {
        int opp = 0;
        printf("请输入您的选择\n1:扫雷\n2:标记\n3:取消标记\n4:退出\n");
        scanf("%d", &opp);
        
        switch (opp)
        {
        case 1:  // 扫雷操作
            Check_mine(arr, arr1, ROW, COL, MINE, &win);
            break;
        case 2:  // 标记地雷
            Sign_mine(arr, arr1, ROW, COL, MINE);
            break;
        case 3:  // 取消标记
            unSign_mine(arr, arr1, ROW, COL, MINE);
            break;
        case 4:  // 退出游戏
            printf("已退出游戏\n");
            win = row * col - mine;  // 结束循环
            break;
        default:
            printf("输入错误,请输入1-4之间的数字!\n");
            break;
        }
    } while (win < row * col - mine);  // 胜利条件:已探索区域=总区域-地雷数
}

// 游戏主函数
void game()
{
    printf("游戏开始\n");
    char mine[ROWS][COLS];  // 存储地雷信息
    char show[ROWS][COLS];  // 展示给玩家的棋盘
    
    // 初始化棋盘:mine初始化为'0',show初始化为'*'
    Init_Board(mine, ROWS, COLS, '0');
    Init_Board(show, ROWS, COLS, '*');
    
    // 打印初始棋盘
    Print_Board(show, ROW, COL);
    
    // 布置地雷
    Set(mine, ROW, COL, MINE);
    
    // 进入游戏操作循环
    Option(mine, show, ROW, COL, MINE);
}

9. 程序入口

int main()
{
    int op;
    do
    {
        menu();  // 显示菜单
        printf("请输入您的选择\n1:开始游戏\n0:退出程序\n");
        scanf("%d", &op);
        
        switch (op)
        {
        case 1:  // 开始游戏
            game();
            break;
        case 0:  // 退出程序
            printf("退出游戏,祝您生活愉快!\n");
            break;
        default:
            printf("输入错误,请输入0或1!\n");
            break;
        }
    } while (op != 0);  // 输入0则退出程序
    
    return 0;
}

游戏玩法说明

  1. 启动与退出:运行程序后,输入1开始游戏,输入0退出程序

  2. 棋盘元素

    • *:未探索的格子
    • #:标记为地雷的格子
    • 数字(0-8):表示周围8个格子中的地雷数量
    • 1:游戏结束时显示的地雷位置
  3. 操作指南

    • 选择1:进行扫雷操作,输入格式为"x,y"(如3,5表示第3行第5列)
    • 选择2:标记疑似地雷的位置,帮助记忆
    • 选择3:取消之前的标记
    • 选择4:中途退出当前游戏
  4. 胜负判定

    • 胜利:成功探索所有非地雷区域(即已探索区域数量 = 总格子数 - 地雷数)
    • 失败:不小心点击到地雷位置
  5. 技巧提示

    • 优先点击角落或边缘格子,更容易触发自动扩展
    • 善用标记功能,明确记录怀疑有地雷的位置
    • 根据数字提示判断周围地雷分布,例如"1"表示周围8格中只有1个地雷

总结与扩展方向

这款拓展版扫雷游戏通过模块化的代码设计,实现了经典扫雷的全部核心功能,并增加了更友好的交互体验。代码中使用了数组、函数、循环、条件判断和递归等多种C语言基础知识点,非常适合作为C语言初学者的实践项目。

未来可以从以下几个方向进行扩展:

  • 增加难度选择(初级、中级、高级)
  • 实现计时功能,记录玩家完成时间
  • 添加剩余地雷数量显示
  • 增加右键标记的鼠标操作支持
  • 实现游戏存档与读档功能

通过这个项目,不仅可以巩固C语言基础知识,还能学习到游戏开发的基本思路和逻辑设计方法。希望这款拓展版扫雷能给你带来编程和游戏的双重乐趣!

《扫雷拓展版》源代码


  • 本节完…
评论 30
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值