为C语言实现的扫雷游戏添加游戏时长计时功能
给C语言扫雷游戏添加计时器功能
你手头有一款运行正常的C语言扫雷游戏,现在需要给它加上计时器功能,让游戏在结束(不管是胜利还是触雷失败)时显示玩家的游戏时长。下面是完整的修改方案和可运行代码:
实现思路
我们利用C标准库<time.h>里的工具来实现计时:
- 用
time_t类型变量记录游戏开始和结束的时间点 - 在雷区生成完成、玩家开始猜坐标前启动计时
- 游戏结束时计算时间差,转换成秒数并友好展示
修改后的完整代码
#include <stdio.h> #include <stdlib.h> #include <time.h> #define FLUSH fflush(stdin) // 全局变量 int x, y; int M, N; float diff; int total_mines = 0; int mines = 0; int minefield[30][30]; // 存储地雷、数字和空白的核心棋盘 int blank_minefield[30][30]; // 显示给玩家的初始棋盘(全为'-') int final_minefield[30][30]; // 游戏结束后展示的完整棋盘 time_t start_time, end_time; // 计时用的时间点变量 double game_duration; // 最终计算出的游戏时长(秒) // 函数声明 void difficulty( void ); void beginner( void ); void intermediate( void ); void expert( void ); void custom( void ); void minefield_generator( void ); void print_minefield( void ); void guess( void ); void boom( void ); void print_final_minefield( void ); void win( void ); void play_again( void ); void game_over( void ); int main() { printf("\t\tWelcome to Minesweeper\n"); difficulty(); return 0; } void difficulty( void ) { diff = 0; while( (diff != 1) && (diff != 2) && (diff != 3) && (diff != 4)) { printf("\t\tChoose a difficulty level(1-3) or 4 for a custom game:"); scanf("%f", &diff); FLUSH; if( (diff != 1) && (diff != 2) && (diff != 3) && (diff != 4)) { printf("\t\tPlease enter either 1, 2, 3 or 4\n"); } } if( diff == 1 ) { beginner(); } else if( diff == 2 ) { intermediate(); } else if( diff == 3 ) { expert(); } else if( diff == 4) { custom(); } } void beginner( void ) { M = 9; N = 9; total_mines = 10; minefield_generator(); start_time = time(NULL); // 生成雷区后启动计时 guess(); } void intermediate( void ) { M = 16; N = 16; total_mines = 40; minefield_generator(); start_time = time(NULL); // 启动计时 guess(); } void expert( void ) { M = 16; N = 30; total_mines = 99; minefield_generator(); start_time = time(NULL); // 启动计时 guess(); } void custom( void ) { M = 0; N = 0; total_mines = 0; printf("\t\tPlease enter the size of the dimensions you want\n"); printf("\t\tFirst value:\n"); scanf("%d", &M); printf("\t\tSecond value:\n"); scanf("%d", &N); printf("\t\tNumber of mines you want to assign to the board:\n"); scanf("%d", &total_mines); minefield_generator(); start_time = time(NULL); // 启动计时 guess(); } void minefield_generator( void ) { int i = 0, j = 0; srand( time( NULL ) ); // 初始化三个棋盘的初始状态 while( j < N ) { while( i < M) { minefield[i][j] = '-'; blank_minefield[i][j] = minefield[i][j]; final_minefield[i][j] = minefield[i][j]; i++; } i = 0; j++; } // 随机生成地雷 mines = 0; while( mines < total_mines ) { i = rand()%(M); j = rand()%(N); if( minefield[i][j] != '*') { minefield[i][j] = '*'; final_minefield[i][j] = minefield[i][j]; mines++; } } // 计算每个非雷格子的相邻地雷数量 i = 0; j = 0; while( j < N ) { while( i < M) { if( minefield[i][j] != '*') { minefield[i][j] = 0; // 检查8个相邻方向的地雷 if(i > 0 && j > 0 && minefield[i-1][j-1] == '*') minefield[i][j]++; if(i > 0 && minefield[i-1][j] == '*') minefield[i][j]++; if(j > 0 && minefield[i][j-1] == '*') minefield[i][j]++; if(i > 0 && j < N-1 && minefield[i-1][j+1] == '*') minefield[i][j]++; if(i < M-1 && j > 0 && minefield[i+1][j-1] == '*') minefield[i][j]++; if(i < M-1 && minefield[i+1][j] == '*') minefield[i][j]++; if(j < N-1 && minefield[i][j+1] == '*') minefield[i][j]++; if(i < M-1 && j < N-1 && minefield[i+1][j+1] == '*') minefield[i][j]++; } i++; } i = 0; j++; } } void print_minefield(void) { int i = 0, j = 0, z = 0; // 打印X轴坐标 printf("\t"); while( z < M ) { printf("|%d|\t", z); z++; } printf("\n\n"); // 打印棋盘内容和Y轴坐标 while( j < N ) { printf("|%d|\t", j); while( i < M) { if( blank_minefield[i][j] == '-') { printf("|%c|\t", blank_minefield[i][j]); } else { printf("|%d|\t", blank_minefield[i][j]); } i++; } printf("\n\n"); i = 0; j++; } } // 玩家猜坐标的核心逻辑 void guess( void ) { int revealed = 0; int total_safe = M*N - total_mines; // 非雷格子总数 while(1) { print_minefield(); printf("\t\tEnter coordinates (x y): "); scanf("%d %d", &x, &y); FLUSH; // 检查坐标是否合法 if(x < 0 || x >= M || y < 0 || y >= N) { printf("\t\tInvalid coordinates! Try again.\n"); continue; } // 触雷失败 if(minefield[x][y] == '*') { boom(); break; } // 揭开未探索的格子 if(blank_minefield[x][y] == '-') { blank_minefield[x][y] = minefield[x][y]; revealed++; // 检查是否清空所有非雷格子(胜利条件) if(revealed == total_safe) { win(); break; } } } } // 触雷失败的处理函数 void boom( void ) { end_time = time(NULL); game_duration = difftime(end_time, start_time); printf("\n\t\tBOOM! You hit a mine!\n"); printf("\t\tYour game lasted %.2f seconds.\n", game_duration); print_final_minefield(); play_again(); } // 游戏胜利的处理函数 void win( void ) { end_time = time(NULL); game_duration = difftime(end_time, start_time); printf("\n\t\tCongratulations! You Win!\n"); printf("\t\tYour game took %.2f seconds.\n", game_duration); print_final_minefield(); play_again(); } // 显示最终完整棋盘 void print_final_minefield( void ) { int i = 0, j = 0, z = 0; printf("\t\tFinal Minefield:\n"); printf("\t"); while( z < M ) { printf("|%d|\t", z); z++; } printf("\n\n"); while( j < N ) { printf("|%d|\t", j); while( i < M) { if(final_minefield[i][j] == '*') { printf("|%c|\t", final_minefield[i][j]); } else { printf("|%d|\t", final_minefield[i][j]); } i++; } printf("\n\n"); i = 0; j++; } } // 询问是否再玩一局 void play_again( void ) { char choice; printf("\t\tPlay again? (Y/N): "); scanf(" %c", &choice); FLUSH; if(choice == 'Y' || choice == 'y') { difficulty(); } else { game_over(); } } // 退出游戏 void game_over( void ) { printf("\t\tThanks for playing Minesweeper!\n"); exit(0); }
修改要点说明
- 新增计时变量:添加了
time_t类型的时间点变量和double类型的时长变量,用于存储和计算游戏时间 - 启动计时:在每个难度模式的雷区生成完成后,调用
start_time = time(NULL);开始计时 - 结束计时并展示:在
boom()(失败)和win()(胜利)函数中,获取结束时间,用difftime()计算时间差,格式化后显示给玩家 - 补全缺失代码:完善了原代码中未完成的
print_minefield、guess等函数,确保代码可以完整编译运行
内容的提问来源于stack exchange,提问作者Jose Luis Mendoza
相关产品推荐
相关产品推荐

