BattleWords / claude.md
Surn's picture
0.2.29
ffe26fc
# 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.