Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .Jules/palette.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,7 @@
## 2026-02-13 - Tactile Feedback in CLI
**Learning:** In terminal-based games, users expect immediate visual feedback for their actions. Relying on a periodic "tick" to update the UI creates a laggy feel. Using `poll()` with a dynamic timeout allows the application to remain idle yet wake up instantly to process and render user input.
**Action:** Always trigger a UI refresh immediately after processing user input in CLI applications, and use efficient waiting mechanisms (like `poll`) that can be interrupted by input.

## 2026-05-23 - Ensuring a Fair Start in CLI Games
**Learning:** Users often spam keys during a game's countdown phase in anticipation. If these inputs are buffered and processed immediately when the game starts, it can lead to an unfair advantage or accidental actions. Using `tcflush(STDIN_FILENO, TCIFLUSH)` after the countdown ensures the game starts with a clean slate.
**Action:** Always clear the input buffer with `tcflush` after a blocking countdown or transition period in interactive CLI applications to ensure intent-based interaction.
27 changes: 23 additions & 4 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,29 @@ int main() {
<< "Controls:\n " << CLR_CTRL << "[h]" << CLR_RESET << " Toggle Hard Mode (10x Speed!)\n "
<< CLR_CTRL << "[q]" << CLR_RESET << " Quit Game\n " << CLR_CTRL << "[Any key]" << CLR_RESET << " Click!\n\n";

std::cout << "Press any key to start... " << std::flush;
struct pollfd fds[1] = {{STDIN_FILENO, POLLIN, 0}};
if (poll(fds, 1, -1) > 0) {
if (read(STDIN_FILENO, &input, 1) > 0 && input == 'q') {
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
return 0;
}
}

for (int i = 3; i > 0; --i) {
std::cout << "\rStarting in " << i << "... " << std::flush;
if (poll(fds, 1, 1000) > 0) {
if (read(STDIN_FILENO, &input, 1) > 0 && input == 'q') {
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
std::cout << "\n";
return 0;
}
}
}
std::cout << "\rGO! \n" << std::flush;
std::this_thread::sleep_for(std::chrono::milliseconds(200));
tcflush(STDIN_FILENO, TCIFLUSH);

auto last_tick = std::chrono::steady_clock::now();
bool updateUI = true;
while (true) {
Expand All @@ -76,12 +98,9 @@ int main() {
}

if (updateUI) {
std::cout << GREEN << "Score: " << score << RESET
<< (hardMode ? RED " [FAST] " : BLUE " [NORMAL] ") << RESET
<< " \r" << std::flush;
std::cout << "\r" << CLR_SCORE << "Score: " << score << CLR_RESET << " "
<< (hardMode ? CLR_HARD "[HARD MODE]" : CLR_NORM "[NORMAL MODE]")
<< " " << std::flush;
<< " " << std::flush;
updateUI = false;
}
}
Expand Down