如何在ANSI C中实现计时器?适配Boggle游戏1分钟倒计时场景
Hey there! For your Boggle game's 1-minute countdown that needs to update live within your main loop, here's a practical implementation using standard C tools, plus a fix for the input blocking problem that would otherwise freeze the timer display.
Core Timing Logic (Using time.h)
The foundation is tracking the start time and calculating how much time remains on each loop iteration. We'll use time() from the standard time.h library, which gives us a Unix timestamp (seconds since epoch) to work with:
#include <stdio.h> #include <time.h> int main() { time_t game_start = time(NULL); time_t game_end = game_start + 60; // Set 1-minute limit int game_running = 1; int player_score = 0; while (game_running) { // Calculate remaining time time_t now = time(NULL); int time_left = game_end - now; // End game if time's up if (time_left <= 0) { printf("\nTime's up! Game over.\n"); break; } // Clear screen (optional but cleaner: use "cls" for Windows, "clear" for Unix) // system("clear"); // Draw your board, score, and live timer printf("=== Boggle Board ===\n"); printf("X Y Z Q\nA B C D\nE F G H\nI J K L\n"); // Replace with your actual board render printf("Score: %d | Time Remaining: %d seconds\n", player_score, time_left); printf("Enter a word: "); // ⚠️ Problem: Regular scanf() blocks here, so timer won't update until input is entered // We'll fix this below with non-blocking input } return 0; }
Fixing Input Blocking: Non-Blocking Input
The big issue with regular scanf() is that it pauses the program until the user types something. To keep the timer ticking while waiting for input, we need non-blocking input handling—this lets the program check for key presses without stopping the loop.
Unix/Linux Implementation
Use fcntl() to tweak standard input into non-blocking mode:
#include <stdio.h> #include <time.h> #include <fcntl.h> #include <unistd.h> #include <string.h> int main() { time_t game_start = time(NULL); time_t game_end = game_start + 60; int game_running = 1; int player_score = 0; char input_word[20]; int input_pos = 0; // Set stdin to non-blocking mode int stdin_flags = fcntl(STDIN_FILENO, F_GETFL, 0); fcntl(STDIN_FILENO, F_SETFL, stdin_flags | O_NONBLOCK); while (game_running) { time_t now = time(NULL); int time_left = game_end - now; if (time_left <= 0) { printf("\nTime's up! Final score: %d\n", player_score); break; } // Clear screen for clean updates system("clear"); // Render game state printf("=== Boggle Board ===\n"); printf("X Y Z Q\nA B C D\nE F G H\nI J K L\n"); printf("Score: %d | Time Remaining: %d seconds\n", player_score, time_left); printf("Enter a word: %s_\r", input_word); // \r moves cursor back to start of line fflush(stdout); // Force output to update immediately // Check for key presses char key; ssize_t bytes_read = read(STDIN_FILENO, &key, 1); if (bytes_read > 0) { if (key == '\n') { // User pressed enter—process the word input_word[input_pos] = '\0'; printf("\nYou submitted: %s\n", input_word); // Call your word validation function here, update score if valid // if (is_valid_word(input_word)) player_score += calculate_points(input_word); input_pos = 0; memset(input_word, 0, sizeof(input_word)); sleep(1); // Give user a moment to see their submission } else if (key == '\b' && input_pos > 0) { // Handle backspace to delete characters input_pos--; input_word[input_pos] = '\0'; } else if (input_pos < sizeof(input_word) - 1) { // Add valid character to input input_word[input_pos++] = key; } } // Reduce CPU usage by pausing briefly usleep(100000); // 100ms pause } // Reset stdin to normal blocking mode fcntl(STDIN_FILENO, F_SETFL, stdin_flags); return 0; }
Windows Implementation
Windows uses _kbhit() and _getch() from conio.h to detect key presses without blocking:
#include <stdio.h> #include <time.h> #include <conio.h> #include <string.h> #include <windows.h> int main() { time_t game_start = time(NULL); time_t game_end = game_start + 60; int game_running = 1; int player_score = 0; char input_word[20]; int input_pos = 0; while (game_running) { time_t now = time(NULL); int time_left = game_end - now; if (time_left <= 0) { printf("\nTime's up! Final score: %d\n", player_score); break; } // Clear screen system("cls"); // Render game state printf("=== Boggle Board ===\n"); printf("X Y Z Q\nA B C D\nE F G H\nI J K L\n"); printf("Score: %d | Time Remaining: %d seconds\n", player_score, time_left); printf("Enter a word: %s_\r", input_word); fflush(stdout); // Check for key presses if (_kbhit()) { char key = _getch(); if (key == '\r') { // Enter key on Windows input_word[input_pos] = '\0'; printf("\nYou submitted: %s\n", input_word); // Validate word and update score here input_pos = 0; memset(input_word, 0, sizeof(input_word)); Sleep(1000); } else if (key == '\b' && input_pos > 0) { // Handle backspace input_pos--; input_word[input_pos] = '\0'; } else if (input_pos < sizeof(input_word) - 1) { input_word[input_pos++] = key; } } // Reduce CPU usage Sleep(100); } return 0; }
Key Notes
- Time Precision: The
time()function works at the second level, which is perfect for a 1-minute Boggle timer. If you wanted millisecond-level precision, you could useclock_gettime()(Unix) orQueryPerformanceCounter()(Windows), but it's overkill here. - Output Flushing: Always use
fflush(stdout)after printing the timer—this ensures the display updates immediately instead of waiting for the buffer to fill. - Cross-Platform Support: If you need your code to work on both Unix and Windows, wrap the platform-specific parts in
#ifdefmacros (e.g.,#ifdef _WIN32for Windows code).
内容的提问来源于stack exchange,提问作者brann22

