特别鸣谢:@(提供扫雷画面) 以及豆包

//记得加 -std=c++11

#include<bits/stdc++.h>
#include<windows.h>
#include<conio.h>

#define FG_BLACK        0
#define FG_BLUE         FOREGROUND_BLUE
#define FG_GREEN        FOREGROUND_GREEN
#define FG_RED          FOREGROUND_RED
#define FG_CYAN         (FOREGROUND_BLUE | FOREGROUND_GREEN)
#define FG_MAGENTA      (FOREGROUND_RED | FOREGROUND_BLUE)
#define FG_YELLOW       (FOREGROUND_RED | FOREGROUND_GREEN)
#define FG_WHITE        (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE)
#define FG_INTENSITY    FOREGROUND_INTENSITY

#define BG_BLACK        0
#define BG_BLUE         BACKGROUND_BLUE
#define BG_GREEN        BACKGROUND_GREEN
#define BG_RED          BACKGROUND_RED
#define BG_CYAN         (BACKGROUND_BLUE | BACKGROUND_GREEN)
#define BG_MAGENTA      (BACKGROUND_RED | BACKGROUND_BLUE)
#define BG_YELLOW       (BACKGROUND_RED | BACKGROUND_GREEN)
#define BG_WHITE        (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE)
#define BG_INTENSITY    BACKGROUND_INTENSITY

#define COLOR_UNOPEN    (FG_BLACK | BG_GRAY)
#define COLOR_FLAG      (FG_WHITE | FG_INTENSITY | BG_RED)
#define COLOR_MINE      (FG_RED | FG_INTENSITY | BG_BLACK)
#define COLOR_EMPTY     (FG_BLACK | BG_WHITE)
#define COLOR_CURSOR_HIGHLIGHT (FG_BLACK | BG_YELLOW | BG_INTENSITY)

#define BG_GRAY         (BACKGROUND_INTENSITY)

using namespace std;

enum GameState { PLAYING, WIN, LOSE };

struct Cell {
    bool isMine;
    bool isRevealed;
    bool isFlagged;
    int adjacentMines;
    Cell() : isMine(false), isRevealed(false), isFlagged(false), adjacentMines(0) {}
};

class Minesweeper {
private:
    int width, height;
    int totalMines;
    int flagsPlaced;
    int revealedCount;
    bool firstMove;
    GameState state;
    std::vector<std::vector<Cell>> board;
    int cursorRow, cursorCol;
    int difficultyIndex;

    HANDLE hConsole;

public:
    Minesweeper() : hConsole(GetStdHandle(STD_OUTPUT_HANDLE)) {
        srand((unsigned)time(nullptr));
        hideCursor();
        cursorRow = cursorCol = 0;
        difficultyIndex = 0;
    }

    void hideCursor() {
        CONSOLE_CURSOR_INFO cursorInfo;
        GetConsoleCursorInfo(hConsole, &cursorInfo);
        cursorInfo.bVisible = FALSE;
        SetConsoleCursorInfo(hConsole, &cursorInfo);
    }

    void gotoxy(int x, int y) {
        COORD coord = { (SHORT)x, (SHORT)y };
        SetConsoleCursorPosition(hConsole, coord);
    }

    void setColor(int color) {
        SetConsoleTextAttribute(hConsole, color);
    }

    void initGame(int w, int h, int mines, int diffIdx) {
        width = w;
        height = h;
        totalMines = mines;
        difficultyIndex = diffIdx;
        flagsPlaced = 0;
        revealedCount = 0;
        firstMove = true;
        state = PLAYING;
        cursorRow = cursorCol = 0;
        board.assign(height, std::vector<Cell>(width));
    }

    void placeMines(int excludeRow, int excludeCol) {
        int cells = width * height;
        int minesToPlace = totalMines;
        if (minesToPlace > cells - 1) minesToPlace = cells - 1;
        while (minesToPlace > 0) {
            int idx = rand() % cells;
            int r = idx / width;
            int c = idx % width;
            if ((r == excludeRow && c == excludeCol) || board[r][c].isMine)
                continue;
            board[r][c].isMine = true;
            minesToPlace--;
        }
        calculateAdjacentNumbers();
    }

    void calculateAdjacentNumbers() {
        for (int r = 0; r < height; ++r) {
            for (int c = 0; c < width; ++c) {
                if (board[r][c].isMine) {
                    board[r][c].adjacentMines = -1;
                } else {
                    int count = 0;
                    for (int dr = -1; dr <= 1; ++dr) {
                        for (int dc = -1; dc <= 1; ++dc) {
                            if (dr == 0 && dc == 0) continue;
                            int nr = r + dr;
                            int nc = c + dc;
                            if (nr >= 0 && nr < height && nc >= 0 && nc < width && board[nr][nc].isMine)
                                count++;
                        }
                    }
                    board[r][c].adjacentMines = count;
                }
            }
        }
    }

    void revealCell(int row, int col) {
        if (row < 0 || row >= height || col < 0 || col >= width) return;
        Cell& cell = board[row][col];
        if (cell.isRevealed || cell.isFlagged || state != PLAYING) return;
        
        if (firstMove) {
            firstMove = false;
            if (cell.isMine) {
                for (int r = 0; r < height; ++r)
                    for (int c = 0; c < width; ++c)
                        board[r][c].isMine = false;
                placeMines(row, col);
            } else {
                bool hasMine = false;
                for (int r = 0; r < height && !hasMine; ++r)
                    for (int c = 0; c < width && !hasMine; ++c)
                        if (board[r][c].isMine) hasMine = true;
                if (!hasMine) placeMines(row, col);
            }
        }
        
        Cell& current = board[row][col];
        if (current.isMine) {
            state = LOSE;
            revealAllMines();
            return;
        }
        
        current.isRevealed = true;
        revealedCount++;
        
        if (current.adjacentMines == 0) {
            for (int dr = -1; dr <= 1; ++dr) {
                for (int dc = -1; dc <= 1; ++dc) {
                    if (dr == 0 && dc == 0) continue;
                    int nr = row + dr;
                    int nc = col + dc;
                    if (nr >= 0 && nr < height && nc >= 0 && nc < width) {
                        if (!board[nr][nc].isRevealed && !board[nr][nc].isFlagged) {
                            revealCell(nr, nc);
                        }
                    }
                }
            }
        }
        checkWinCondition();
    }

    void toggleFlag(int row, int col) {
        if (row < 0 || row >= height || col < 0 || col >= width) return;
        if (state != PLAYING) return;
        Cell& cell = board[row][col];
        if (cell.isRevealed) return;
        cell.isFlagged = !cell.isFlagged;
        flagsPlaced += cell.isFlagged ? 1 : -1;
    }

    void revealAllMines() {
        for (int r = 0; r < height; ++r)
            for (int c = 0; c < width; ++c)
                if (board[r][c].isMine)
                    board[r][c].isRevealed = true;
    }

    void checkWinCondition() {
        if (revealedCount == width * height - totalMines) {
            state = WIN;
            for (int r = 0; r < height; ++r)
                for (int c = 0; c < width; ++c)
                    if (board[r][c].isMine && !board[r][c].isFlagged) {
                        board[r][c].isFlagged = true;
                        flagsPlaced++;
                    }
        }
    }

    int getCellColor(const Cell& cell) const {
        if (!cell.isRevealed) {
            return cell.isFlagged ? COLOR_FLAG : COLOR_UNOPEN;
        } else {
            if (cell.isMine) return COLOR_MINE;
            if (cell.adjacentMines == 0) return COLOR_EMPTY;
            int fg;
            switch(cell.adjacentMines) {
                case 1: fg = FG_BLUE  | FG_INTENSITY; break;
                case 2: fg = FG_GREEN | FG_INTENSITY; break;
                case 3: fg = FG_RED   | FG_INTENSITY; break;
                case 4: fg = FG_BLUE;                      break;
                case 5: fg = FG_RED;                       break;
                case 6: fg = FG_CYAN  | FG_INTENSITY; break;
                case 7: fg = FG_MAGENTA | FG_INTENSITY; break;
                case 8: fg = FG_BLACK | FG_INTENSITY; break;
                default: fg = FG_BLACK;
            }
            return fg | BG_WHITE;
        }
    }

    void draw() {
        gotoxy(0, 0);
        
        setColor(FG_WHITE | BG_BLACK);
        std::cout << "========== 扫雷游戏 ==========" << std::endl;
        
        int remainingMines = totalMines - flagsPlaced;
        std::cout << "剩余雷数: ";
        setColor(FG_RED | FG_INTENSITY | BG_BLACK);
        std::cout << remainingMines << "  ";
        
        if (state == PLAYING) {
            setColor(FG_GREEN | FG_INTENSITY | BG_BLACK);
            std::cout << "[游戏中]";
        } else if (state == WIN) {
            setColor(FG_CYAN | FG_INTENSITY | BG_BLACK);
            std::cout << "[你赢了!]";
        } else if (state == LOSE) {
            setColor(FG_RED | FG_INTENSITY | BG_BLACK);
            std::cout << "[游戏结束]";
        }
        setColor(FG_WHITE | BG_BLACK);
        std::cout << "    光标: (" << cursorRow << "," << cursorCol << ")" << std::endl;
        
        std::cout << "  +";
        for (int c = 0; c < width; ++c) std::cout << "--";
        std::cout << "+" << std::endl;
        
        for (int r = 0; r < height; ++r) {
            std::cout << "  |";
            
            for (int c = 0; c < width; ++c) {
                const Cell& cell = board[r][c];
                bool isCursor = (r == cursorRow && c == cursorCol);
                
                char content;
                if (!cell.isRevealed) {
                    content = cell.isFlagged ? 'F' : '#';
                } else {
                    if (cell.isMine) content = '*';
                    else if (cell.adjacentMines == 0) content = ' ';
                    else content = '0' + cell.adjacentMines;
                }
                
                int color = getCellColor(cell);
                if (isCursor) {
                    int fg = color & 0x0F;
                    color = fg | COLOR_CURSOR_HIGHLIGHT;
                }
                
                setColor(color);
                if (isCursor) std::cout << '>';
                else std::cout << ' ';
                std::cout << content;
            }
            
            setColor(FG_WHITE | BG_BLACK);
            std::cout << "|" << std::endl;
        }
        
        std::cout << "  +";
        for (int c = 0; c < width; ++c) std::cout << "--";
        std::cout << "+" << std::endl;
        
        setColor(FG_WHITE | BG_BLACK);
        std::cout << "\n操作:";
        setColor(FG_CYAN | FG_INTENSITY | BG_BLACK);   std::cout << " 鼠标移动 ";
        setColor(FG_WHITE | BG_BLACK);                 std::cout << "选择格子  ";
        setColor(FG_CYAN | FG_INTENSITY | BG_BLACK);   std::cout << " 左键 ";
        setColor(FG_WHITE | BG_BLACK);                 std::cout << "揭开格子  ";
        setColor(FG_CYAN | FG_INTENSITY | BG_BLACK);   std::cout << " 右键 ";
        setColor(FG_WHITE | BG_BLACK);                 std::cout << "标记/取消标记" << std::endl;
    }

    void runMouseMode() {
        HANDLE hIn = GetStdHandle(STD_INPUT_HANDLE);
        DWORD oldMode;
        GetConsoleMode(hIn, &oldMode);
        SetConsoleMode(hIn, ENABLE_MOUSE_INPUT | ENABLE_EXTENDED_FLAGS);

        while (state == PLAYING) {
            draw();
            INPUT_RECORD ir;
            DWORD rd;
            bool ok = false;
            while (!ok && state == PLAYING) {
                ReadConsoleInput(hIn, &ir, 1, &rd);
                if (ir.EventType != MOUSE_EVENT) continue;
                MOUSE_EVENT_RECORD me = ir.Event.MouseEvent;
                int cx = me.dwMousePosition.X;
                int cy = me.dwMousePosition.Y;

                int gx = cy - 3;
                int gy = (cx - 3) / 2;
                bool in = (gx >= 0 && gx < height) && (gy >= 0 && gy < width);

                if (!in) continue;

                cursorRow = gx;
                cursorCol = gy;

                if (me.dwEventFlags == MOUSE_MOVED) {
                    ok = true;
                }

                if ((me.dwButtonState & FROM_LEFT_1ST_BUTTON_PRESSED) && (me.dwEventFlags == 0)) {
                    revealCell(gx, gy);
                    ok = true;
                }

                if ((me.dwButtonState & RIGHTMOST_BUTTON_PRESSED) && (me.dwEventFlags == 0)) {
                    toggleFlag(gx, gy);
                    ok = true;
                }
            }
        }

        draw();
        SetConsoleMode(hIn, oldMode);
        std::cout << "\n游戏结束,按任意键返回菜单...";
        _getch();
    }

    void clearScreen() {
        system("cls");
    }
};
const int con_bc[5]={0,9,16,22,30},con_lei[5]={0,10,40,99,200};
int ci=0,bc,left_flag=2e9;
int showMenu() {
    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
    SetConsoleTextAttribute(hConsole, FG_WHITE | BG_BLACK);
    system("cls");
    std::cout << "========================================" << std::endl;
    std::cout << "           扫 雷 游 戏(鼠标版)                " << std::endl;
    std::cout << "========================================" << std::endl;
    std::cout << "  选择难度 (正方形棋盘):" << std::endl;
    std::cout << "    1. 初级  (9x9,  10 雷)  " <<  std::endl;
    std::cout << "    2. 中级  (16x16, 40 雷)  " << std::endl;
    std::cout << "    3. 高级  (22x22, 99 雷)  " << std::endl;
    std::cout << "    4. 专家  (30x30, 200 雷) " << std::endl;
    std::cout << "    5. 自定义 (自行输入边长和雷数)" << std::endl;
    std::cout << "    0. 退出" << std::endl;
    std::cout << "----------------------------------------" << std::endl;
    std::cout << "  请输入选项 (0-5): "<<endl;
    std::cout << "  为了游玩舒适,请将窗口调成全屏!!!请匀速缓慢移动鼠标!!!"<<endl;
    int x;cin>>x;
    if(x==0){
		if(!ci) cout<<"拜拜!!!!!!!!!!!(臭shazi)";
		else cout<<"感谢游玩!!!"; 
		return 0;
	}
	else if(x==5){
		cout<<"请输入边长:";
		cin>>bc;
		cout<<"输入的边长:"<<bc<<endl<<"请输入雷的个数:"<<endl; 
		bool p=0;left_flag=2e9; 
		while(left_flag>=bc*bc){
			if(p){cout<<"输入的雷数:"<<left_flag<<" (不符合)"<<endl;}
			cin>>left_flag;
			p=1;
		}
		cout<<"输入的雷数:"<<left_flag<<endl;
	}
	else bc=con_bc[x],left_flag=con_lei[x];
	return 1;
}
int main(){
    SetConsoleTitle("扫雷游戏");
    HANDLE hOut=GetStdHandle(STD_OUTPUT_HANDLE);
    while(1){
    	if(!showMenu()) break;
        Minesweeper game;
        game.clearScreen();
        game.initGame(bc, bc, left_flag, -1);
        game.runMouseMode();
        game.clearScreen();
        ci++;
    }
    return 0;
}