FIFTEEN QUESTIONS
September 4, 1998. ITV broadcast the first episode of Who Wants to Be a Millionaire?[1], a quiz show created by David Briggs, Steven Knight, and Mike Whitehill.

The format was built around a single escalating structure: fifteen questions, each harder than the last, a prize ladder from £100 to £1,000,000, two safe levels, and three lifelines — each usable once. Answer wrong and you fall to the last safe level you passed. Answer wrong before question five and you leave with nothing.
By 2000, Eidos Interactive had published Who Wants to Be a Millionaire?[2] for PC. It reconstructed the show's visual language for a home monitor: the prize ladder with the current level highlighted, the question and four lettered options, the audience percentage bar, the phone-a-friend reveal, a win screen that looked nothing like a game over.






Your version has to render all of it too. Not with a GPU, not with a
2D engine — with the same mechanism every terminal program uses.
Characters written to a display device. A function that formats them
and calls write().
You built that function in
c02/02.
Chapter c03 added the input side:
tci_getline reads a file one line at a time and tciu_split parses
each line into fields. The prize ladder, the question block, the
audience bar chart, the win screen — every visible element of the game
is a tci_printf call. The file descriptor is your terminal.
The implementation pages build the game one layer at a time: the data structures, question loading, the display functions, the game loop, and random selection from a larger question bank. Start at Setup.
The Rendering Question
Before I touched an editor, I drew a diagram — states, transitions, terminal nodes. That planning session is the first implementation page: I drew the flow, read the nodes, and let the data structures fall out of the reading.
The more interesting question comes after: what renders it?
tci_printf renders it. Every element of the game's visual output —
the prize ladder highlighted in yellow, the four lettered options, the
audience bar chart, the win screen — is a tci_printf call. No curses
library, no SDL, no special terminal toolkit. The function built in
c02 is the rendering
engine. The file descriptor happens to be a terminal.
This is not a trick. tci_printf writes characters to a file
descriptor. A terminal interprets certain character sequences as
formatting instructions. Combining them intentionally — \033[33m
before the current prize level, \033[0m after — is exactly what
every terminal UI library does underneath. You are seeing the
mechanism directly.
The Display
tci_printf is the rendering engine. The entire game UI is
tci_printf calls — ANSI escape codes for colour, nothing else.
Three sequences matter:
| Purpose | Sequence |
|---|---|
| Yellow (current level) | \033[33m |
| Green (safe level marker) | \033[32m |
| Reset | \033[0m |
The prize ladder renders from top (level 15) to bottom (level 1),
highlighting the current level in yellow and marking safe levels
in green. The question block shows whichever options survive a 50:50
lifeline. The audience display generates fake percentages weighted
toward the correct answer using rand().
Input
Two mechanisms, used for different purposes:
read(0, &c, 1) reads one byte from stdin — a single keypress
followed by Enter. The newline must be consumed with a second read.
This handles single-character choices: A, B, C, D for answers;
1, 2, 3 for lifelines; W for walk away.
tci_getline(0) handles multi-character input — if the game ever
prompts for a filename interactively.
The design decision is explicit in the code. Mixing buffered and unbuffered reads on the same file descriptor produces unpredictable results. Pick one mechanism per input type and stay consistent.
The Project
Build the complete terminal game. Source is split across four files:
| File | Contents |
|---|---|
main.c | argument check, load, shuffle, game loop, free |
load.c | load_questions(), free_questions() |
display.c | display_ladder(), display_question(), display_audience() |
game.c | game_loop(), read_input(), handle_lifeline() |
The game takes the question file as argv[1]:
./game questions.txtRules:
- 15 questions per game, drawn from a larger bank by random selection
- Safe levels at Q5 (£1,000) and Q10 (£32,000): a wrong answer drops the player to the last safe level reached; wrong before Q5 means £0
- Three lifelines — 50:50, Phone-a-Friend, Ask the Audience — each usable once
- Walk away at any point before answering; keep the current banked prize
- Win screen on Q15 correct
The Tester
The companion repo contains test.sh. Clone it once, copy test.sh
into your working directory, and run it:
git clone https://github.com/thecodingidiot-com/g01a-the-developer.git
cp g01a-the-developer/test.sh ~/g01a-practice/
bash test.shThe tester pipes scripted input into the binary and compares output to expected results. It covers a correct run through all 15 questions, an early loss, a 50:50 lifeline, and a walk away.
The Companion Repo
The reference solution is at
github.com/thecodingidiot-com/g01a-the-developer.
The solution/ directory contains main.c, load.c, display.c,
game.c, a Makefile, questions.txt (30 questions), and test.sh.