用c语言实现扫雷游戏
printf(" 扫雷游戏 (剩余安全格子: %d)\n", game->remaining);printf(" 操作: WASD移动 空格翻开 M标记 R重来 Q退出\n\n");case 'm': case 'M': // 标记地雷。case 'r': case 'R': // 重新开始。case 'q': case 'Q': // 退出游戏。case 'w': case 'W': // 上移
## C语言实现经典扫雷游戏:控制台版详解
扫雷是Windows经典的益智游戏,自1990年诞生以来风靡全球。本文将带你用C语言在控制台环境下完整实现这款经典游戏,并深入讲解核心算法和实现细节。
### 游戏规则与核心机制
1. **游戏目标**:在不触雷的情况下揭开所有非雷格子
2. **核心玩法**:
- 数字表示周围8格中的地雷数量
- 空格(0值)自动展开相邻安全区域
- 支持标记可疑地雷位置
3. **操作方式**:
- W/A/S/D:移动光标
- 空格:翻开格子
- M:标记/取消标记地雷
- R:重新开始游戏
- Q:退出游戏
### 完整代码实现
```c
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <conio.h>
#define ROWS 9
#define COLS 9
#define MINES 10
// 游戏状态
enum GameState {
PLAYING,
WIN,
LOSE
};
// 游戏数据结构
typedef struct {
char board[ROWS][COLS]; // 实际棋盘(包含地雷和数字)
char display[ROWS][COLS]; // 显示给玩家的棋盘
int mines[MINES][2]; // 地雷位置
int cursorRow, cursorCol; // 光标位置
int remaining; // 剩余安全格子数
enum GameState state; // 游戏状态
} Game;
// 初始化游戏
void initGame(Game* game) {
game->state = PLAYING;
game->remaining = ROWS * COLS - MINES;
game->cursorRow = 0;
game->cursorCol = 0;
// 初始化棋盘
for (int i = 0; i < ROWS; i++) {
for (int j = 0; j < COLS; j++) {
game->board[i][j] = '0';
game->display[i][j] = '#';
}
}
// 随机布雷
srand(time(NULL));
for (int i = 0; i < MINES; i++) {
int row = rand() % ROWS;
int col = rand() % COLS;
// 确保不重复布雷
if (game->board[row][col] == '*') {
i--;
continue;
}
game->board[row][col] = '*';
game->mines[i][0] = row;
game->mines[i][1] = col;
// 更新周围数字
for (int r = row-1; r <= row+1; r++) {
for (int c = col-1; c <= col+1; c++) {
if (r >= 0 && r < ROWS && c >= 0 && c < COLS &&
game->board[r][c] != '*') {
game->board[r][c]++;
}
}
}
}
}
// 绘制游戏界面
void drawGame(Game* game) {
system("cls"); // 清屏
printf(" 扫雷游戏 (剩余安全格子: %d)\n", game->remaining);
printf(" 操作: WASD移动 空格翻开 M标记 R重来 Q退出\n\n");
// 打印列号
printf(" ");
for (int j = 0; j < COLS; j++) {
printf("%d ", j);
}
printf("\n +");
for (int j = 0; j < COLS; j++) {
printf("--");
}
printf("+\n");
// 打印棋盘
for (int i = 0; i < ROWS; i++) {
printf("%d | ", i); // 行号
for (int j = 0; j < COLS; j++) {
// 高亮显示光标位置
if (i == game->cursorRow && j == game->cursorCol) {
printf("\033[1;31m"); // 红色高亮
}
printf("%c ", game->display[i][j]);
if (i == game->cursorRow && j == game->cursorCol) {
printf("\033[0m"); // 重置颜色
}
}
printf("|\n");
}
printf(" +");
for (int j = 0; j < COLS; j++) {
printf("--");
}
printf("+\n");
// 游戏状态提示
if (game->state == LOSE) {
printf("\n 游戏结束!你踩到地雷了!按R重新开始\n");
} else if (game->state == WIN) {
printf("\n 恭喜获胜!你成功避开了所有地雷!\n");
}
}
// 展开空白区域(递归实现)
void revealEmpty(Game* game, int row, int col) {
if (row < 0 || row >= ROWS || col < 0 || col >= COLS ||
game->display[row][col] != '#' || game->board[row][col] == '*') {
return;
}
game->display[row][col] = game->board[row][col];
game->remaining--;
if (game->board[row][col] == '0') {
// 递归展开周围的空白区域
for (int r = row-1; r <= row+1; r++) {
for (int c = col-1; c <= col+1; c++) {
if (!(r == row && c == col)) {
revealEmpty(game, r, c);
}
}
}
}
}
// 翻开格子
void revealCell(Game* game, int row, int col) {
if (game->display[row][col] != '#' || game->state != PLAYING) {
return;
}
if (game->board[row][col] == '*') {
// 踩到地雷
game->display[row][col] = '*';
game->state = LOSE;
// 显示所有地雷
for (int i = 0; i < MINES; i++) {
int r = game->mines[i][0];
int c = game->mines[i][1];
game->display[r][c] = '*';
}
} else {
revealEmpty(game, row, col);
// 检查是否获胜
if (game->remaining == 0) {
game->state = WIN;
}
}
}
// 标记格子
void markCell(Game* game, int row, int col) {
if (game->display[row][col] == '#') {
game->display[row][col] = 'M'; // 标记为地雷
} else if (game->display[row][col] == 'M') {
game->display[row][col] = '#'; // 取消标记
}
}
// 处理键盘输入
void handleInput(Game* game) {
int key = _getch();
switch (key) {
case 'w': case 'W': // 上移
if (game->cursorRow > 0) game->cursorRow--;
break;
case 's': case 'S': // 下移
if (game->cursorRow < ROWS-1) game->cursorRow++;
break;
case 'a': case 'A': // 左移
if (game->cursorCol > 0) game->cursorCol--;
break;
case 'd': case 'D': // 右移
if (game->cursorCol < COLS-1) game->cursorCol++;
break;
case ' ': // 翻开格子
revealCell(game, game->cursorRow, game->cursorCol);
break;
case 'm': case 'M': // 标记地雷
markCell(game, game->cursorRow, game->cursorCol);
break;
case 'r': case 'R': // 重新开始
initGame(game);
break;
case 'q': case 'Q': // 退出游戏
exit(0);
}
}
int main() {
Game game;
initGame(&game);
while (1) {
drawGame(&game);
handleInput(&game);
}
return 0;
}
```
### 核心算法解析
1. **地雷生成算法**:
- 使用`srand(time(NULL))`初始化随机数种子
- 循环生成随机坐标,确保位置不重复
- 更新周围格子的数字计数
2. **递归展开算法**:
- 当翻开空白格子(值为0)时递归展开相邻格子
- 边界检查防止越界访问
- 终止条件:遇到数字或已翻开的格子
3. **游戏状态管理**:
- 使用`remaining`变量追踪剩余安全格子
- 当翻开地雷时进入LOSE状态
- 当安全格子全部翻开时进入WIN状态
### 编译与运行方法
1. 保存代码为`minesweeper.c`
2. 使用GCC编译:
```bash
gcc minesweeper.c -o minesweeper
```
3. 运行游戏:
```bash
./minesweeper # Linux/Mac
minesweeper.exe # Windows
```
### 游戏界面示例
```
扫雷游戏 (剩余安全格子: 71)
操作: WASD移动 空格翻开 M标记 R重来 Q退出
0 1 2 3 4 5 6 7 8
+-----------------+
0 | # # # # # # # # # |
1 | # # # # # # # # # |
2 | # # # # # # # # # |
3 | # # # # # # # # # |
4 | # # # # # # # # # |
5 | # # # # # # # # # |
6 | # # # # # # # # # |
7 | # # # # # # # # # |
8 | # # # # # # # # # |
+-----------------+
```
### 扩展改进方向
1. **难度分级**:
```c
// 初级:9x9,10雷
// 中级:16x16,40雷
// 高级:16x30,99雷
```
2. **计时功能**:
```c
#include <time.h>
time_t startTime = time(NULL);
// 游戏过程中显示已用时间
```
3. **首次翻开保护**:
```c
// 确保第一次翻开不会是地雷
if (firstMove) {
while (board[row][col] == '*') {
// 重新布置地雷
}
}
```
4. **保存/加载游戏**:
```c
// 将游戏状态写入文件
FILE *saveFile = fopen("savegame.dat", "wb");
fwrite(game, sizeof(Game), 1, saveFile);
fclose(saveFile);
```
本实现完整展示了扫雷游戏的核心逻辑,使用纯C语言标准库实现,不依赖第三方库,适合学习C语言的项目实践。通过这个项目,可以深入理解二维数组操作、递归算法、状态机等编程核心概念。
更多推荐
所有评论(0)