Word Scramble++
A browser-based timed anagram game. Unscramble letters to form words from themed categories or a random pool, and compete for the high score. Visit /puzzles/wordscramble.
Architecture
The game is entirely client-side JavaScript. The server provides:
- The template (
templates/wordscramble.html) — page layout with controls (category, timer, game area), high score sidebar, and name submission modal. - The game script (
static/js/wordscramble.js) — ~560 lines handling word selection, letter scrambling, timer, scoring, streak tracking, hint system, and high score API integration. Keyboard shortcuts: Enter to submit, Tab to skip, Space for hint. - The game route (
src/routers/wordscramble.py) — serves the template. High score endpoints are shared with existing games viasrc/routers/highscores.pyandsrc/store.py.
The existing high score system is fully reused — no server-side changes were needed. Scores are stored per-category and per-timer combination under data/wordscramble_<category>_<timer>s/highscores.json (e.g. data/wordscramble_animals_60s/highscores.json).
Game Flow
- Player selects a Category (Animals, Countries, Programming, Space, Food, Sports, Music, Nature, Geography, Science, or Random).
- Player sets a Timer (30s / 60s / 90s / 120s) by clicking the button.
- Player clicks Start Game.
- A word is randomly picked from the category, scrambled, and displayed as letter tiles.
- The player types the answer and presses Enter (or clicks Submit).
- Correct: points are awarded and the next word appears after a 1.2s pause.
- Wrong: streak resets and the correct answer is shown before advancing.
- When the timer expires, the final score is checked against the high score leaderboard.
Scoring
| Factor | Formula |
|---|---|
| Base points | word.length × 10 |
| Streak multiplier | min(streak, 5) — consecutive correct answers multiply points |
| Hint penalty | ÷ 2 (rounded down) — using a hint halves the points for that word |
| Skip penalty | −10 points per skip |
The feedback after each correct answer shows the full breakdown, e.g.:
- Correct! DOG = 30 (base) × 3 (streak) = 90 pts
- Correct! PYTHON = 60 (base) ÷ 2 (hint) = 30 pts
Controls
| Key | Action |
|---|---|
| Enter | Submit answer |
| Tab | Skip word (−10 pts) |
| Space | Hint (corrects one letter, halves points) |
High Scores
When the timer ends, the game checks GET /api/highscores/check?game=wordscramble_<category>_<timer>s&score=N. If the score qualifies for the top 10, a modal appears with a 10-second countdown to submit a name. The leaderboard is displayed in the sidebar and refreshes after each submission. Each category and timer setting has its own independent leaderboard. A score of 0 is never considered a high score. All backed by the generic src/routers/highscores.py API and src/store.py store.
Word Categories
| Category | Word count |
|---|---|
| Animals | ~60 |
| Countries | 50 |
| Programming | 50 |
| Space | 41 |
| Food | 52 |
| Sports | 30 |
| Music | 30 |
| Nature | 30 |
| Geography | 30 |
| Science | 30 |
| Random | ~132K (via data/words/english.txt) |
The Random category fetches 50 words from /api/wordsearch/random-words?count=50 on each game start.
Files
| File | Role |
|---|---|
templates/wordscramble.html |
Game template (layout, controls, high score sidebar, modals) |
static/js/wordscramble.js |
Game engine (word selection, scramble, timer, scoring, high scores) |
static/js/wordsearch.js |
Shared WORD_LISTS and random-words API (reused) |
src/routers/wordscramble.py |
GET /puzzles/wordscramble |
src/routers/highscores.py |
Generic high score API (shared with other games) |
src/store.py |
Generic high score data store (shared) |
data/words/english.txt |
Word pool for Random mode |
tests/test_routes.py |
Route tests for puzzle page rendering |