全面解读 C++ 编写扫雷游戏:从入门到精通

话不多说,先给出完整代码~~~

#include <iostream>
#include <sstream>
#include <ctime>
#include <limits>
#define MAX 100
#define NUM 9
#define BOOM 99
using namespace std;

int len = 10, wid = 10;
int allay_Number[MAX][MAX] = {0};
int allay_Click[MAX][MAX] = {0};
char a[] = "-";

// 初始化游戏数据
void initGame() {
// 重置雷区和点击状态数组
for (int i = 0; i < MAX; i++) {
    for (int j = 0; j < MAX; j++) {
        allay_Number[i][j] = 0;
        allay_Click[i][j] = 0;
    }
}
// 重新生成地雷
srand((unsigned int)time(NULL));
int x, y;
for (int i = 0; i < NUM; i++) {
    x = rand() % 9 + 1;
    y = rand() % 9 + 1;
    if (allay_Number[y][x] == BOOM)
        i--;
    else
        allay_Number[y][x] = BOOM;
}
// 重新计算数字
for (int i = 1; i <= 10; i++)
    for (int j = 1; j <= 10; j++)
        if (allay_Number[i][j] == BOOM) {
            if (allay_Number[i - 1][j - 1] != BOOM)
                allay_Number[i - 1][j - 1]++;
            if (allay_Number[i - 1][j] != BOOM)
                allay_Number[i - 1][j]++;
            if (allay_Number[i - 1][j + 1] != BOOM)
                allay_Number[i - 1][j + 1]++;
            if (allay_Number[i][j - 1] != BOOM)
                allay_Number[i][j - 1]++;
            if (allay_Number[i][j + 1] != BOOM)
                allay_Number[i][j + 1]++;
            if (allay_Number[i + 1][j - 1] != BOOM)
                allay_Number[i + 1][j - 1]++;
            if (allay_Number[i + 1][j] != BOOM)
                allay_Number[i + 1][j]++;
            if (allay_Number[i + 1][j + 1] != BOOM)
                allay_Number[i + 1][j + 1]++;
        }
}

void createboom() {
    srand((unsigned int)time(NULL));
    int x, y;
    for (int i = 0; i < NUM; i++) {
        x = rand() % 9 + 1;
        y = rand() % 9 + 1;
        if (allay_Number[y][x] == BOOM)
            i--;
        else
            allay_Number[y][x] = BOOM;
    }
}

void createnum() {
    for (int i = 1; i <= 10; i++)
        for (int j = 1; j <= 10; j++)
            if (allay_Number[i][j] == BOOM) {
                if (allay_Number[i - 1][j - 1] != BOOM)
                    allay_Number[i - 1][j - 1]++;
                if (allay_Number[i - 1][j] != BOOM)
                    allay_Number[i - 1][j]++;
                if (allay_Number[i - 1][j + 1] != BOOM)
                    allay_Number[i - 1][j + 1]++;
                if (allay_Number[i][j - 1] != BOOM)
                    allay_Number[i][j - 1]++;
                if (allay_Number[i][j + 1] != BOOM)
                    allay_Number[i][j + 1]++;
                if (allay_Number[i + 1][j - 1] != BOOM)
                    allay_Number[i + 1][j - 1]++;
                if (allay_Number[i + 1][j] != BOOM)
                    allay_Number[i + 1][j]++;
                if (allay_Number[i + 1][j + 1] != BOOM)
                    allay_Number[i + 1][j + 1]++;
            }
}

void print() {
    for (int i = 0; i < len; i++) {
        cout << i << " ";
        for (int j = 1; j <= wid - 1; j++) {
            if (i == 0)
                cout << j << " ";
            else if (allay_Click[i][j] == 0)
                cout << a[0] << " ";
            else
                cout << allay_Number[i][j] << " ";
        }
        cout << '\n';
    }
}

int main() {
    char restart;
    do {
        system("color F0");
        cout << "共有9颗雷!\n";
        cout << endl;
        // 初始化游戏
        initGame();
        int x, y;
        int times = 0, flag = 0;
        while (1) {
            cout << '\n';
            cout << "雷区如下:\n";
            print();
            cout << '\n';
            cout << "请输入要检查的位置的横纵坐标(1-9):\n";

            string input;
            getline(cin, input);
            stringstream ss(input);
            int numRead = 0;
            while (ss >> x) {
                numRead++;
                if (numRead == 1) {
                    y = x;
                } else if (numRead > 2) {
                    break;
                }
            }
            // 检查是否输入了恰好两个整数
            if (numRead != 2 || x <= 0 || x >= 10 || y <= 0 || y >= 10 || allay_Click[y][x] == 1) {
                cout << '\n';
                if (numRead != 2) {
                    cout << "输入无效,请输入两个整数!\n";
                } else {
                    cout << "请检验将被检查的位置是否合法!\n";
                }
                continue;
            }

            cout << '\n';
            if (allay_Number[y][x] == BOOM) {
                system("color C7");
                cout << '\a' << "失败!您被雷炸死了~~\n";
                break;
            } else {
                allay_Click[y][x] = 1;
                times++;
            }

            if (times == 72) {
                flag = 1;
                break;
            }
        }

        if (flag == 1) {
            print();
            cout << "\a恭喜您获胜!\n";
            system("color A7");
        }

        cout << "按'r'键重新开始游戏,按其他键退出:\n ";
        cin >> restart;
        // 清除输入缓冲区
        cin.ignore(numeric_limits<streamsize>::max(), '\n');
        cout << '\n';
    } while (restart == 'r' || restart == 'R');

    return 0;
}

一、引言

扫雷游戏作为一款经典的单人益智游戏,自诞生以来便广受欢迎。它不仅考验玩家的逻辑思维能力,还能帮助我们理解和掌握编程中的许多核心概念。本文将带领大家一步步用 C++ 实现一个完整的扫雷游戏,从基础设计到高级功能优化,让你全面掌握扫雷游戏的开发过程。

二、游戏设计与数据结构

2.1 游戏基本规则

扫雷游戏的规则很简单:在一个 9 × 9 的网格中,随机分布着 9 个地雷。玩家需要通过点击格子来揭开它们,如果点击到地雷,游戏失败;如果格子周围没有地雷,将会自动展开周围的格子;如果格子周围有地雷,则会显示周围地雷的数量。当玩家揭开所有非地雷格子时,游戏胜利。

2.2 数据结构设计

在 C++ 中实现扫雷游戏,我们需要设计合适的数据结构来存储游戏状态。主要使用两个二维数组:

int allay_Number[MAX][MAX] = {0};  // 存储每个格子的状态(地雷或数字)
int allay_Click[MAX][MAX] = {0};   // 存储格子是否被点击的状态

其中,allay_Number数组中,0 表示空格子,99(定义为 BOOM)表示地雷,其他数字表示周围地雷的数量。allay_Click数组中,0 表示未点击,1 表示已点击。

三、核心功能实现

3.1 初始化游戏

游戏开始时,我们需要初始化游戏数据,包括重置数组、随机生成地雷和计算每个格子周围的地雷数。

// 初始化游戏数据
void initGame() {
    // 重置雷区和点击状态数组
    for (int i = 0; i < MAX; i++) {
        for (int j = 0; j < MAX; j++) {
            allay_Number[i][j] = 0;
            allay_Click[i][j] = 0;
        }
    }
    // 重新生成地雷
    srand((unsigned int)time(NULL));
    int x, y;
    for (int i = 0; i < NUM; i++) {
        x = rand() % 9 + 1;
        y = rand() % 9 + 1;
        if (allay_Number[y][x] == BOOM)
            i--;
        else
            allay_Number[y][x] = BOOM;
    }
    // 重新计算数字
    for (int i = 1; i <= 10; i++)
        for (int j = 1; j <= 10; j++)
            if (allay_Number[i][j] == BOOM) {
                // 检查周围8个方向的格子
                if (allay_Number[i - 1][j - 1] != BOOM)
                    allay_Number[i - 1][j - 1]++;
                if (allay_Number[i - 1][j] != BOOM)
                    allay_Number[i - 1][j]++;
                // 其他6个方向的检查...
            }
}

3.2 显示游戏界面

使用print()函数显示当前游戏界面,未点击的格子显示为-,已点击的格子显示其数字或地雷。

void print() {
    for (int i = 0; i < len; i++) {
        cout << i << " ";
        for (int j = 1; j <= wid - 1; j++) {
            if (i == 0)
                cout << j << " ";  // 显示列号
            else if (allay_Click[i][j] == 0)
                cout << a[0] << " ";  // 未点击的格子
            else
                cout << allay_Number[i][j] << " ";  // 已点击的格子
        }
        cout << '\n';
    }
}

3.3 处理用户输入

在主函数中,我们需要处理用户的输入,并根据输入更新游戏状态。

int main() {
    char restart;
    do {
        // 初始化游戏
        initGame();
        int x, y;
        int times = 0, flag = 0;
        while (1) {
            // 显示游戏界面
            print();
            cout << "请输入要检查的位置的横纵坐标(1-9):\n";
        
            // 读取用户输入并验证
            string input;
            getline(cin, input);
            stringstream ss(input);
            int numRead = 0;
            while (ss >> x) {
                numRead++;
                if (numRead == 1) {
                    y = x;
                } else if (numRead > 2) {
                    break;
                }
            }
        
            // 验证输入是否合法
            if (numRead != 2 || x <= 0 || x >= 10 || y <= 0 || y >= 10 || allay_Click[y][x] == 1) {
                cout << "输入无效,请重新输入!\n";
                continue;
            }
        
            // 处理用户点击
            if (allay_Number[y][x] == BOOM) {
                cout << "失败!您被雷炸死了~~\n";
                break;
            } else {
                allay_Click[y][x] = 1;
                times++;
            }
        
            // 检查游戏是否胜利
            if (times == 72) {  // 72 = 10*10 - 9 - 19(边界格子)
                flag = 1;
                break;
            }
        }
    
        // 显示游戏结果
        if (flag == 1) {
            print();
            cout << "恭喜您获胜!\n";
        }
    
        // 询问是否重新开始
        cout << "按'r'键重新开始游戏,按其他键退出:\n ";
        cin >> restart;
        cin.ignore(numeric_limits<streamsize>::max(), '\n');
    } while (restart == 'r' || restart == 'R');

    return 0;
}

四、输入验证与错误处理

在游戏中,用户输入的合法性非常重要。我们使用字符串流来确保用户输入恰好两个整数,并处理各种异常情况。

string input;
getline(cin, input);
stringstream ss(input);
int numRead = 0;
while (ss >> x) {
    numRead++;
    if (numRead == 1) {
        y = x;
    } else if (numRead > 2) {
        break;
    }
}
// 检查输入是否合法
if (numRead != 2 || x <= 0 || x >= 10 || y <= 0 || y >= 10 || allay_Click[y][x] == 1) {
    cout << "输入无效,请重新输入!\n";
    continue;
}

五、游戏体验优化

5.1 自动展开空白区域

在实际的扫雷游戏中,当点击到周围没有地雷的格子时,会自动展开周围的格子。我们可以通过递归或迭代的方式实现这一功能。

5.2 标记地雷功能

可以添加标记地雷的功能,让玩家能够标记他们认为是地雷的格子,提高游戏体验。

5.3 界面美化

使用控制台颜色和符号美化游戏界面,例如使用不同的颜色显示不同的数字,或者使用特殊字符表示地雷和旗帜。

六、总结与扩展

通过本文的学习,我们掌握了如何用 C++ 实现一个完整的扫雷游戏。从数据结构设计到核心功能实现,再到输入验证和游戏体验优化,我们一步步构建了一个功能完善的游戏。

当然,这个扫雷游戏还有很多可以扩展的地方,例如:

  1. 添加难度级别选择(初级、中级、高级)
  2. 实现计时器和最佳成绩记录
  3. 添加图形界面,使用图形库如 SFML 或 Qt
  4. 优化算法,提高游戏性能

通过不断地学习和实践,你可以进一步完善这个扫雷游戏,同时也能提高自己的 C++ 编程水平。希望本文能为你提供一个良好的起点,让你在编程的道路上越走越远。

  1. ipvdeqhljq说道:

    做了几十年的项目 总结最好的

  2. 鍗庣撼鍏徃鍚堜綔寮€鎴锋墍闇€鏉愭枡锛熺數璇濆彿鐮?5587291507 寰俊STS5099说道:

    华纳东方明珠客服电话是多少?(▲18288362750?《?微信STS5099? 】
    如何联系华纳东方明珠客服?(▲18288362750?《?微信STS5099? 】
    华纳东方明珠官方客服联系方式?(▲18288362750?《?微信STS5099?
    华纳东方明珠客服热线?(▲18288362750?《?微信STS5099?
    华纳东方明珠24小时客服电话?(▲18288362750?《?微信STS5099? 】
    华纳东方明珠官方客服在线咨询?(▲18288362750?《?微信STS5099?

  3. 鍗庣撼鍏徃鍚堜綔寮€鎴锋墍闇€鏉愭枡锛熺數璇濆彿鐮?5587291507 寰俊STS5099说道:

    华纳东方明珠客服电话是多少?(??155--8729--1507?《?薇-STS5099】【?扣6011643?】
    华纳东方明珠开户专线联系方式?(??155--8729--1507?《?薇-STS5099】【?扣6011643?】

发表评论

电子邮件地址不会被公开。 必填项已用*标注