Spaces:
Running
Running
0.2.19
Browse files- Fix music and sound effect volume issues
- Update documentation for proposed new features
- .gitignore +1 -0
- README.md +27 -0
- battlewords/__init__.py +1 -1
- battlewords/storage.py +1 -1
- claude.md +93 -0
- pyproject.toml +2 -2
- requirements.txt +3 -1
- specs/requirements.md +55 -0
- specs/specs.md +25 -0
.gitignore
CHANGED
|
@@ -490,3 +490,4 @@ secrets.*
|
|
| 490 |
/battlewords/__pycache__/__init__.cpython-311.pyc
|
| 491 |
/package.json
|
| 492 |
/package-lock.json
|
|
|
|
|
|
| 490 |
/battlewords/__pycache__/__init__.cpython-311.pyc
|
| 491 |
/package.json
|
| 492 |
/package-lock.json
|
| 493 |
+
/.claude
|
README.md
CHANGED
|
@@ -112,6 +112,33 @@ docker run -p8501:8501 battlewords
|
|
| 112 |
- High Scores: local leaderboard tracking top scores by wordlist and game mode.
|
| 113 |
- Persistent Storage: all game results saved locally for personal statistics without accounts.
|
| 114 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 115 |
-0.2.18
|
| 116 |
- Fix sound effect volume wiring and apply volume to all effects (hit/miss/correct/incorrect)
|
| 117 |
- Respect "Enable music" and "Volume" when playing congratulations music and when resuming background music (uses selected track)
|
|
|
|
| 112 |
- High Scores: local leaderboard tracking top scores by wordlist and game mode.
|
| 113 |
- Persistent Storage: all game results saved locally for personal statistics without accounts.
|
| 114 |
|
| 115 |
+
-0.2.20 (development)
|
| 116 |
+
- Remote Storage game_id:
|
| 117 |
+
- Per-game JSON settings uploaded to a storage server (Hugging Face repo) under unique `games/{uid}/settings.json`
|
| 118 |
+
- A shortened URL id (sid) is generated; shareable link: `?game_id=<sid>`
|
| 119 |
+
- On load with `game_id`, the app resolves sid to the JSON and applies word_list, game_mode, grid_size, puzzle options
|
| 120 |
+
- High Scores: add remote `highscores/highscores.json` (repo) alongside local highscores
|
| 121 |
+
- Dependencies: add `huggingface_hub` and `python-dotenv`
|
| 122 |
+
- Env: `.env` should include `HF_API_TOKEN` (or `HF_TOKEN`), `CRYPTO_PK`, `HF_REPO_ID`, `SPACE_NAME`
|
| 123 |
+
|
| 124 |
+
### Environment Variables
|
| 125 |
+
- HF_API_TOKEN or HF_TOKEN: HF Hub access token
|
| 126 |
+
- CRYPTO_PK: reserved for signing (optional)
|
| 127 |
+
- HF_REPO_ID: e.g., Surn/Storage
|
| 128 |
+
- SPACE_NAME: e.g., Surn/BattleWords
|
| 129 |
+
|
| 130 |
+
### Remote Storage Structure
|
| 131 |
+
- shortener.json
|
| 132 |
+
- games/{uid}/settings.json
|
| 133 |
+
- highscores/highscores.json
|
| 134 |
+
|
| 135 |
+
Note
|
| 136 |
+
- `battlewords/storage.py` remains local-only storage; a separate HF integration wrapper will be added in a later PR to avoid confusion with generic modules
|
| 137 |
+
|
| 138 |
+
-0.2.19
|
| 139 |
+
- Fix music and sound effect volume issues
|
| 140 |
+
- Update documentation for proposed new features
|
| 141 |
+
|
| 142 |
-0.2.18
|
| 143 |
- Fix sound effect volume wiring and apply volume to all effects (hit/miss/correct/incorrect)
|
| 144 |
- Respect "Enable music" and "Volume" when playing congratulations music and when resuming background music (uses selected track)
|
battlewords/__init__.py
CHANGED
|
@@ -1,2 +1,2 @@
|
|
| 1 |
-
__version__ = "0.2.
|
| 2 |
__all__ = ["models", "generator", "logic", "ui"]
|
|
|
|
| 1 |
+
__version__ = "0.2.19"
|
| 2 |
__all__ = ["models", "generator", "logic", "ui"]
|
battlewords/storage.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
| 1 |
-
|
| 2 |
"""
|
| 3 |
Storage module for BattleWords game.
|
| 4 |
|
|
|
|
| 1 |
+
# file: battlewords/storage.py
|
| 2 |
"""
|
| 3 |
Storage module for BattleWords game.
|
| 4 |
|
claude.md
CHANGED
|
@@ -309,3 +309,96 @@ pytest tests/
|
|
| 309 |
- Storage features are backward-compatible (game works without storage)
|
| 310 |
- Game IDs are deterministic for consistent sharing
|
| 311 |
- JSON storage chosen for simplicity and privacy
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 309 |
- Storage features are backward-compatible (game works without storage)
|
| 310 |
- Game IDs are deterministic for consistent sharing
|
| 311 |
- JSON storage chosen for simplicity and privacy
|
| 312 |
+
|
| 313 |
+
### WSL Environment Python Versions
|
| 314 |
+
The development environment is WSL (Windows Subsystem for Linux) with access to both native Linux and Windows Python installations:
|
| 315 |
+
|
| 316 |
+
**Native WSL (Linux):**
|
| 317 |
+
- `python3` → Python 3.10.12 (`/usr/bin/python3`)
|
| 318 |
+
- `python3.10` → Python 3.10.12
|
| 319 |
+
|
| 320 |
+
**Windows Python (accessible via WSL):**
|
| 321 |
+
- `python311.exe` → Python 3.11.9 (`/mnt/c/Users/cfettinger/AppData/Local/Programs/Python/Python311/`)
|
| 322 |
+
- `python3.13.exe` → Python 3.13.1 (`/mnt/c/ProgramData/chocolatey/bin/`)
|
| 323 |
+
|
| 324 |
+
**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+.
|
| 325 |
+
|
| 326 |
+
## v0.2.20: Remote Storage game_id via Shortened URL
|
| 327 |
+
|
| 328 |
+
Overview
|
| 329 |
+
- Use a storage server (Hugging Face Hub repo) to persist:
|
| 330 |
+
- Per-game settings JSON (word_list, score, time, game_mode, grid_size, puzzle options)
|
| 331 |
+
- High scores JSON (top scores)
|
| 332 |
+
- Each completed game writes JSON to repo under a unique `uid` folder.
|
| 333 |
+
- A shortened URL (sid) referencing the settings JSON is generated and used as `game_id` in the query string.
|
| 334 |
+
- On load, if `?game_id=<sid>` exists, resolve sid to the full JSON URL, fetch it, and apply settings for the session.
|
| 335 |
+
|
| 336 |
+
Modules to leverage (from OpenBadge/modules)
|
| 337 |
+
- `modules/storage.py`
|
| 338 |
+
- `upload_files_to_repo(files, repo_id, folder_name, repo_type="dataset")`
|
| 339 |
+
- `gen_full_url(short_url=None, full_url=None, repo_id=None, json_file="shortener.json")`
|
| 340 |
+
- `modules/constants.py` (env + defaults)
|
| 341 |
+
- Uses HF token from env (expects `HF_TOKEN`, we will also document `HF_API_TOKEN`)
|
| 342 |
+
- `HF_REPO_ID`, `SPACE_NAME`, `SHORTENER_JSON_FILE`
|
| 343 |
+
- `modules/file_utils.py` (helpers)
|
| 344 |
+
|
| 345 |
+
Environment variables (.env)
|
| 346 |
+
- HF_API_TOKEN or HF_TOKEN: Hugging Face access token (Bearer)
|
| 347 |
+
- CRYPTO_PK: optional, reserved for future signing
|
| 348 |
+
- HF_REPO_ID: target repo, e.g., Surn/Storage
|
| 349 |
+
- SPACE_NAME: e.g., Surn/BattleWords
|
| 350 |
+
|
| 351 |
+
Repository structure (dataset repo)
|
| 352 |
+
- shortener.json # sid -> full URL mapping
|
| 353 |
+
- games/{uid}/settings.json # per-game settings payload (primary)
|
| 354 |
+
- games/{uid}/result.json # finalized game result (optional)
|
| 355 |
+
- highscores/highscores.json # global/top scores JSON
|
| 356 |
+
|
| 357 |
+
Game settings JSON (example)
|
| 358 |
+
{
|
| 359 |
+
"uid": "20250101T120001Z-ABC123",
|
| 360 |
+
"word_list": ["APPLE","TRAIN","..."],
|
| 361 |
+
"score": 40,
|
| 362 |
+
"time": 173,
|
| 363 |
+
"game_mode": "classic",
|
| 364 |
+
"grid_size": 12,
|
| 365 |
+
"puzzle_options": { "spacer": 1, "may_overlap": false }
|
| 366 |
+
}
|
| 367 |
+
|
| 368 |
+
Flow
|
| 369 |
+
1) On game completion
|
| 370 |
+
- Build unique `uid` (timestamp + random suffix).
|
| 371 |
+
- Write settings.json (and optional result.json) to games/{uid}/
|
| 372 |
+
- Create full URL to settings.json, call `gen_full_url(full_url=...)` to obtain `sid`
|
| 373 |
+
- Share link: https://<space>/?game_id=<sid>
|
| 374 |
+
2) On load with `?game_id=<sid>`
|
| 375 |
+
- Call `gen_full_url(short_url=sid)` to get full URL
|
| 376 |
+
- Fetch settings.json, apply session: word_list, game_mode, grid_size, puzzle options; ignore score/time for gameplay
|
| 377 |
+
3) Highscores
|
| 378 |
+
- Maintain highscores/highscores.json in repo; append/update with best entries
|
| 379 |
+
|
| 380 |
+
Security/Privacy
|
| 381 |
+
- Only game configuration and scores are stored; no PII required
|
| 382 |
+
- sid is a reference; shortener.json can be in the same repo
|
| 383 |
+
- Consider private repo for write access; dataset can be public for read
|
| 384 |
+
|
| 385 |
+
Notes
|
| 386 |
+
- 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.
|
| 387 |
+
- Add dependencies: `huggingface_hub`, `python-dotenv`
|
| 388 |
+
|
| 389 |
+
## Documentation Structure
|
| 390 |
+
|
| 391 |
+
This file (CLAUDE.md) serves as a **living context document** for AI-assisted development. It complements the formal specification documents:
|
| 392 |
+
|
| 393 |
+
- **[specs/specs.md](specs/specs.md)** - Game rules, requirements, and feature specifications
|
| 394 |
+
- **[specs/requirements.md](specs/requirements.md)** - Implementation phases, acceptance criteria, and technical tasks
|
| 395 |
+
- **[README.md](README.md)** - User-facing documentation, installation guide, and changelog
|
| 396 |
+
|
| 397 |
+
**When to use each:**
|
| 398 |
+
- **specs.md** - Understanding game rules, scoring, and player experience
|
| 399 |
+
- **requirements.md** - Planning implementation work, tracking phases, and defining done criteria
|
| 400 |
+
- **CLAUDE.md** - Quick reference for codebase structure, recent changes, and development context
|
| 401 |
+
- **README.md** - Public-facing information, setup instructions, and feature announcements
|
| 402 |
+
|
| 403 |
+
**Synchronization:**
|
| 404 |
+
Changes to game mechanics should update specs.md → requirements.md → CLAUDE.md → README.md in that order
|
pyproject.toml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
| 1 |
[project]
|
| 2 |
name = "battlewords"
|
| 3 |
-
version = "0.2.
|
| 4 |
-
description = "BattleWords vocabulary game"
|
| 5 |
readme = "README.md"
|
| 6 |
requires-python = ">=3.12,<3.13"
|
| 7 |
dependencies = [
|
|
|
|
| 1 |
[project]
|
| 2 |
name = "battlewords"
|
| 3 |
+
version = "0.2.20"
|
| 4 |
+
description = "BattleWords vocabulary game with game sharing via shortened game_id URL referencing server-side JSON settings"
|
| 5 |
readme = "README.md"
|
| 6 |
requires-python = ">=3.12,<3.13"
|
| 7 |
dependencies = [
|
requirements.txt
CHANGED
|
@@ -7,4 +7,6 @@ Pillow
|
|
| 7 |
pytest
|
| 8 |
flake8
|
| 9 |
mypy
|
| 10 |
-
requests
|
|
|
|
|
|
|
|
|
| 7 |
pytest
|
| 8 |
flake8
|
| 9 |
mypy
|
| 10 |
+
requests
|
| 11 |
+
huggingface_hub
|
| 12 |
+
python-dotenv
|
specs/requirements.md
CHANGED
|
@@ -192,3 +192,58 @@ Definitions of Done (per task)
|
|
| 192 |
- Code merged with tests and docs updated.
|
| 193 |
- No regressions in existing tests; coverage maintained or improved for core logic.
|
| 194 |
- Manual playthrough validates rules: reveal/guess gating, scoring, radar pulses, end state and tiers.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 192 |
- Code merged with tests and docs updated.
|
| 193 |
- No regressions in existing tests; coverage maintained or improved for core logic.
|
| 194 |
- Manual playthrough validates rules: reveal/guess gating, scoring, radar pulses, end state and tiers.
|
| 195 |
+
|
| 196 |
+
## v0.2.20 Update: Game Sharing with Shortened game_id URL
|
| 197 |
+
|
| 198 |
+
### Game Sharing Feature
|
| 199 |
+
- On game completion, save a JSON file to the storage server named by a unique `uid`.
|
| 200 |
+
- The JSON file contains: word_list, score, time, game_mode, grid_size, and puzzle options.
|
| 201 |
+
- Generate a shortened URL for this file; use it as the `game_id` in the shareable link.
|
| 202 |
+
- When a user loads a game with a `game_id` query string, fetch the JSON file and apply all settings for the session.
|
| 203 |
+
|
| 204 |
+
### Implementation Notes
|
| 205 |
+
- The game_id is a shortened URL referencing the JSON file.
|
| 206 |
+
- The app applies all settings from the file for a true replay.
|
| 207 |
+
- No direct encoding of game data in the query string; only the reference is shared.
|
| 208 |
+
|
| 209 |
+
## Phase 1.6: Remote Storage & Sharing (0.2.20)
|
| 210 |
+
|
| 211 |
+
Goal
|
| 212 |
+
- Persist per-game settings and highscores on a storage server (Hugging Face Hub repo).
|
| 213 |
+
- Use a shortened `game_id` (sid) that resolves to settings.json for replay/sharing.
|
| 214 |
+
|
| 215 |
+
A) Storage Server Integration
|
| 216 |
+
- Use modules from OpenBadge `modules/storage.py`:
|
| 217 |
+
- `upload_files_to_repo(...)` to write JSON to `HF_REPO_ID`
|
| 218 |
+
- `gen_full_url(...)` for shortener lookups/creation backed by `shortener.json`
|
| 219 |
+
- Create per-game folder `games/{uid}/` and write:
|
| 220 |
+
- `settings.json` with: word_list, score, time, game_mode, grid_size, puzzle options
|
| 221 |
+
- (optional) `result.json` with additional details for analytics
|
| 222 |
+
- Maintain `highscores/highscores.json` for top scores
|
| 223 |
+
- Env vars (.env): `HF_API_TOKEN` (or `HF_TOKEN`), `CRYPTO_PK`, `HF_REPO_ID`, `SPACE_NAME`
|
| 224 |
+
|
| 225 |
+
B) Sharing Link (game_id)
|
| 226 |
+
- After upload of `settings.json`, call `gen_full_url(full_url=...)` to obtain a short id (sid)
|
| 227 |
+
- Shareable link: `https://<SPACE_NAME>/?game_id=<sid>`
|
| 228 |
+
- On app load with `game_id`, call `gen_full_url(short_url=sid)`, fetch JSON, apply settings
|
| 229 |
+
|
| 230 |
+
C) App Behavior
|
| 231 |
+
- When `game_id` exists:
|
| 232 |
+
- Apply `game_mode`, `grid_size`, `puzzle_options` directly
|
| 233 |
+
- Load `word_list` as the target set; positions remain randomized unless later extended
|
| 234 |
+
- Ignore `score`/`time` for gameplay; those are metadata only
|
| 235 |
+
- Continue to support local JSON storage for users without HF credentials
|
| 236 |
+
|
| 237 |
+
D) Dependencies
|
| 238 |
+
- Add `huggingface_hub` and `python-dotenv` to requirements
|
| 239 |
+
- Ensure `requests` remains present for HTTP fetch fallback if needed
|
| 240 |
+
|
| 241 |
+
E) Acceptance
|
| 242 |
+
- A completed game produces a working share link with `game_id` sid
|
| 243 |
+
- Visiting the link reconstructs the session settings from storage server JSON
|
| 244 |
+
- Highscores JSON updates in the repo
|
| 245 |
+
- Documentation updated with env vars, repo structure, and flows
|
| 246 |
+
|
| 247 |
+
F) Implementation Notes
|
| 248 |
+
- Do not replace `battlewords/storage.py` now; introduce a separate integration wrapper (e.g., `battlewords/hf_storage.py`) in the next PR
|
| 249 |
+
- Consider a private repo for write access; shortener JSON and settings JSONs can be public read
|
specs/specs.md
CHANGED
|
@@ -88,3 +88,28 @@ Battlewords is inspired by the classic Battleship game, but uses words instead o
|
|
| 88 |
|
| 89 |
## Copyright
|
| 90 |
BattlewordsTM. All Rights Reserved. All content, trademarks and logos are copyrighted by the owner.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 88 |
|
| 89 |
## Copyright
|
| 90 |
BattlewordsTM. All Rights Reserved. All content, trademarks and logos are copyrighted by the owner.
|
| 91 |
+
|
| 92 |
+
## v0.2.20: Remote Storage and Shortened game_id URL
|
| 93 |
+
|
| 94 |
+
Game Sharing
|
| 95 |
+
- Each puzzle can be shared via a link containing a `game_id` querystring (short id / sid)
|
| 96 |
+
- `game_id` resolves to a settings JSON on the storage server (HF repo)
|
| 97 |
+
- JSON fields:
|
| 98 |
+
- word_list (list of 6 uppercase words)
|
| 99 |
+
- score (int), time (int seconds) [metadata only]
|
| 100 |
+
- game_mode (e.g., classic, too easy)
|
| 101 |
+
- grid_size (e.g., 12)
|
| 102 |
+
- puzzle_options (e.g., { spacer, may_overlap })
|
| 103 |
+
- On load with `game_id`, fetch and apply: word_list, game_mode, grid_size, puzzle_options
|
| 104 |
+
|
| 105 |
+
High Scores
|
| 106 |
+
- Repository maintains `highscores/highscores.json` for top scores
|
| 107 |
+
- Local highscores remain supported for offline use
|
| 108 |
+
|
| 109 |
+
UI/UX
|
| 110 |
+
- Show the current `game_id` (sid) and a �Share Challenge� link
|
| 111 |
+
- When loading with a `game_id`, indicate the puzzle is a shared challenge
|
| 112 |
+
|
| 113 |
+
Security/Privacy
|
| 114 |
+
- Only game configuration and scores are stored; no personal data is required
|
| 115 |
+
- `game_id` is a short reference; full URL is stored in a repo JSON shortener index
|