特别鸣谢:@(提供扫雷画面) 以及豆包
//记得加 -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;
}