C++ Chess Clock Project
Two countdown clocks, one button — flag fall decides the game.
What you will build
Each player has a countdown; making a move stops your clock and starts your opponent's, and running out of time loses the game. It's a study in precise real-time state: whose clock is running, exactly how much remains, and what happens at zero.
What you will learn
- Countdown arithmetic with steady_clock
- State machines (white running / black running / finished)
- Increment (Fischer) time controls
- Millisecond-accurate display updates
Feature checklist
- Two clocks: White and Black
- Press to switch after each move
- Flag fall: game ends, winner declared
- Choose time controls (e.g. 5, 10, 15 minutes)
- Optional increment added per move
- Move counter for both players
Starter code
#include <iostream>
#include <chrono>
using Clock = std::chrono::steady_clock;
using Ms = std::chrono::milliseconds;
struct ChessClock {
Ms left[2];
int turn = 0; // 0 = White, 1 = Black
Ms increment{0};
Clock::time_point stamp;
bool over = false;
ChessClock(Ms start, Ms inc) : increment(inc) {
left[0] = left[1] = start;
stamp = Clock::now();
}
// Charge the running player for time since last press.
void tick() {
auto now = Clock::now();
left[turn] -= std::chrono::duration_cast<Ms>(now - stamp);
stamp = now;
if (left[turn] <= Ms{0}) { left[turn] = Ms{0}; over = true; }
}
void press() { // current player ends their move
tick();
if (over) return;
left[turn] += increment;
turn = 1 - turn;
stamp = Clock::now();
}
};Full walkthrough
Step 1: Model the clock as a small class
class ChessClock holds: two remaining times (as chrono durations or milliseconds), whose turn is running, a move counter per player, an optional increment, and the start timestamp of the current turn. The key insight: only ONE clock runs at a time, and it switches on press — the class exists to make 'the running side loses time' impossible to get wrong.
Step 2: tick(): charge time to the side to move
tick() computes now - turnStart, subtracts it from the running player's remaining time, and resets turnStart to now. Called a few times a second by the main loop, it keeps the display fresh without ever storing a 'current displayed time' that could drift — derived state once more.
Step 3: Detect flag fall the moment it happens
If the running player's remaining time hits zero inside tick(), the game is over: that player loses on time, the other is declared the winner. Check on EVERY tick, not on press — a player whose flag falls while thinking loses even if nobody touches the clock. Freeze both clocks at that moment.
Step 4: press(): switch sides, add increment, count the move
On a press (Enter key in the console version): settle the presser's time via tick(), add the increment to the PRESSER's remaining time if configured, increment their move count, flip the running side, and reset turnStart. Order is crucial — settle first, then bonus, then switch; adding increment to the wrong player is the classic implementation slip.
Step 5: Choose the time control at startup
Prompt for base minutes (5, 10, 15 or custom) and increment seconds (0 for none). Both clocks start equal. Starting White's clock immediately on game start matches real tournament behaviour — White's time runs while they think about move one.
Step 6: Draw a clear two-clock display
Each redraw shows both remaining times as MM:SS (tenths under a minute, if you want the drama), a marker on the side whose clock is running, and the move counts. Redraw in place with \r or a clear-screen code like the clock and snake projects — the information is the state, formatted.
Step 7: Test with a blitz game
Set 1 minute per side for testing. Press alternately and watch only the mover's clock fall; sit on one side for the full minute and confirm the flag falls, the winner is announced, and further presses do nothing. Then a game with a 2-second increment: a press must visibly refund time to the player who just moved.
Common mistakes
- Subtracting time from BOTH players or from the player who is NOT to move — the single sign error this entire class exists to prevent.
- Checking flag fall only on press, letting a player whose time expired keep 'playing' until someone notices.
- Adding the increment to the incoming player instead of the player who just completed a move.
Compile and run
g++ -std=c++17 -o chess_clock chess_clock.cppSample run
$ ./chess_clock
Time control — minutes per side:
> 5
Increment seconds per move (0 = none):
> 2
White 5:00 · Black 5:00 — White to move, White's clock runs
(White thinks for 8 seconds, then presses — Enter)
>
White 4:54 (+2s increment) · Black 5:00 — Black to move · moves: W1 B0
(Black replies quickly, presses)
>
White 4:54 · Black 4:57 (+2s increment) — White to move · moves: W1 B1
(...the game continues, clocks only ever fall for the side to move...)
White 0:41 · Black 1:12 — White to move · moves: W38 B38
(White's time runs out while thinking)
FLAG FALL — White's clock hit 0:00. Black wins on time!Try it in your browser
No browser demo is included for this project. Build the C++ version below — that is the real program.