// ===== CodeLab: C++ 小游戏③:扫雷(控制台) =====
// 来源: https://aoerliang.dpdns.org/articles/game-cpp-minesweeper
// 以下代码片段按文章出现顺序拼接, 共 6 段

// ----- 片段 1 (cpp) -----
#include <iostream>
#include <vector>
#include <queue>
#include <random>

const int ROWS = 9, COLS = 9, MINES = 10;

std::vector<std::vector<int>> board(ROWS, std::vector<int>(COLS, 0));
std::vector<std::vector<bool>> shown(ROWS, std::vector<bool>(COLS, false));
// board: -1 表示地雷,其他为周围雷数;shown: 是否已翻开

// ----- 片段 2 (cpp) -----
void placeMines() {
    std::random_device rd;
    std::mt19937 gen(rd());
    std::uniform_int_distribution<int> rr(0, ROWS - 1);
    std::uniform_int_distribution<int> cc(0, COLS - 1);
    int placed = 0;
    while (placed < MINES) {
        int r = rr(gen), c = cc(gen);
        if (board[r][c] != -1) {
            board[r][c] = -1;
            ++placed;
        }
    }
}

// ----- 片段 3 (cpp) -----
const int dr[8] = {-1, -1, -1, 0, 0, 1, 1, 1};
const int dc[8] = {-1, 0, 1, -1, 1, -1, 0, 1};

void countNumbers() {
    for (int r = 0; r < ROWS; ++r)
        for (int c = 0; c < COLS; ++c) {
            if (board[r][c] == -1) continue;
            int cnt = 0;
            for (int k = 0; k < 8; ++k) {
                int nr = r + dr[k], nc = c + dc[k];
                if (nr >= 0 && nr < ROWS && nc >= 0 && nc < COLS
                    && board[nr][nc] == -1)
                    ++cnt;
            }
            board[r][c] = cnt;
        }
}

// ----- 片段 4 (cpp) -----
void reveal(int sr, int sc) {
    std::queue<std::pair<int, int>> q;
    q.push({sr, sc});
    while (!q.empty()) {
        auto [r, c] = q.front();
        q.pop();
        if (r < 0 || r >= ROWS || c < 0 || c >= COLS) continue;
        if (shown[r][c] || board[r][c] == -1) continue;
        shown[r][c] = true;
        if (board[r][c] != 0) continue;   // 数字格不扩散
        for (int k = 0; k < 8; ++k)
            q.push({r + dr[k], c + dc[k]});
    }
}

// ----- 片段 5 (cpp) -----
void draw() {
    std::cout << "   ";
    for (int c = 0; c < COLS; ++c) std::cout << c << " ";
    std::cout << "\n";
    for (int r = 0; r < ROWS; ++r) {
        std::cout << r << "  ";
        for (int c = 0; c < COLS; ++c) {
            if (!shown[r][c]) std::cout << "# ";
            else if (board[r][c] == -1) std::cout << "* ";
            else if (board[r][c] == 0) std::cout << ". ";
            else std::cout << board[r][c] << " ";
        }
        std::cout << "\n";
    }
}

int main() {
    placeMines();
    countNumbers();
    int opened = 0;
    while (opened < ROWS * COLS - MINES) {
        draw();
        int r, c;
        std::cout << "输入坐标(行 列): ";
        std::cin >> r >> c;
        if (r < 0 || r >= ROWS || c < 0 || c >= COLS) continue;
        if (board[r][c] == -1) {
            std::cout << "踩雷了!游戏结束。\n";
            return 0;
        }
        reveal(r, c);
        opened = 0;
        for (int i = 0; i < ROWS; ++i)
            for (int j = 0; j < COLS; ++j)
                if (shown[i][j]) ++opened;
    }
    std::cout << "恭喜,排除所有地雷!\n";
    return 0;
}

// ----- 片段 6 (bash) -----
g++ -std=c++17 -o minesweeper minesweeper.cpp
./minesweeper
