# 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.17 (Stable) **Next Version:** 0.3.0 (In Development - Storage & Sharing Features) **Repository:** https://github.com/Oncorporation/BattleWords.git **Live Demo:** https://huggingface.co/spaces/Surn/BattleWords ## 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 revealed - Incorrect guess history with optional display (enabled by default) - 10 incorrect guess limit per game - **PLANNED (v0.3.0):** Game sharing via unique game IDs - **PLANNED (v0.3.0):** Local persistent storage for 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.50.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) ### PLANNED: Storage & Sharing (v0.3.0) - **Game ID System:** 8-character deterministic IDs based on word combinations - Format: `?game_id=ABC123` in URL - Same words, different positions for each replay - Enables fair challenges between players - **Local Storage:** - Location: `~/.battlewords/data/` - Files: `game_results.json`, `highscores.json` - Privacy-first: no cloud dependency - **High Scores:** - Top 100 scores tracked automatically - Filterable by wordlist and game mode - Optional player names (defaults to "Anonymous") - **Player Statistics:** - Games played, average score, best score - Fastest completion time - Per-player history ### 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 - **v0.3.0:** Game ID system planned (not yet integrated into Puzzle model) ### 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 - **PLANNED (v0.3.0):** High scores expander in sidebar - **PLANNED (v0.3.0):** Share challenge button in game over dialog - **PLANNED (v0.3.0):** Game ID display during gameplay ### 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 **In Progress (v0.3.0 on cc-01):** - ✅ 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 - ✅ UI integration complete (`battlewords/ui.py`): - Query parameter parsing for `?game_id=` on app load - Load shared game settings into session state - Challenge Mode banner showing target score and time - Share button in game over dialog with "Generate Share Link" - Copy-to-clipboard functionality for share URLs - Automatic save to HuggingFace on game completion - ✅ 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 same words, different positions - ⏳ High score tracking infrastructure (backend ready, UI pending) ## 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/ ``` ## 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=` 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:///?game_id= 2) On load with `?game_id=` - 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=`). - 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.