Spaces:
Running
Running
| # BattleWords - Project Context | |
| ## Project Overview | |
| BattleWords is a vocabulary learning game inspired by Battleship mechanics, built with Streamlit and Python 3.12. Players reveal cells on a 12x12 grid to discover hidden words and earn points for strategic guessing. | |
| **Current Version:** 0.2.28 (Stable - PWA, Challenge Mode & Remote Storage) | |
| **Next Version:** 0.3.0 (In Development - Local Player History & Statistics) | |
| **Repository:** https://github.com/Oncorporation/BattleWords.git | |
| **Live Demo:** https://huggingface.co/spaces/Surn/BattleWords | |
| ## Recent Changes & Branch Status | |
| **Latest (v0.2.28):** | |
| - Progressive Web App (PWA) support | |
| - Added `service worker` and `manifest.json` | |
| - Basic offline caching of static assets | |
| - INSTALL_GUIDE.md added with install steps | |
| - No gameplay logic changes | |
| **Previous (v0.2.27):** | |
| - New setting: "Show Challenge Share Links" (default OFF) | |
| - Header Challenge Mode banner hides the "Share this challenge" link when disabled | |
| - Game Over dialog still lets you submit or create a challenge, but hides the generated share URL when disabled (shows a success message instead) | |
| - Setting is stored in Streamlit session state and preserved across "New Game" | |
| - No changes to `logic.py` or `game_storage.py`; this is a UI-only visibility feature | |
| ## Core Gameplay | |
| - 12x12 grid with 6 hidden words (2Γ4-letter, 2Γ5-letter, 2Γ6-letter) | |
| - Words placed horizontally or vertically, no overlaps | |
| - Players click cells to reveal letters or empty spaces | |
| - After revealing a letter, players can guess words | |
| - Scoring: word length + bonus for unrevealed letters | |
| - Game ends when all words are guessed or all word letters are revealed | |
| - Incorrect guess history with optional display (enabled by default) | |
| - 10 incorrect guess limit per game | |
| - **β IMPLEMENTED (v0.2.20+):** Challenge Mode with game sharing via short URLs | |
| - **β IMPLEMENTED (v0.2.20+):** Remote storage via Hugging Face datasets for challenges and leaderboards | |
| - **β IMPLEMENTED (v0.2.28):** PWA install support | |
| - **PLANNED (v0.3.0):** Local persistent storage for individual player results and high scores | |
| ### Scoring Tiers | |
| - **Fantastic:** 42+ points | |
| - **Great:** 38-41 points | |
| - **Good:** 34-37 points | |
| - **Keep practicing:** < 34 points | |
| ## Technical Architecture | |
| ### Technology Stack | |
| - **Framework:** Streamlit 1.51.0 | |
| - **Language:** Python 3.12.8 | |
| - **Visualization:** Matplotlib, NumPy | |
| - **Data Processing:** Pandas, Altair | |
| - **Storage:** JSON-based local persistence | |
| - **Testing:** Pytest | |
| - **Code Quality:** Flake8, MyPy | |
| - **Package Manager:** UV (modern Python package manager) | |
| ### Project Structure | |
| ``` | |
| battlewords/ | |
| βββ app.py # Streamlit entry point | |
| βββ battlewords/ # Main package | |
| β βββ __init__.py # Version: 0.2.17 | |
| β βββ models.py # Data models (Coord, Word, Puzzle, GameState) | |
| β βββ generator.py # Puzzle generation with deterministic seeding | |
| β βββ logic.py # Game mechanics (reveal, guess, scoring) | |
| β βββ ui.py # Streamlit UI (~1800 lines) | |
| β βββ word_loader.py # Word list management | |
| β βββ audio.py # Background music system | |
| β βββ sounds.py # Sound effects management | |
| β βββ generate_sounds.py # Sound generation utilities | |
| β βββ game_storage.py # HF game storage wrapper (v0.1.0) | |
| β βββ version_info.py # Version display | |
| β βββ modules/ # Shared utility modules (from OpenBadge) | |
| β β βββ __init__.py # Module exports | |
| β β βββ storage.py # HuggingFace storage & URL shortener (v0.1.5) | |
| β β βββ storage.md # Storage module documentation | |
| β β βββ constants.py # Storage-related constants (trimmed) | |
| β β βββ file_utils.py # File utility functions | |
| β βββ words/ # Word list files | |
| β βββ classic.txt # Default word list | |
| β βββ fourth_grade.txt # Elementary word list | |
| β βββ wordlist.txt # Full word list | |
| βββ tests/ # Unit tests | |
| βββ specs/ # Documentation | |
| β βββ specs.md # Game specifications | |
| β βββ requirements.md # Implementation requirements | |
| β βββ history.md # Game history | |
| βββ .env # Environment variables | |
| βββ pyproject.toml # Project metadata | |
| βββ requirements.txt # Dependencies | |
| βββ uv.lock # UV lock file | |
| βββ Dockerfile # Container deployment | |
| βββ CLAUDE.md # This file - project context for Claude | |
| ``` | |
| ## Key Features | |
| ### Game Modes | |
| 1. **Classic Mode:** Allows consecutive guessing after correct answers | |
| 2. **Too Easy Mode:** Single guess per reveal | |
| ### Audio & Visual Effects | |
| - **Background Music:** Toggleable ocean-themed background music with volume control | |
| - **Sound Effects:** Hit/miss/correct/incorrect guess sounds with volume control | |
| - **Animated Radar:** Pulsing rings showing word boundaries (last letter locations) | |
| - **Ocean Theme:** Gradient animated background with wave effects | |
| - **Incorrect Guess History:** Visual display of wrong guesses (toggleable in settings) | |
| ### β Challenge Mode & Remote Storage (v0.2.20+) | |
| - **Game ID System:** Short URL-based challenge sharing | |
| - Format: `?game_id=<sid>` in URL (shortened URL reference) | |
| - Each player gets different random words from the same wordlist | |
| - Enables fair challenges between players | |
| - Stored in Hugging Face dataset repository | |
| - **Remote Storage via HuggingFace Hub:** | |
| - Per-game settings JSON in `games/{uid}/settings.json` | |
| - Shortened URL mapping in `shortener.json` | |
| - Multi-user leaderboards with score, time, and difficulty tracking | |
| - Results sorted by: highest score β fastest time β highest difficulty | |
| - **Challenge Features:** | |
| - Submit results to existing challenges | |
| - Create new challenges from any completed game | |
| - Top 5 leaderboard display in Challenge Mode banner | |
| - Optional player names (defaults to "Anonymous") | |
| - Word list difficulty calculation and display | |
| - "Show Challenge Share Links" toggle (default OFF) to control URL visibility | |
| ### PLANNED: Local Player Storage (v0.3.0) | |
| - **Local Storage:** | |
| - Location: `~/.battlewords/data/` | |
| - Files: `game_results.json`, `highscores.json` | |
| - Privacy-first: no cloud dependency, offline-capable | |
| - **Personal High Scores:** | |
| - Top 100 scores tracked automatically on local machine | |
| - Filterable by wordlist and game mode | |
| - High score sidebar expander display | |
| - **Player Statistics:** | |
| - Games played, average score, best score | |
| - Fastest completion time | |
| - Per-player history on local device | |
| ### Puzzle Generation | |
| - Deterministic seeding support for reproducible puzzles | |
| - Configurable word spacing (spacer: 0-2) | |
| - 0: Words may touch | |
| - 1: At least 1 blank cell between words (default) | |
| - 2: At least 2 blank cells between words | |
| - Validation ensures no overlaps, proper bounds, correct word distribution | |
| ### UI Components (Current) | |
| - **Radar Visualization:** Animated matplotlib GIF showing word boundaries | |
| - Displays pulsing rings at last letter of each word | |
| - Hides rings for guessed words | |
| - Three-layer composition: gradient background, scope image, animated rings | |
| - Cached per-puzzle with signature matching | |
| - **Game Grid:** Interactive 12x12 button grid with responsive layout | |
| - **Score Panel:** Real-time scoring with client-side JavaScript timer | |
| - **Settings Sidebar:** | |
| - Word list picker (classic, fourth_grade, wordlist) | |
| - Game mode selector | |
| - Word spacing configuration (0-2) | |
| - Audio volume controls (music and effects separate) | |
| - Toggle for incorrect guess history display | |
| - **Theme System:** Ocean gradient background with CSS animations | |
| - **Game Over Dialog:** Final score display with tier ranking | |
| - **Incorrect Guess Display:** Shows history of wrong guesses with count | |
| - **β Challenge Mode UI (v0.2.20+):** | |
| - Challenge Mode banner with leaderboard (top 5 players) | |
| - Share challenge button in game over dialog | |
| - Submit result or create new challenge options | |
| - Word list difficulty display | |
| - Conditional share URL visibility toggle | |
| - **PLANNED (v0.3.0):** Local high scores expander in sidebar | |
| - **PLANNED (v0.3.0):** Personal statistics display | |
| ### Recent Changes & Branch Status | |
| **Branch:** cc-01 (Storage and sharing features - v0.3.0 development) | |
| **Latest (v0.2.17):** | |
| - Documentation updates and corrections | |
| - Updated CLAUDE.md with accurate feature status | |
| - Clarified v0.3.0 planned features vs current implementation | |
| - Added comprehensive project structure details | |
| - Improved version tracking and roadmap clarity | |
| **Previously Fixed (v0.2.16):** | |
| - Replace question marks with underscores in score panel | |
| - Add toggle for incorrect guess history display (enabled by default) | |
| - Game over popup positioning improvements | |
| - Music playback after game end | |
| - Sound effect and music volume issues | |
| - Radar alignment inconsistencies | |
| - Added `fig.subplots_adjust(left=0, right=0.9, top=0.9, bottom=0)` | |
| - Set `fig.patch.set_alpha(0.0)` for transparent background | |
| - Maintains 2% margin for tick visibility while ensuring consistent layer alignment | |
| **Completed (v0.2.20-0.2.27 - Challenge Mode):** | |
| - β Imported storage modules from OpenBadge project: | |
| - `battlewords/modules/storage.py` (v0.1.5) - HuggingFace storage & URL shortener | |
| - `battlewords/modules/constants.py` (trimmed) - Storage-related constants | |
| - `battlewords/modules/file_utils.py` - File utility functions | |
| - `battlewords/modules/storage.md` - Documentation | |
| - β Created `battlewords/game_storage.py` (v0.1.0) - BattleWords storage wrapper: | |
| - `save_game_to_hf()` - Save game to HF repo and generate short URL | |
| - `load_game_from_sid()` - Load game from short ID | |
| - `generate_uid()` - Generate unique game identifiers | |
| - `serialize_game_settings()` - Convert game data to JSON | |
| - `get_shareable_url()` - Generate shareable URLs | |
| - `add_user_result_to_game()` - Append results to existing challenges | |
| - β UI integration complete (`battlewords/ui.py`): | |
| - Query parameter parsing for `?game_id=<sid>` on app load | |
| - Load shared game settings into session state | |
| - Challenge Mode banner with leaderboard (top 5) | |
| - Share button in game over dialog with "Generate Share Link" or "Submit Result" | |
| - Conditional share URL display based on settings toggle | |
| - Automatic save to HuggingFace on game completion | |
| - Word list difficulty calculation and display | |
| - β Generator updates (`battlewords/generator.py`): | |
| - Added `target_words` parameter for loading specific words | |
| - Added `may_overlap` parameter (for future crossword mode) | |
| - Support for shared game replay with randomized word positions | |
| **In Progress (v0.3.0 - Local Player History):** | |
| - β³ Local storage module (`battlewords/local_storage.py`) | |
| - β³ Personal high score tracking (local JSON files) | |
| - β³ High score sidebar UI display | |
| - β³ Player statistics tracking and display | |
| ## Data Models | |
| ### Core Classes | |
| ```python | |
| @dataclass | |
| class Coord: | |
| x: int # row, 0-based | |
| y: int # col, 0-based | |
| @dataclass | |
| class Word: | |
| text: str | |
| start: Coord | |
| direction: Direction # "H" or "V" | |
| cells: List[Coord] | |
| @dataclass | |
| class Puzzle: | |
| words: List[Word] | |
| radar: List[Coord] | |
| may_overlap: bool | |
| spacer: int | |
| uid: str # Unique identifier for caching | |
| @dataclass | |
| class GameState: | |
| grid_size: int | |
| puzzle: Puzzle | |
| revealed: Set[Coord] | |
| guessed: Set[str] | |
| score: int | |
| last_action: str | |
| can_guess: bool | |
| game_mode: str | |
| points_by_word: Dict[str, int] | |
| start_time: Optional[datetime] | |
| end_time: Optional[datetime] | |
| ``` | |
| ## Development Workflow | |
| ### Running Locally | |
| ```bash | |
| # Install dependencies | |
| uv pip install -r requirements.txt --link-mode=copy | |
| # Run app | |
| uv run streamlit run app.py | |
| # or | |
| streamlit run app.py | |
| ``` | |
| ### Docker Deployment | |
| ```bash | |
| docker build -t battlewords . | |
| docker run -p 8501:8501 battlewords | |
| ``` | |
| ### Testing | |
| ```bash | |
| pytest tests/ | |
| ``` | |
| ### Environment Variables (for Challenge Mode) | |
| Challenge Mode requires HuggingFace Hub access for remote storage. Create a `.env` file in the project root: | |
| ```bash | |
| # Required for Challenge Mode | |
| HF_API_TOKEN=hf_xxxxxxxxxxxxxxxxxxxxx # or HF_TOKEN | |
| HF_REPO_ID=YourUsername/YourRepo # Target HF dataset repo | |
| SPACE_NAME=YourUsername/BattleWords # Your HF Space name | |
| # Optional | |
| CRYPTO_PK= # Reserved for future signing | |
| ``` | |
| **How to get your HF_API_TOKEN:** | |
| 1. Go to https://huggingface.co/settings/tokens | |
| 2. Create a new token with `write` access | |
| 3. Add to `.env` file as `HF_API_TOKEN=hf_...` | |
| **HF_REPO_ID Structure:** | |
| The dataset repository will contain: | |
| - `shortener.json` - Short URL mappings | |
| - `games/{uid}/settings.json` - Per-game challenge data | |
| - `games/{uid}/result.json` - Optional detailed results | |
| **Note:** The app will work without these variables but Challenge Mode features (sharing, leaderboards) will be disabled. | |
| ## Git Configuration & Deployment | |
| **Current Branch:** cc-01 | |
| **Purpose:** Storage and sharing features (v0.3.0 development) | |
| **Main Branch:** main (not specified in git config, but typical convention) | |
| ### Remotes | |
| - **ONCORP (origin):** https://github.com/Oncorporation/BattleWords.git (main repository) | |
| - **Hugging:** https://huggingface.co/spaces/Surn/BattleWords (live deployment) | |
| ## Known Issues | |
| - Word list loading bug: App may not select proper word lists in some environments | |
| - Investigation needed in `word_loader.get_wordlist_files()` and `load_word_list()` | |
| - Sidebar selection persistence needs verification | |
| ## v0.3.0 Development Status (cc-01 branch) | |
| ### Completed β | |
| - `battlewords/storage.py` module created with: | |
| - `GameStorage` class for JSON-based local storage | |
| - `GameResult` and `HighScoreEntry` dataclasses | |
| - Functions: `generate_game_id_from_words()`, `parse_game_id_from_url()`, `create_shareable_url()` | |
| - Storage location: `~/.battlewords/data/` (game_results.json, highscores.json) | |
| - Documentation updated in specs/ folder | |
| ### In Progress β³ | |
| - Puzzle model integration for game_id field | |
| - Generator updates for `target_words` parameter (replay from game_id) | |
| - UI integration: | |
| - Storage calls on game completion | |
| - High score display in sidebar | |
| - Share button in game over dialog | |
| - Query parameter parsing for game_id | |
| - Player name input in sidebar | |
| ### Planned π | |
| - Unit tests for storage module | |
| - Integration tests for complete storage flow | |
| - Game replay from shared ID functionality | |
| - Player statistics display | |
| - Share results text generation | |
| ## Future Roadmap | |
| ### Phase 1.5 (v0.3.0) - Current Focus β³ | |
| - β Storage module with local JSON persistence (backend complete) | |
| - β Game ID generation system (backend complete) | |
| - β³ High score tracking and display (backend complete, UI pending) | |
| - β³ Share challenge functionality (UI integration pending) | |
| - β³ Game replay from shared IDs (generator updates needed) | |
| - β³ Player name input and statistics | |
| ### Beta (v0.5.0) | |
| - Word overlaps on shared letters (crossword-style gameplay) | |
| - Enhanced responsive layout for mobile/tablet | |
| - Keyboard navigation and guessing | |
| - Deterministic seed UI for custom puzzles | |
| - Improved accessibility features | |
| ### Full (v1.0.0) | |
| - Optional cloud storage backend (FastAPI) | |
| - Daily puzzle mode with global leaderboards | |
| - Practice mode with hints | |
| - Enhanced UX features (animations, themes) | |
| - Multiple difficulty levels | |
| - Internationalization (i18n) support | |
| ## Deployment Targets | |
| - **Hugging Face Spaces:** Primary deployment platform | |
| - **Docker:** Containerized deployment for any platform | |
| - **Local:** Development and testing | |
| ### Privacy & Data | |
| - All storage is local (no telemetry) | |
| - Player names optional | |
| - No data leaves user's machine | |
| - Easy to delete: just remove `~/.battlewords/data/` | |
| ## Notes for Claude | |
| - Project uses modern Python features (3.12+) | |
| - Heavy use of Streamlit session state for game state management | |
| - Matplotlib figures are converted to PIL images and animated GIFs | |
| - Client-side JavaScript for timer updates without page refresh | |
| - CSS heavily customized for game aesthetics | |
| - All file paths should be absolute when working in WSL environment | |
| - Current working directory: `/mnt/d/Projects/Battlewords` | |
| - Storage features are backward-compatible (game works without storage) | |
| - Game IDs are deterministic for consistent sharing | |
| - JSON storage chosen for simplicity and privacy | |
| ### WSL Environment Python Versions | |
| The development environment is WSL (Windows Subsystem for Linux) with access to both native Linux and Windows Python installations: | |
| **Native WSL (Linux):** | |
| - `python3` β Python 3.10.12 (`/usr/bin/python3`) | |
| - `python3.10` β Python 3.10.12 | |
| **Windows Python (accessible via WSL):** | |
| - `python311.exe` β Python 3.11.9 (`/mnt/c/Users/cfettinger/AppData/Local/Programs/Python/Python311/`) | |
| - `python3.13.exe` β Python 3.13.1 (`/mnt/c/ProgramData/chocolatey/bin/`) | |
| **Note:** Windows Python executables (`.exe`) can be invoked directly from WSL and are useful for testing compatibility across Python versions. The project targets Python 3.12+ but can run on 3.10+. | |
| ## v0.2.20: Remote Storage game_id via Shortened URL | |
| Overview | |
| - Use a storage server (Hugging Face Hub repo) to persist: | |
| - Per-game settings JSON (word_list, score, time, game_mode, grid_size, puzzle options) | |
| - High scores JSON (top scores) | |
| - Each completed game writes JSON to repo under a unique `uid` folder. | |
| - A shortened URL (sid) referencing the settings JSON is generated and used as `game_id` in the query string. | |
| - On load, if `?game_id=<sid>` exists, resolve sid to the full JSON URL, fetch it, and apply settings for the session. | |
| Modules to leverage (from OpenBadge/modules) | |
| - `modules/storage.py` | |
| - `upload_files_to_repo(files, repo_id, folder_name, repo_type="dataset")` | |
| - `gen_full_url(short_url=None, full_url=None, repo_id=None, json_file="shortener.json")` | |
| - `modules/constants.py` (env + defaults) | |
| - Uses HF token from env (expects `HF_TOKEN`, we will also document `HF_API_TOKEN`) | |
| - `HF_REPO_ID`, `SPACE_NAME`, `SHORTENER_JSON_FILE` | |
| - `modules/file_utils.py` (helpers) | |
| Environment variables (.env) | |
| - HF_API_TOKEN or HF_TOKEN: Hugging Face access token (Bearer) | |
| - CRYPTO_PK: optional, reserved for future signing | |
| - HF_REPO_ID: target repo, e.g., Surn/Storage | |
| - SPACE_NAME: e.g., Surn/BattleWords | |
| Repository structure (dataset repo) | |
| - shortener.json # sid -> full URL mapping | |
| - games/{uid}/settings.json # per-game settings payload (primary) | |
| - games/{uid}/result.json # finalized game result (optional) | |
| - highscores/highscores.json # global/top scores JSON | |
| Game settings JSON (example) | |
| { | |
| "uid": "20250101T120001Z-ABC123", | |
| "word_list": ["APPLE","TRAIN","..."], | |
| "score": 40, | |
| "time": 173, | |
| "game_mode": "classic", | |
| "grid_size": 12, | |
| "puzzle_options": { "spacer": 1, "may_overlap": false } | |
| } | |
| Flow | |
| 1) On game completion | |
| - Build unique `uid` (timestamp + random suffix). | |
| - Write settings.json (and optional result.json) to games/{uid}/ | |
| - Create full URL to settings.json, call `gen_full_url(full_url=...)` to obtain `sid` | |
| - Share link: https://<space>/?game_id=<sid> | |
| 2) On load with `?game_id=<sid>` | |
| - Call `gen_full_url(short_url=sid)` to get full URL | |
| - Fetch settings.json, apply session: word_list, game_mode, grid_size, puzzle options; ignore score/time for gameplay | |
| 3) Highscores | |
| - Maintain highscores/highscores.json in repo; append/update with best entries | |
| Security/Privacy | |
| - Only game configuration and scores are stored; no PII required | |
| - sid is a reference; shortener.json can be in the same repo | |
| - Consider private repo for write access; dataset can be public for read | |
| Notes | |
| - We will keep `battlewords/storage.py` as local-only storage (JSON on disk) and introduce a new integration wrapper in a later PR (e.g., `battlewords/hf_storage.py`) to avoid confusion with the generic modules. If needed, rename `battlewords/storage.py` to `local_storage.py` in a future pass. | |
| - Add dependencies: `huggingface_hub`, `python-dotenv` | |
| ## Documentation Structure | |
| This file (CLAUDE.md) serves as a **living context document** for AI-assisted development. It complements the formal specification documents: | |
| - **[specs/specs.md](specs/specs.md)** - Game rules, requirements, and feature specifications | |
| - **[specs/requirements.md](specs/requirements.md)** - Implementation phases, acceptance criteria, and technical tasks | |
| - **[README.md](README.md)** - User-facing documentation, installation guide, and changelog | |
| **When to use each:** | |
| - **specs.md** - Understanding game rules, scoring, and player experience | |
| - **requirements.md** - Planning implementation work, tracking phases, and defining done criteria | |
| - **CLAUDE.md** - Quick reference for codebase structure, recent changes, and development context | |
| - **README.md** - Public-facing information, setup instructions, and feature announcements | |
| **Synchronization:** | |
| Changes to game mechanics should update specs.md β requirements.md β CLAUDE.md β README.md in that order | |
| ## Challenge Mode & Remote Storage | |
| - The app supports a Challenge Mode where games can be shared via a short link (`?game_id=<sid>`). | |
| - Results are stored in a Hugging Face dataset repo using `game_storage.py`. | |
| - The leaderboard for a challenge is sorted by highest score (descending), then by fastest time (ascending). | |
| - Each user result is appended to the challenge's `users` array in the remote JSON. | |