本人蒟蒻,啥也不会
扫雷(小游戏)
//记得加上-std=c++11
#include <windows.h>
#include <iostream>
#include <vector>
#include <string>
#include <iomanip>
#include <cstdlib>
#include <ctime>
#include <conio.h>
#include <fstream>
#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_GREEN | BACKGROUND_BLUE)
#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)
enum GameState { PLAYING, WIN, LOSE };
double totalScore = 0.0;
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 chordReveal(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;
int flagCount = 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 && board[nr][nc].isFlagged)
flagCount++;
}
}
if (flagCount == cell.adjacentMines) {
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);
}
}
}
}
}
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;
double add = (double)totalMines / width;
totalScore += add;
saveScore();
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++;
}
}
}
void moveCursor(int dr, int dc) {
if (state != PLAYING) return;
int nr = cursorRow + dr;
int nc = cursorCol + dc;
if (nr >= 0 && nr < height && nc >= 0 && nc < width) {
cursorRow = nr;
cursorCol = nc;
}
}
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 << " W/A/S/D ";
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 << "F";
setColor(FG_WHITE | BG_BLACK); std::cout << "插旗 ";
setColor(FG_CYAN | FG_INTENSITY | BG_BLACK); std::cout << "C";
setColor(FG_WHITE | BG_BLACK); std::cout << "快速翻开 ";
setColor(FG_CYAN | FG_INTENSITY | BG_BLACK); std::cout << "Q";
setColor(FG_WHITE | BG_BLACK); std::cout << "返回菜单" << std::endl;
}
void runCursorMode() {
while (state == PLAYING) {
draw();
int ch = _getch();
if (ch >= 'A' && ch <= 'Z') ch += 32;
switch (ch) {
case 'w': moveCursor(-1, 0); break;
case 's': moveCursor(1, 0); break;
case 'a': moveCursor(0, -1); break;
case 'd': moveCursor(0, 1); break;
case ' ': revealCell(cursorRow, cursorCol); break;
case 'f': toggleFlag(cursorRow, cursorCol); break;
case 'c': chordReveal(cursorRow, cursorCol); break;
case 'q': return;
default: break;
}
}
draw();
std::cout << "\n游戏结束,按任意键返回菜单...";
_getch();
}
void clearScreen() {
system("cls");
}
void saveScore() {
std::ofstream file("score.txt");
if (file.is_open()) {
file << totalScore << std::endl;
file.close();
}
}
void loadScore() {
std::ifstream file("score.txt");
if (file.is_open()) {
file >> totalScore;
file.close();
}
}
};
void loadScore() {
std::ifstream file("score.txt");
if (file.is_open()) {
file >> totalScore;
file.close();
}
}
void showCustomMenu() {
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 << " 总积分:";
SetConsoleTextAttribute(hConsole, FG_CYAN | FG_INTENSITY | BG_BLACK);
std::cout << std::fixed << std::setprecision(2) << totalScore << std::endl << std::endl;
SetConsoleTextAttribute(hConsole, FG_WHITE | BG_BLACK);
std::cout << " 1. 开始游戏" << std::endl;
std::cout << " 0. 退出游戏" << std::endl;
std::cout << "----------------------------------------" << std::endl;
std::cout << " 请输入选项 (0/1): ";
}
int main() {
SetConsoleTitle("扫雷");
loadScore();
int choice;
bool exitProgram = false;
while (!exitProgram) {
showCustomMenu();
std::cin >> choice;
std::cin.ignore();
if (choice == 0) {
exitProgram = true;
continue;
}
if (choice != 1) {
continue;
}
int size, mines;
system("cls");
std::cout << "========= 扫雷 =========\n";
std::cout << "请输入棋盘边长(5~50): ";
std::cin >> size;
if (size < 5) size = 5;
if (size > 50) size = 50;
std::cout << "请输入地雷数量(1~" << size*size-1 << "): ";
std::cin >> mines;
if (mines < 1) mines = 1;
if (mines >= size*size) mines = size*size - 1;
Minesweeper game;
game.clearScreen();
game.initGame(size, size, mines, -1);
game.runCursorMode();
}
system("cls");
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FG_WHITE | BG_BLACK);
std::cout << "感谢游玩,再见!" << std::endl;
return 0;
}