WOPR is a mobile-first React app hosting five turn-based strategy games on a single menu, themed around the 1983 film WarGames. The games are Tic-Tac-Toe, Connect Four, Dots and Boxes, Go, and a full Global Thermonuclear War simulation with nuclear-triad units, six CPU personalities, and a five-phase round system. Live at wopr.awrylabs.com, source at github.com/rhoekstr/wopr.
Live · Play now
WOPR
Five turn-based strategy games on a single mobile-first menu, themed
around the 1983 film WarGames. Classic abstracts — Tic-Tac-Toe,
Connect Four, Dots & Boxes, Go — sit alongside a full Global
Thermonuclear War simulator with a nuclear triad, interceptor doctrine,
six CPU personalities, and a DEFCON ladder. Pure React, no analytics,
no accounts, deliberately written as a single ~2,700-line file.
At a glance
Games
5
Tic-Tac-Toe · Connect Four · Dots & Boxes · Go · Global Thermonuclear War, all behind one menu.
Source size
~2.7K
Lines in src/games.jsx. Deliberately one file — easy to grep, easy to ship.
Non-React deps
0
No Tailwind, no game library, no animation library. Inline styles, plain SVG.
Tracking
0
No accounts, no analytics, no localStorage. Each visit is fresh.
The five games
Each game has its own background, accent color, and AI ladder. They
share a small set of UI primitives — the Back button, mode toggle,
difficulty toggle — so the menu feels like one app rather than five.
3 × 3
Tic-Tac-Toe
Standard 3×3 with three modes (vs CPU, pass-and-play, CPU vs CPU)
and four AI levels topping out at full minimax — Impossible never
loses.
7 × 6
Connect Four
Animated piece drop with quadratic easing. Alpha-beta search with
center-first move ordering, scaling from depth-2 (Easy) to depth-8
(Impossible).
Lucas, 1889
Dots & Boxes
Three board sizes (4×4 / 6×6 / 8×8). Iterative-deepening alpha-beta
with a chain-aware heuristic — Hard and Impossible plan inside a
3–6 second time budget.
5/7/9
Go (囲棋)
Captures, suicide rule, ko via board-position hashing, two-pass
end. Chinese-rules scoring with 6.5 komi. AI prefers captures and
atari escapes, then heuristic-ranked safe moves.
The big one
Global Thermonuclear War
Real Russia and USA SVG outlines. Nuclear triad: silos, SSBNs,
bombers — each with different rules for targetability, intercept,
and per-round limits. Six CPU personalities (firstStrike,
populationStrike, decapitation, defenseHeavy, deescalatory,
erratic), five-phase rounds, and four end conditions including
DEFCON-2 de-escalation peace.
Inside Global Thermonuclear War
Most mechanically rich of the five. Models the nuclear triad with
strategic AI personalities, a phase machine, and — crucially — a
peaceful end condition.
The triad
Each side has 8 silos (2 missiles, targetable, interceptable),
2 SSBNs (2 missiles, hidden, interceptable), and 3 bombers (1
sortie each, hidden, cannot be intercepted). 23 launches max
per side if everything fires.
Phase machine
Each round runs us_launch → ru_launch → us_intercept
→ ru_intercept → resolve. Resolution preempts struck
silos before they can fire, rolls intercepts and bomber AAA,
then applies casualties and adjusts DEFCON.
Six personalities
CPU sides are assigned one personality per game — from
firstStrike (95% launch rate, silos first) to
deescalatory (10% launch rate, prefers low-population
targets when it must fire).
DEFCON ladder
Inverted from real-world DEFCON for game clarity. 3 is peace,
4–5 is escalation (rises with launches), 2 is the de-escalation
floor. Reaching DEFCON 2 with no launches that round ends the
game in negotiated peace.
A strange game
From the in-tree CPU-vs-CPU simulator at current settings: ~43%
conclusive endings, ~45% negotiated peace via DEFCON-2 de-escalation,
~13% silo stalemate. Average game runs four rounds. The most common
outcome is "the only winning move is not to play" — by design.
Single-file by choice
src/games.jsx contains every game's logic and UI in one
~2,700-line module. That sounds heretical, but for a small static SPA
it's the right call: one file to grep, one bundle to ship, no
cross-file plumbing for what is fundamentally five small pieces of
state and five components.
React 18
Hooks only
useState, useEffect, useRef. No reducers, no context, no third-party state library. GameRoom keeps a single screen string and renders the matching component.
Vite 5
Build pipeline
Vite + @vitejs/plugin-react, plain JSX, no TypeScript. npm run build writes dist/; the deploy workflow ships it to GitHub Pages on every push to main.
Inline styles
No CSS toolchain
Every component sets its own styles inline. No Tailwind, no CSS modules, no styled-components. SVG for game boards, HTML for chrome. Each game has its own background-color and accent so identity reads at a glance.
Mobile-first
420px column
Every game's root caps width at 420px and centers, so on desktop you get a phone-sized column on a black field. The page looks identical full-screen on a phone.
Run it locally
Clone & serve
git clone https://github.com/rhoekstr/wopr.git
cd wopr
npm install
npm run dev # localhost:5173
npm run build # writes dist/
npm run preview # serves dist/ locally
Live
wopr.awrylabs.com —
five games, free, no sign-in, mobile-friendly, deployed via GitHub
Pages on every push to main.
Source
github.com/rhoekstr/wopr —
Apache-friendly fork-and-tinker target. Reference docs live in the
repo's REFERENCE.md.