DP版扫雷
#include <iostream>
#include <vector>
#include <ctime>
#include <cstdlib>
#include <windows.h> // 用于彩色输出
#include <conio.h> // 用于_getch()
#include <iomanip> // 用于setw()
using namespace std;
// 颜色定义
const int BLACK = 0;
const int BLUE = 1;
const int GREEN = 2;
const int CYAN = 3;
const int RED = 4;
const int MAGENTA = 5;
const int YELLOW = 6;
const int WHITE = 7;
const int GRAY = 8;
const int BRIGHT_BLUE = 9;
const int BRIGHT_GREEN = 10;
const int BRIGHT_CYAN = 11;
const int BRIGHT_RED = 12;
const int BRIGHT_MAGENTA = 13;
const int BRIGHT_YELLOW = 14;
const int BRIGHT_WHITE = 15;
// 设置控制台颜色
void setColor(int foreground, int background = BLACK) {
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), foreground | (background << 4));
}
// 游戏状态
enum GameState {
MENU,
SETUP,
PLAYING,
GAME_OVER,
WIN
};
class Minesweeper {
private:
int n, m; // 地图大小
int totalMines; // 总雷数
int remainingMines; // 剩余雷数
int flags; // 已标记数
time_t startTime; // 游戏开始时间
vector<vector<int>> board; // 游戏板 (-1=雷, 0-8=周围雷数)
vector<vector<bool>> revealed; // 已揭示的格子
vector<vector<bool>> marked; // 已标记的格子
GameState state; // 游戏状态
bool firstClick; // 是否是第一次点击
public:
Minesweeper() : state(MENU), firstClick(true) {}
// 显示主菜单
void showMenu() {
system("cls");
setColor(BRIGHT_WHITE);
cout << "======================" << endl;
cout << " 扫雷游戏 " << endl;
cout << "======================" << endl;
cout << "1. 开始游戏" << endl;
cout << "2. 退出游戏" << endl;
cout << "======================" << endl;
cout << "请选择: ";
}
// 设置游戏参数
void setupGame() {
system("cls");
setColor(BRIGHT_WHITE);
cout << "======================" << endl;
cout << " 游戏设置 " << endl;
cout << "======================" << endl;
// 输入地图大小
cout << "输入地图大小 (行 列, 如 10 10): ";
cin >> n >> m;
// 输入雷数
char choice;
cout << "随机生成雷数? (y/n): ";
cin >> choice;
if (choice == 'y' || choice == 'Y') {
// 随机生成雷数 (10%-20%的格子是雷)
int minMines = n * m * 0.1;
int maxMines = n * m * 0.2;
totalMines = minMines + rand() % (maxMines - minMines + 1);
} else {
cout << "输入雷数 (不超过 " << n*m << "): ";
cin >> totalMines;
}
remainingMines = totalMines;
flags = 0;
// 初始化游戏板
board = vector<vector<int>>(n, vector<int>(m, 0));
revealed = vector<vector<bool>>(n, vector<bool>(m, false));
marked = vector<vector<bool>>(n, vector<bool>(m, false));
state = PLAYING;
firstClick = true;
}
// 放置地雷 (避开第一次点击的位置)
void placeMines(int firstX, int firstY) {
int minesPlaced = 0;
while (minesPlaced < totalMines) {
int x = rand() % n;
int y = rand() % m;
// 避开第一次点击的位置及其周围8格
if ((abs(x - firstX) <= 1 && abs(y - firstY) <= 1) || board[x][y] == -1) {
continue;
}
board[x][y] = -1; // -1表示雷
minesPlaced++;
// 更新周围格子的数字
for (int i = max(0, x-1); i <= min(n-1, x+1); i++) {
for (int j = max(0, y-1); j <= min(m-1, y+1); j++) {
if (board[i][j] != -1) {
board[i][j]++;
}
}
}
}
}
// 显示游戏板
void displayBoard() {
system("cls");
// 显示游戏信息
setColor(BRIGHT_WHITE);
cout << "雷数: " << remainingMines << " 用时: " << (time(nullptr) - startTime) << "秒" << endl;
// 显示列号
cout << " ";
for (int j = 0; j < m; j++) {
cout << setw(2) << j << " ";
}
cout << endl;
// 显示游戏板
for (int i = 0; i < n; i++) {
cout << setw(2) << i << " ";
for (int j = 0; j < m; j++) {
if (marked[i][j]) {
setColor(BRIGHT_RED);
cout << " F "; // 旗帜标记
} else if (!revealed[i][j]) {
setColor(GRAY);
cout << " ■ "; // 未揭示的格子
} else if (board[i][j] == -1) {
setColor(BRIGHT_RED);
cout << " * "; // 雷
} else if (board[i][j] == 0) {
setColor(WHITE);
cout << " "; // 空白
} else {
setColor(board[i][j]); // 数字用不同颜色显示
cout << " " << board[i][j] << " ";
}
setColor(WHITE);
}
cout << endl;
}
// 显示操作提示
cout << "\n操作: (WASD移动, 空格揭示, F标记, Q退出)" << endl;
cout << "提示: 当数字周围标记数等于数字时,可以自动翻开周围格子" << endl;
}
// 检查数字周围标记是否正确
bool checkSurroundingMarks(int x, int y) {
if (board[x][y] <= 0) return false;
int markedCount = 0;
for (int i = max(0, x-1); i <= min(n-1, x+1); i++) {
for (int j = max(0, y-1); j <= min(m-1, y+1); j++) {
if (marked[i][j]) markedCount++;
}
}
return markedCount == board[x][y];
}
// 揭示数字周围的格子
void revealAroundNumber(int x, int y) {
if (!checkSurroundingMarks(x, y)) return;
for (int i = max(0, x-1); i <= min(n-1, x+1); i++) {
for (int j = max(0, y-1); j <= min(m-1, y+1); j++) {
if (!marked[i][j] && !revealed[i][j]) {
reveal(i, j);
}
}
}
}
// 揭示格子
void reveal(int x, int y) {
if (x < 0 || x >= n || y < 0 || y >= m || revealed[x][y] || marked[x][y]) {
return;
}
revealed[x][y] = true;
// 如果是第一次点击,放置地雷
if (firstClick) {
placeMines(x, y);
firstClick = false;
startTime = time(nullptr);
}
// 如果是雷,游戏结束
if (board[x][y] == -1) {
state = GAME_OVER;
return;
}
// 如果是空白格子,递归揭示周围格子
if (board[x][y] == 0) {
for (int i = max(0, x-1); i <= min(n-1, x+1); i++) {
for (int j = max(0, y-1); j <= min(m-1, y+1); j++) {
if (!revealed[i][j]) {
reveal(i, j);
}
}
}
}
// 检查是否胜利
checkWin();
}
// 标记格子
void toggleMark(int x, int y) {
if (revealed[x][y]) {
// 如果是已揭示的数字,尝试自动翻开周围格子
if (board[x][y] > 0) {
revealAroundNumber(x, y);
}
return;
}
if (marked[x][y]) {
marked[x][y] = false;
flags--;
remainingMines++;
} else {
marked[x][y] = true;
flags++;
remainingMines--;
}
// 检查是否胜利
checkWin();
}
// 检查是否胜利
void checkWin() {
// 所有非雷格子都被揭示
bool allRevealed = true;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (board[i][j] != -1 && !revealed[i][j]) {
allRevealed = false;
break;
}
}
if (!allRevealed) break;
}
if (allRevealed) {
state = WIN;
}
}
// 游戏主循环
void playGame() {
int cursorX = 0, cursorY = 0;
while (state == PLAYING) {
displayBoard();
// 显示光标位置
COORD cursorPos;
cursorPos.X = 4 + cursorY * 3;
cursorPos.Y = 2 + cursorX;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), cursorPos);
setColor(BRIGHT_YELLOW, BLACK);
cout << "[" << (revealed[cursorX][cursorY] ? (board[cursorX][cursorY] == -1 ? "*" : (board[cursorX][cursorY] == 0 ? " " : to_string(board[cursorX][cursorY]))) : (marked[cursorX][cursorY] ? "F" : " ") ) << "]";
setColor(WHITE);
// 获取输入
char input = _getch();
// 处理输入
switch (tolower(input)) {
case 'w': if (cursorX > 0) cursorX--; break;
case 'a': if (cursorY > 0) cursorY--; break;
case 's': if (cursorX < n-1) cursorX++; break;
case 'd': if (cursorY < m-1) cursorY++; break;
case ' ': reveal(cursorX, cursorY); break;
case 'f': toggleMark(cursorX, cursorY); break;
case 'q': state = MENU; break;
}
}
// 游戏结束处理
if (state == GAME_OVER || state == WIN) {
// 揭示所有格子
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
revealed[i][j] = true;
}
}
displayBoard();
if (state == GAME_OVER) {
setColor(BRIGHT_RED);
cout << "\n游戏结束! 你踩到雷了!" << endl;
} else {
setColor(BRIGHT_GREEN);
cout << "\n恭喜你赢了! 用时: " << (time(nullptr) - startTime) << "秒" << endl;
}
setColor(WHITE);
cout << "按任意键返回主菜单...";
_getch();
state = MENU;
}
}
// 运行游戏
void run() {
while (true) {
if (state == MENU) {
showMenu();
char choice = _getch();
if (choice == '1') {
state = SETUP;
setupGame();
} else if (choice == '2') {
break;
}
} else if (state == PLAYING) {
playGame();
}
}
}
};
int main() {
srand(time(nullptr)); // 初始化随机数种子
Minesweeper game;
game.run();
return 0;
}