C语言实现经典扫雷游戏(详细教程+代码解析)

C语言实现扫雷游戏详解


一、项目介绍
 


扫雷游戏的核心玩法是:玩家通过点击格子排查地雷,根据格子显示的数字判断周围雷的数量,最终在不触雷的情况下排查完所有安全区域即可获胜。
 
用C语言实现扫雷,能帮助我们深入理解二维数组操作、函数模块化设计、随机数生成等知识点,是从语法学习到项目实践的重要过渡。
 


二、实现思路
 

 


1.采用两个二维数组分别维护游戏状态:
 
-  mine  数组:存储地雷的实际分布( '1'  表示有雷, '0'  表示无雷)。
-  show  数组:展示给玩家的界面( '*'  表示未排查,数字表示周围雷的数量)。
 
为避免数组越界,我们将数组尺寸定义得比实际棋盘大2(如棋盘是9×9,数组定义为11×11),方便处理边缘格子的逻辑。
 
2. 功能模块划分
 
将游戏拆分为以下核心函数,实现高内聚、低耦合:
 
-  InitBoard :初始化棋盘(地雷棋盘初始为 '0' ,显示棋盘初始为 '*' )。
-  DisplayBoard :打印棋盘,展示游戏界面。
-  SetMine :随机布置指定数量的地雷。
-  GetMineCount :统计某个坐标周围的地雷数量。
-  FindMine :处理玩家的排查操作,判断胜负或“炸死”。
 


三、代码详细解析
 


1. 头文件与宏定义( game.h )
 
先定义通用头文件、宏和函数声明,为后续功能实现做准备:

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

#define EASY_COUNT 10  // 简单难度雷的数量
#define ROW 9         // 棋盘行数
#define COL 9         // 棋盘列数
#define ROWS ROW+2    // 实际数组行数(防止越界)
#define COLS COL+2    // 实际数组列数(防止越界)

// 初始化棋盘
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set);
// 打印棋盘
void DisplayBoard(char board[ROWS][COLS], int row, int col);
// 布置雷
void SetMine(char board[ROWS][COLS], int row, int col);
// 统计周围雷数(辅助函数)
int GetMineCount(char mine[ROWS][COLS], int x, int y);
// 排查雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);


 
 
2. 功能函数实现( game.c )
 


(1)初始化棋盘  InitBoard 
 
通过双重循环将棋盘每个元素初始化为指定字符:
 

  

#include "game.h"

void InitBoard(char board[ROWS][COLS], int rows, int cols, char set)
{
    int i = 0;
    for (i = 0; i < rows; i++)
    {
        int j = 0;
        for (j = 0; j < cols; j++)
        {
            board[i][j] = set;
        }
    }
}

这里的set可以接收两种参数
 
 
(2)打印棋盘  DisplayBoard 
 
打印时先输出列号,再逐行输出行号+棋盘内容,让玩家能清晰定位坐标:

void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
    int i = 0;
    printf("--------扫雷游戏--------\n");
    // 打印列号
    for (i = 0; i <= col; i++)
    {
        printf("%d ", i);
    }
    printf("\n");
    // 打印每一行
    for (i = 1; i <= row; i++)
    {
        printf("%d ", i);  // 打印行号
        int j = 0;
        for (j = 1; j <= col; j++)
        {
            printf("%c ", board[i][j]);
        }
        printf("\n");
    }
}
 
 



(3)布置雷  SetMine 
 
利用 rand() 生成随机坐标,循环布置指定数量的雷(确保雷的位置不重复):
 
c

void SetMine(char board[ROWS][COLS], int row, int col)
{
    int count = EASY_COUNT;
    while (count)
    {
        // 生成1~row、1~col的随机坐标
        int x = rand() % row + 1;
        int y = rand() % col + 1;
        // 只有当前位置无雷时,才布置雷
        if (board[x][y] == '0')
        {
            board[x][y] = '1';
            count--;
        }
    }
}
 


  

 
(4)统计周围雷数  GetMineCount 
 
这是一个巧妙的实现:利用 '1' 和 '0' 的ASCII码差异,直接对周围8个格子的字符求和,再减去8个 '0' 的ASCII码,即可得到雷的数量:

int GetMineCount(char mine[ROWS][COLS], int x, int y)
{
    return (mine[x-1][y] + mine[x-1][y-1] + mine[x][y-1] + mine[x+1][y-1] + 
            mine[x+1][y] + mine[x+1][y+1] + mine[x][y+1] + mine[x-1][y+1] - 8 * '0');
}
 

当然我们还能用for循环来写:

 static int  Get_Mine_Count(char mine[ROWS][COLS], int x, int y)
{
	int sum = 0;
	for (int i = -1; i <= 1; i++)
	{
		for (int j = -1; j <= 1; j++)
		{
			sum = sum + mine[x+i][y+j];
		}

	}
	return sum - 9 * '0';
}


  

 
(5)排查雷  FindMine 
 
处理玩家的排查逻辑,包括坐标合法性判断、触雷检测、胜负判断:

void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
    int x = 0;
    int y = 0;
    int win = 0;  // 已排查的安全格子数量
    while (win < row*col - EASY_COUNT)  // 未排查完所有安全格子时循环
    {
        printf("请输入要排查的坐标:>");
        scanf("%d %d", &x, &y);
        if (x >= 1 && x <= row && y >= 1 && y <= col)  // 坐标合法
        {
            if (mine[x][y] == '1')  // 触雷
            {
                printf("很遗憾,你被炸死了\n");
                DisplayBoard(mine, ROW, COL);  // 展示所有雷的位置
                break;
            }
            else  // 未触雷,统计周围雷数
            {
                int count = GetMineCount(mine, x, y);
                show[x][y] = count + '0';  // 数字转字符
                DisplayBoard(show, ROW, COL);
                win++;
            }
        }
        else
        {
            printf("坐标非法,重新输入\n");
        }
    }
    if (win == row * col - EASY_COUNT)  // 排查完所有安全格子,获胜
    {
        printf("恭喜你,排雷成功\n");
        DisplayBoard(mine, ROW, COL);
    }
}


 
 
3. 主逻辑与菜单( test.c )
 


封装菜单和游戏主流程,通过 do-while 和 switch 实现交互:
 

#include "game.h"

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

void game()
{
    char mine[ROWS][COLS];  // 存储雷的分布
    char show[ROWS][COLS];  // 展示给玩家的界面
    // 初始化棋盘
    InitBoard(mine, ROWS, COLS, '0');
    InitBoard(show, ROWS, COLS, '*');
    // 打印初始界面
    DisplayBoard(show, ROW, COL);
    // 布置雷
    SetMine(mine, ROW, COL);
    // 排查雷
    FindMine(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);  // input为0时退出循环
    return 0;
}
 



  

 
四、运行效果演示
 
1. 启动程序后显示菜单,选择“1. play”进入游戏:
 

 
2. 展示初始棋盘,玩家可输入坐标排查:
 

请输入要排查的坐标:>
 
 
3. 若排查的格子无雷,将显示周围雷数(如输入 1 2 ,周围有2个雷):
 

请输入要排查的坐标:>
 
 
4. 若触雷,将展示所有雷的位置并提示失败;若排查完所有安全格子,提示“排雷成功”。

 
五、功能扩展建议

 
1. 难度选择:增加简单、中等、困难模式,调整 ROW 、 COL 和 EASY_COUNT (如中等难度设为16×16,雷数40)。
2. 标记雷功能:允许玩家用 '#' 标记疑似雷的位置,避免误触。
3. 界面优化:用颜色区分雷区(红色)、数字(蓝色),提升视觉体验。
4. 自动展开功能:当排查的格子周围无雷时,自动展开周围所有安全格子(类似Windows扫雷的连锁反应)。

 
六、总结

 
通过实现扫雷游戏,我们巩固了二维数组操作、函数模块化、随机数生成等C语言核心知识。希望本文的解析能帮你在C语言学习路上更进一步,也欢迎在评论区交流扩展功能的实现思路!

评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值