A Frontend Mentor challenge built with no framework, no dependencies, and no build step — one index.html, one styles.css, one script.js. Pick your mark, play the CPU or a friend on the same device, and the board keeps a running tally of wins and ties until you quit.
Features
- Two modes — solo against the CPU, or local two-player on one device
- Choose X or O before the match starts; X always moves first
- Turn tracker showing whose move it is
- Running score for X, O, and ties, carried across rounds
- Round-end overlay with mode-aware messaging — “You won!” and “Oh no, you lost…” against the CPU, “Player 1 wins!” in two-player
- Restart confirmation, so the score isn’t wiped by a misclick
- Board squares are real
<button>elements, so the whole game is keyboard-playable - Hover styling gated behind
(hover: hover)— no sticky hover states on touch devices - Self-hosted Outfit variable font and a mobile breakpoint at 30rem
Implementation note
Win detection never re-scans the board. Each player starts with their own copy of the eight winning combinations, and claiming a square removes that number from every combination that player holds. When any one of them empties out, that player has won — reducing the check to a filter over a few short arrays.
The CPU picks a random open square rather than playing optimally. The challenge scoped the work around UI state and game flow, not the opponent, so a minimax player would be the obvious next addition.
