180 lines
7.4 KiB
Markdown
180 lines
7.4 KiB
Markdown
# Tic-Tac-Toe vs CPU — Implementation Plan
|
||
|
||
A polished, mobile-friendly tic-tac-toe game (X vs O) playable in the browser against a
|
||
random-move CPU opponent. Pure HTML/CSS/JS — no build step, no dependencies.
|
||
Open `index.html` directly in a browser to play.
|
||
|
||
## 1. Project Structure
|
||
|
||
```
|
||
game1/
|
||
├── index.html # Page structure (board, scoreboard, status, overlay)
|
||
├── style.css # All styling: glassmorphism dark theme, animations
|
||
├── game.js # Game logic: state, win detection, CPU, scoring, FX
|
||
└── docs/
|
||
├── PLAN.md # This document
|
||
└── mockup.svg # UI mockup (open in a browser to view)
|
||
```
|
||
|
||
## 2. Visual Design
|
||
|
||
Research (Dribbble/Figma/CodePen examples) shows the current popular style for
|
||
tic-tac-toe: **dark glassmorphism with neon accents**, frosted panels, soft glows,
|
||
and confetti celebrations on wins.
|
||
|
||
- **Background**: deep gradient (dark navy → violet) with two soft blurred
|
||
colored blobs (cyan + magenta) for depth.
|
||
- **Panels**: frosted glass cards — `background: rgba(255,255,255,0.06)`,
|
||
`backdrop-filter: blur(14px)`, 1px translucent white border, soft shadow.
|
||
(Blur kept modest for mobile performance.)
|
||
- **Colors**:
|
||
- X (player) — neon cyan `#22d3ee`
|
||
- O (CPU) — neon pink/magenta `#f472b6`
|
||
- Text: white / muted gray
|
||
- **Typography**: system font stack, bold title, tabular numerals for scores.
|
||
- **Mockup**: see `docs/mockup.svg` (open in a browser) for the envisioned
|
||
look — dark glass panels, neon cyan X / pink O with glow, gradient title.
|
||
- **Layout (top → bottom)**:
|
||
1. Title: "Tic-Tac-Toe" with subtle gradient text
|
||
2. Scoreboard: three glass chips — You (X) · CPU (O) · Draws
|
||
3. Status bar: "Your turn" / "CPU is thinking…" / result text
|
||
4. Board: 3×3 grid of glass cells
|
||
5. Buttons: "New Game" (primary) and "Reset Scores" (ghost)
|
||
|
||
## 3. Mobile-Friendliness
|
||
|
||
- `<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">`
|
||
- Board width: `min(88vw, 340px)`; cells are large touch targets (≥ 72px on phones).
|
||
- `touch-action: manipulation` on buttons/cells to kill double-tap zoom delay.
|
||
- No hover-only interaction: hover glow is a desktop enhancement only; taps work
|
||
everywhere. Use `:active` press feedback.
|
||
- Layout uses flex column, centered, max-width 420px — looks like a mobile app
|
||
on desktop too.
|
||
- `user-select: none` on the board to avoid text selection while tapping fast.
|
||
- Test: 360px-wide viewport, fast repeated taps, orientation change.
|
||
|
||
## 4. Game Rules
|
||
|
||
- Standard 3×3 tic-tac-toe. Player is **X**, CPU is **O**.
|
||
- Player always starts the round with X (keeps it simple and predictable).
|
||
- Click/tap an empty cell to place your mark.
|
||
- CPU responds on a random empty cell after a **600 ms "thinking" delay**
|
||
(feels natural, shows the "CPU is thinking…" status).
|
||
- Win: 3 in a row (8 winning lines). Draw: board full with no winner.
|
||
- After a round ends, a result overlay appears; "Play Again" starts a fresh round
|
||
(board clears, scores persist).
|
||
|
||
## 5. Scoring
|
||
|
||
- Track **You**, **CPU**, and **Draws** across rounds.
|
||
- Persisted in `localStorage` (key `ttt-scores`) so scores survive reloads.
|
||
- "Reset Scores" button zeroes them (with a short confirm-less toast feedback).
|
||
- Score chips animate a quick pop when the value changes.
|
||
|
||
## 6. Game-Over Reactions
|
||
|
||
- **Winning line**: an SVG line is drawn across the three winning cells with a
|
||
stroke-dashoffset animation (draws itself in ~400 ms).
|
||
- **Result overlay**: frosted glass modal fades/scales in with:
|
||
- Win → "You Win! 🎉" + confetti burst (DOM particles, ~40 pieces, random
|
||
colors/velocities, fall + fade over ~1.8 s, then removed).
|
||
- Loss → "CPU Wins" + a subtle red-tinted shake of the board.
|
||
- Draw → "It's a Draw" + neutral pulse.
|
||
- Overlay has a single big "Play Again" button.
|
||
- Small micro-feedback during play:
|
||
- Marks pop in with a scale+fade animation (150 ms).
|
||
- Empty cells glow faintly on hover (desktop) and brighten on `:active`.
|
||
- Status bar text cross-fades on turn change; "CPU is thinking…" pulses.
|
||
|
||
## 7. JavaScript Architecture (game.js)
|
||
|
||
Single file, plain functions + one state object:
|
||
|
||
```
|
||
state = {
|
||
board: Array(9).fill(null), // null | 'X' | 'O'
|
||
turn: 'X', // 'X' = player, 'O' = CPU
|
||
gameOver: false,
|
||
scores: { you: 0, cpu: 0, draws: 0 }
|
||
}
|
||
```
|
||
|
||
Modules (sections in the file):
|
||
|
||
1. **DOM refs** — cells, status, score chips, overlay, buttons.
|
||
2. **Win detection** — `WIN_LINES` = 8 combos; `checkWinner(board)` returns
|
||
`{winner, line}` or `{winner: 'draw'}` or `null`.
|
||
3. **Player move** — `onCellTap(i)`: ignore if occupied/game over/CPU turn;
|
||
place X, render, check end; else schedule CPU.
|
||
4. **CPU move** — `cpuMove()`: after 600 ms, pick a random empty index,
|
||
place O, render, check end.
|
||
5. **Render** — `renderMark(i, mark)` (pop animation), `renderStatus()`,
|
||
`renderScores()`, `drawWinLine(line)` (SVG overlay on the board).
|
||
6. **Round end** — `endRound(result)`: update + persist scores, show overlay
|
||
with appropriate FX (confetti / shake / pulse).
|
||
7. **Confetti** — `burstConfetti()`: create N absolutely-positioned divs with
|
||
random transforms, animate via CSS transitions, remove after finish.
|
||
8. **Reset** — `newRound()` (clear board, player first), `resetScores()`.
|
||
9. **Init** — load scores from localStorage, build board DOM, bind events.
|
||
|
||
## 8. Implementation Steps
|
||
|
||
1. `index.html` — semantic structure, viewport meta, SVG defs for win line.
|
||
2. `style.css` — theme tokens (CSS custom properties), background, glass panels,
|
||
board grid, marks (X/O drawn with CSS or inline SVG for crispness),
|
||
animations (pop, pulse, shake, confetti fall), overlay, responsive tweaks.
|
||
3. `game.js` — implement sections 1–9 above.
|
||
4. Manual test pass:
|
||
- Win all 8 line types (play through scenarios).
|
||
- Draw scenario.
|
||
- Rapid tapping (no double placement, no CPU overlap).
|
||
- Scores persist across reload; reset works.
|
||
- 360px viewport: no overflow, big touch targets, no zoom on tap.
|
||
5. Polish: check animation smoothness on a mid-range phone if available.
|
||
|
||
## 9. Hosting the App
|
||
|
||
The app is three static files, so any static file server works. The goal is a
|
||
one-line start, no config files, no build step.
|
||
|
||
**Primary option — Python (already installed, zero setup):**
|
||
|
||
```bash
|
||
python3 -m http.server 8000
|
||
```
|
||
|
||
Run from the `game1/` folder. It binds to all network interfaces by default,
|
||
so the game is immediately reachable:
|
||
|
||
- **Same machine**: http://localhost:8000
|
||
- **Same network (LAN)**: http://\<machine-ip\>:8000
|
||
(find the IP with `hostname -I` or `ip addr`)
|
||
- **Internet**: forward port 8000 in the router/firewall, or put the machine
|
||
behind a reverse proxy. For public exposure, prefer caddy (see below) and
|
||
keep the raw port closed otherwise.
|
||
|
||
**Alternative — Caddy (nicest for internet exposure, auto-TLS with a domain):**
|
||
|
||
```bash
|
||
caddy file-server --root . --listen :8000
|
||
```
|
||
|
||
**Alternative — Node (if Python is unavailable):**
|
||
|
||
```bash
|
||
npx serve -l 8000
|
||
```
|
||
|
||
Notes:
|
||
|
||
- These dev servers are fine for LAN / home use. For a public internet
|
||
endpoint, use caddy behind a domain (it handles TLS automatically) and do
|
||
not expose the raw port to the internet with a bare dev server.
|
||
- No deploy step: the folder *is* the app — copy it anywhere and serve it.
|
||
|
||
## 10. Non-Goals (kept simple on purpose)
|
||
|
||
- No minimax / unbeatable AI (CPU is random, as requested).
|
||
- No sound effects, no multi-language support, no user-vs-user mode.
|
||
- No framework, no bundler — the game is three files.
|