以下是一个简单的C语言扫雷小游戏的示例代码:
- #include <stdio.h>
- #include <stdlib.h>
- #include <time.h>
- #define BOARD_SIZE 10
- #define NUM_MINES 10
- int main() {
- int board[BOARD_SIZE][BOARD_SIZE];
- int num_flags, num_clicks;
- int row, col;
- int reveal[BOARD_SIZE][BOARD_SIZE];
- int mines_left;
- int won;
- char action;
- srand(time(NULL)); // 初始化随机数生成器
- // 初始化雷区,标记雷区中的雷数和未标记的雷数
- for (int i = 0; i < BOARD_SIZE; i++) {
- for (int j = 0; j < BOARD_SIZE; j++) {
- board[i][j] = 0; // 初始化为空格
- reveal[i][j] = 0; // 初始化为未揭示状态
- }
- }
- num_flags = 0; // 初始化为未标记的雷数为0
- mines_left = NUM_MINES; // 初始化为还有NUM_MINES个雷未被标记
- won = 0; // 初始化为游戏未获胜状态
- // 在随机位置放置雷区中的雷
- while (mines_left > 0) {
- row = rand() % BOARD_SIZE; // 随机选择行号
- col = rand() % BOARD_SIZE; // 随机选择列号
- if (board[row][col] != -1) { // 如果该位置不是已经被标记为雷的位置,则将该位置标记为雷,并更新mines_left和board数组
- board[row][col] = -1;
- mines_left--;
- } else { // 如果该位置已经被标记为雷,则重新选择位置
- continue;
- }
- num_flags++; // 更新已标记的雷数
- }
- // 游戏主循环,直到游戏获胜或玩家选择退出游戏为止
- while (1) {
- printf("\n\n"); // 输出一个空行,使输出更清晰
- printf("Minefield:\n"); // 输出雷区名称和当前已标记的雷数和剩余的雷数
- printf("F-revealed, flags: %d/%d\n", num_flags, BOARD_SIZE * BOARD_SIZE); // 输出已揭示的方块数和总方块数
- printf("C-click, Q-quit, X-flag\n"); // 输出操作提示信息,C表示点击方块,Q表示退出游戏,X表示标记方块为雷
- printf("\n"); // 输出一个空行,使输出更清晰
- for (int i = 0; i < BOARD_SIZE; i++) { // 输出雷区表格,0表示空格,-1表示雷,'#'表示已揭示的雷,'.'表示未揭示的空格,'F'表示已标记的雷
- for (int j = 0; j < BOARD_SIZE; j++) {
- if (board[i][j] == -1) { // 如果该位置是雷,则输出'#'并更新reveal数组中对应位置的状态为1(已揭示)和更新num_flags和num_clicks的值(点击了已揭示的雷)
- printf("#");
- reveal[i][j] = 1; // 将该位置揭示为雷区中的雷
示),否则输出board[i][j]的值(0或-1)
}
}
printf("\n"); // 输出一个空行,使输出更清晰
scanf(" %c", &action); // 获取玩家操作
if (action == 'c') { // 如果玩家选择点击方块
printf("Click: ");
scanf("%d %d", &row, &col); // 获取玩家点击的方块位置
if (board[row][col] == 0) { // 如果该位置是空格,则将该位置揭示为雷或空格,并输出相应信息
board[row][col] = 1;
reveal[row][col] = 1;
if (num_clicks == BOARD_SIZE * BOARD_SIZE - mines_left) { // 如果玩家已经点击了所有非雷的方块,则游戏获胜,跳出循环
won = 1;
break;
}
} else if (board[row][col] == -1) { // 如果该位置是雷,则游戏失败,跳出循环
won = -1;
break;
} else { // 如果该位置已经被揭示为雷或空格,则不进行任何操作,继续等待玩家输入下一个操作
continue;
}
num_clicks++; // 更新已点击的方块数
} else if (action == 'q') { // 如果玩家选择退出游戏,则跳出循环
won = 0;
break;
} else if (action == 'x') { // 如果玩家选择标记方块为雷
printf("Flag: ");
scanf("%d %d", &row, &col); // 获取玩家标记的方块位置
if (board[row][col] != -1 && reveal[row][col] == 0) { // 如果该位置是空格且未被揭示,则将该位置标记为雷,并输出相应信息
board[row][col] = -1;
reveal[row][col] = 1;
num_flags++; // 更新已标记的雷数
} else { // 如果该位置是雷或已经被揭示,则不进行任何操作,继续等待玩家输入下一个操作
continue;
}
} else { // 如果玩家输入的操作不是合法的,则提示玩家重新输入,并等待一段时间后自动回到游戏主循环开始下一轮操作
printf("Invalid action. Please try again.\n");
usleep(1000000); // 等待一段时间,使程序运行更流畅,避免频繁输入导致程序卡顿
continue;
}
if (won != 0) { // 如果游戏获胜或失败,输出相应信息,并等待一段时间后自动退出程序
printf("Game over! You %s!\n", won == 1 ? "won" : "lost");
usleep(1000000); // 等待一段时间,使程序运行更流畅,避免频繁输入导致程序卡顿
break;
}
}
这段代码实现了基本的扫雷游戏逻辑,玩家可以通过输入“C”来点击方块,输入“Q”来退出游戏,输入“X”来标记方块为雷。点击空格会揭示该位置为雷或空格,点击雷会导致游戏失败。当玩家已经点击了所有非雷的方块时,游戏获胜。游戏过程中,会随机生成雷区中的雷,并提示玩家当前已标记的雷数和剩余的雷数。当游戏结束后,会输出游戏结果。
注意,该代码仅供参考,可以根据需要进行修改和优化。同时,还需要考虑一些边界情况和错误处理,以确保程序的正确性和健壮性。
确实,这个简单的扫雷实现还没有包含一些高级功能,比如:无法标记已经被标记为雷的方块,没有提供撤销操作,游戏结束后无法重新开始等。同时,这个程序也没有处理输入错误的情况,比如:玩家输入了无效的操作。
下面是对这段代码的一些改进建议:
- 增加错误处理:当玩家输入了无效的操作时,程序应该能够捕获这个错误,并提示玩家重新输入。可以使用switch语句来处理不同的操作。
- 添加撤销操作:玩家应该有机会撤销他们最近的点击或标记操作。这可以通过在board和reveal数组中相应地更新来实现。
- 防止重复标记:玩家不应该能够标记已经被标记为雷的方块。可以在标记操作中增加一个检查,以确保玩家没有标记已经被标记的方块。
- 增加游戏结束后的选项:游戏结束后,玩家可以选择退出或者重新开始游戏。可以通过添加一个全局变量来跟踪游戏的状态,并在游戏结束后询问玩家的意愿。
- 优化布局和输出:当前的输出布局可能会有些混乱,特别是当游戏的规模变得很大的时候。可以考虑使用表格或者其他格式来更清晰地显示游戏状态。
- 增加难度等级:可以根据玩家的表现来调整游戏的难度,比如:随机生成更多的雷,或者增加每轮的操作次数等。
- 增加音效和图形界面:为了使游戏更加吸引人,可以添加音效和图形界面。这可能需要使用额外的库,比如:SDL或者Allegro。
这些只是一些基本的改进建议,你可以根据自己的需求和喜好来调整这个程序。