Hangman is the game everyone has played on the back of a notebook, and it looks almost too simple to be interesting to build. But when I sat down to write it in vanilla JavaScript, it turned out to be one of the cleanest little lessons in derived state I have come across. The whole thing runs on three variables and a drawing that can never disagree with the score. Here is how it works.
The entire game is three pieces of state
A round of Hangman is defined by remarkably little: the secret word, the set of letters you have guessed, and a single counter for wrong guesses.
let secret; // the chosen { word, hint }
let guessed; // a Set of letters tried
let wrong; // wrong guesses so far
const MAX_WRONG = 6; // six mistakes = full figure
Everything the player sees — the blanks, the coloured keyboard, the little stick figure — is derived from those three. Nothing about the display is stored separately, so nothing can ever fall out of sync.
The reveal falls out of set membership
The row of blanks is the part beginners tend to over-engineer, tracking which positions are open and mutating them as letters come in. You do not need any of that. The masked word is a pure read over the secret:
secret.word.split("").map(ch => guessed.has(ch) ? ch : "_");
Walk the word, and for each character ask the guessed Set one question — "have we seen this?" That is the whole reveal. On a loss you relax the test to guessed.has(ch) || state === "lost" so the missed letters show too, painted red.
Using a Set rather than an array is a small decision that pays off three times: it dedupes automatically (guessing "E" twice is a harmless no-op), it answers membership in one call, and it makes that reveal a one-liner. Crucially, both good and bad guesses live in the same set — whether a letter counts as wrong is never recorded, it is decided later by asking the word itself.
One counter is the entire risk model
When a letter is added, the word is the sole judge:
guessed.add(letter);
if (!secret.word.includes(letter)) wrong++; // spend a life
That single branch is the whole difficulty of the game. There is no clock and no penalty for thinking — Hangman is pure deduction. Winning is just every letter of the secret being in the set; losing is the counter hitting six. And notice there is no separate lives variable: lives is simply MAX_WRONG - wrong, computed only when it needs to be shown.
The drawing is a function of that one number
This is my favourite part. The gallows scene is drawn from scratch every render, and each body part is gated behind a threshold on wrong:
drawGallows(); // always present
if (wrong >= 1) circle(190, 92, 22); // head
if (wrong >= 2) line(190,114, 190,190); // body
if (wrong >= 3) line(190,135, 160,165); // left arm
if (wrong >= 4) line(190,135, 220,165); // right arm
if (wrong >= 5) line(190,190, 165,235); // left leg
if (wrong >= 6) line(190,190, 215,235); // right leg
Because the picture reads only from wrong, the figure is always exactly as complete as the number of mistakes. There is no incremental "add one limb per event" logic to get wrong — redrawing from the counter every time is simpler and impossible to desync.
Two inputs, one door
A letter can arrive from a click on an on-screen key or a keypress on the physical keyboard, but both funnel into the same guess() function. The input layer only normalises the letter to uppercase and hands it over; the deduping, the life-spending, and the win/lose check all happen in one place. That is the payoff of keeping the rules together — the two input paths can never drift apart in behaviour.
The keyboard colours itself the same derived way: after a key is used it is green if the letter is in the word and grey if it was wasted, computed from state on every render rather than toggled by hand.
What it teaches
Hangman is about ninety lines, but it is a tidy demonstration of a principle that matters everywhere: keep the smallest possible source of truth and derive everything else. Three variables in, and the blanks, the score, the keyboard colours, and the drawing all fall out as pure functions of them. Get that habit and far bigger UIs stop drifting out of sync.
Play a few rounds, watch the figure build one mistake at a time, and try typing straight on your keyboard:
https://dev48v.infy.uk/game/day34-hangman.html
Top comments (0)