| # Wrdler Specifications | |
| **Version:** 0.2.8 | |
| **Status:** Production Ready - Leaderboards & Settings Page Implemented | |
| **Last Updated:** 2025-12-09 | |
| ## Overview | |
| Wrdler is a Python/Streamlit vocabulary puzzle game based on BattleWords, but with key differences. The objective is to discover hidden words on a grid by making strategic guesses and using free letter reveals at the game start. | |
| **Current Status:** All 7 sprints complete, 100% tested, fully documented | |
| ## Key Differences from BattleWords | |
| - **Python project** (Streamlit, Python 3.12.8) | |
| - **8x6 grid** (instead of 12x12) | |
| - **One word per row** (instead of 6 words placed anywhere) | |
| - **Horizontal words only** (no vertical placement) | |
| - **No scope/radar visualization** | |
| - **2 free letter guesses at game start** (all instances of chosen letters are revealed) | |
| ## Game Board | |
| - 8 x 6 grid | |
| - Six hidden words: | |
| - One word per row (row 0-5) | |
| - **Word composition:** Exactly 2 four-letter words, 2 five-letter words, and 2 six-letter words | |
| - All placed horizontally (left-right) | |
| - No vertical placement | |
| - No diagonal placement | |
| - Words do not overlap | |
| - Entry point is `app.py` | |
| - **Supports Dockerfile-based deployment for Hugging Face Spaces and other container platforms** | |
| ## Gameplay (Core) | |
| - Players start by choosing 2 letters; all instances of those letters are revealed in the grid | |
| - Players click grid squares to reveal letters or empty spaces | |
| - Empty revealed squares are styled with CSS class `empty` | |
| - After any reveal, the app immediately reruns (`st.rerun`) to show the change | |
| - After revealing a letter, players may guess a word by entering it in a text box | |
| - Guess submission triggers an immediate rerun to reflect results | |
| - Only one guess per letter reveal; must uncover another letter before guessing again | |
| - In the default mode, a correct guess allows chaining an additional guess without another reveal | |
| - **The game ends when all six words are guessed or all word letters are revealed** | |
| ## Scoring | |
| - Each correct word guess awards points: | |
| - 1 point per letter in the word | |
| - Bonus points for each hidden letter at the time of guessing | |
| - Score tiers: | |
| - **Legendary:** 45+ points | |
| - **Fantastic:** 42-44 points | |
| - **Great:** 39-41 points | |
| - **Good:** 35-38 points | |
| - **Keep practicing:** <35 points | |
| - **Game over is triggered by either all words being guessed or all word letters being revealed** | |
| ## Core Rules (v0.0.2 - Implemented) | |
| - β 8x6 grid with one word per row | |
| - β Horizontal words only; no vertical placement | |
| - β No overlaps: words do not overlap or share letters | |
| - β No radar/scope visualization (removed in Sprint 3) | |
| - β 2 free letter guesses at game start (implemented in Sprint 4) | |
| - β Incorrect guess history with optional display | |
| - β 10 incorrect guess limit per game | |
| - β Two game modes: Classic (chain guesses) and Too Easy (single guess per reveal) | |
| ## Implemented Features (v0.2.4) | |
| ### Word List Management (v0.2.4) | |
| - β **Filter Wordlist:** Remove words found in `assets/filter.txt` from the selected word list | |
| - β **Sort Wordlist:** Sort words by length and alphabetically | |
| - β **Feedback:** Dialog showing count and list of removed words | |
| ### AI Word Generation (v0.1.0+) | |
| - β **Topic-Based Generation:** Create custom word lists for any theme using AI | |
| - β **Dual Generation Modes:** | |
| - HF Space API (primary): Uses Hugging Face Space when `USE_HF_WORDS=true` | |
| - Local transformers (fallback): Falls back to local models if HF unavailable | |
| - β **Intelligent Word Management:** | |
| - Smart detection separates existing dictionary words from new AI-generated words | |
| - Only saves new words to prevent duplicates in word files | |
| - Automatic retry mechanism (up to 3 attempts) if insufficient words generated | |
| - 1000-word file size limit prevents dictionary bloat | |
| - Auto-sorted by length then alphabetically | |
| - β **Guaranteed Distribution:** Ensures exactly 25 words each of lengths 4, 5, and 6 | |
| - β **Graceful Fallback:** Uses dictionary words if AI generation fails | |
| - β **Enhanced Logging:** Detailed pipeline visibility for debugging | |
| ### Challenge Mode | |
| - β **Game ID Sharing:** Each puzzle generates a shareable link with `?game_id=<sid>` to challenge others with the same word list | |
| - β **Remote Storage:** Game results and leaderboards stored in Hugging Face dataset repos | |
| - β **Leaderboards:** Multi-user leaderboards sorted by score (descending) then time (ascending) | |
| - β **Word List Difficulty:** Calculated and displayed for each challenge | |
| - β **Top 5 Display:** Leaderboard banner shows top 5 players | |
| - β **Optional Sharing:** "Show Challenge Share Links" toggle (default OFF) controls URL visibility | |
| ### Leaderboard System (v0.2.1) β IMPLEMENTED | |
| Wrdler features a comprehensive daily and weekly leaderboard system: | |
| **Core Features:** | |
| - **Daily Leaderboards:** Top 20 scores for each day (resets UTC midnight) | |
| - **Weekly Leaderboards:** Top 20 scores for each ISO week (resets Monday UTC 00:00) | |
| - **Settings-Based Separation:** Each unique combination of game-affecting settings creates a separate leaderboard: | |
| - `game_mode` (classic, easy, too easy) | |
| - `wordlist_source` (classic.txt, fourth_grade.txt, etc.) | |
| - `show_incorrect_guesses` (boolean) | |
| - `enable_free_letters` (boolean) | |
| - `puzzle_options` (spacer, may_overlap) | |
| - **Sorting:** Scores sorted by: score (desc) β time (asc) β difficulty (desc) | |
| - **Qualification:** Only top 25 (configurable) scores displayed per leaderboard (more can be stored) | |
| **Storage Structure:** | |
| ``` | |
| HF_REPO_ID/games/ | |
| βββ leaderboards/ | |
| β βββ daily/{YYYY-MM-DD}/{file_id}/settings.json | |
| β βββ weekly/{YYYY-Wwww}/{file_id}/settings.json | |
| βββ {challenge_id}/settings.json | |
| ``` | |
| **File ID Format:** `{wordlist_source}-{game_mode}-{sequence}` | |
| - Example: `classic-classic-0`, `easy-too_easy-1` | |
| - Sanitized (no .txt, lowercase, underscores for spaces) | |
| **Leaderboard Page UI:** | |
| - **Today Tab:** Current daily and weekly leaderboards | |
| - Query params: `?gidd={file_id}` and `?gidw={file_id}` for filtering | |
| - Side-by-side display in two columns | |
| - **Daily Tab:** Last 7 days of daily leaderboards | |
| - Expandable groups per date | |
| - All settings combinations shown | |
| - **Weekly Tab:** Current ISO week leaderboard | |
| - All settings combinations displayed | |
| - **History Tab:** Historical leaderboard browser | |
| - Dropdown selectors for period and settings | |
| - Separate daily and weekly columns | |
| **Integration:** | |
| - Automatic submission after game completion (opt-in) | |
| - Challenge scores also contribute to daily/weekly leaderboards | |
| - Source tracking via `source_challenge_id` field | |
| - Unified JSON format with `entry_type` field (daily/weekly/challenge) | |
| **Discovery:** Folder-based (no index.json) | |
| - Scans period folders for date/week IDs | |
| - Filters by file_id prefix for matching settings | |
| - Loads and verifies full settings match | |
| **Date Display Updates:** | |
| - All leaderboard files use UTC for period boundaries. | |
| - When displaying daily leaderboards, show the UTC period as a PST date range. | |
| - Example: For UTC file date 2025-12-08, display: | |
| 2025-12-08 00:00:00 UTC to 2025-12-08 23:59:59 UTC | |
| and | |
| 2025-12-07 16:00:00 PST to 2025-12-08 15:59:59 PST | |
| The leaderboard expander label should show: `Mon, Dec 08, 2025 4:00 PM PST β Tue, Dec 09, 2025 3:59:59 PM PST [settings badge]` | |
| **Access:** 'Leaderboard' link in the footer navigation at the bottom of the page | |
| ### PWA Support | |
| - β **PWA Installation:** App is installable as a Progressive Web App on desktop and mobile | |
| - Added `service worker` and `manifest.json` | |
| - Basic offline caching of static assets | |
| - INSTALL_GUIDE.md added with platform-specific install steps | |
| - No gameplay logic changes | |
| ### Settings Page (v0.2.8) | |
| - All game settings moved from sidebar to a dedicated settings page (`?page=settings`) | |
| - Accessible via the footer navigation (`βοΈ Settings` link) | |
| - Controls game mode, word list selection, grid options (spacer, grid ticks), and audio (music and sound effects) | |
| - Settings are persisted to JSON files in `wrdler/settings/` and the latest settings are loaded on app startup | |