Spaces:
Running
Running
Specification Update
Browse files- README.md +142 -1
- specs/requirements.md +50 -25
- specs/specs.md +36 -9
README.md
CHANGED
|
@@ -1,2 +1,143 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
# BattleWords
|
| 2 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
title: BattleWords
|
| 3 |
+
emoji: 🎲
|
| 4 |
+
colorFrom: blue
|
| 5 |
+
colorTo: indigo
|
| 6 |
+
sdk: streamlit
|
| 7 |
+
sdk_version: 1.25.0
|
| 8 |
+
python_version: 3.10
|
| 9 |
+
app_file: app.py
|
| 10 |
+
tags:
|
| 11 |
+
- game
|
| 12 |
+
- vocabulary
|
| 13 |
+
- streamlit
|
| 14 |
+
- education
|
| 15 |
+
---
|
| 16 |
+
|
| 17 |
# BattleWords
|
| 18 |
+
|
| 19 |
+
> **This project is used by [huggingface.co](https://huggingface.co/spaces/Surn/BattleWords) as a demonstration of interactive word games in Python.**
|
| 20 |
+
|
| 21 |
+
BattleWords is a vocabulary learning game inspired by classic Battleship mechanics. The objective is to discover hidden words on a grid, earning points for strategic guessing before all letters are revealed.
|
| 22 |
+
|
| 23 |
+
## Features
|
| 24 |
+
|
| 25 |
+
- 12x12 grid with six hidden words (2x4-letter, 2x5-letter, 2x6-letter)
|
| 26 |
+
- Words placed horizontally or vertically
|
| 27 |
+
- Radar visualization to help locate word boundaries
|
| 28 |
+
- Reveal grid cells and guess words for points
|
| 29 |
+
- Scoring tiers: Good (34–37), Great (38–41), Fantastic (42+)
|
| 30 |
+
- Responsive UI built with Streamlit
|
| 31 |
+
- Deterministic seed support (Beta/Full)
|
| 32 |
+
- Keyboard navigation and guessing (Beta/Full)
|
| 33 |
+
- Overlapping words on shared letters (Beta)
|
| 34 |
+
- Daily and practice modes (Full)
|
| 35 |
+
- Leaderboards, persistence, and advanced features (Full)
|
| 36 |
+
|
| 37 |
+
## Installation
|
| 38 |
+
1. Clone the repository:
|
| 39 |
+
```
|
| 40 |
+
git clone
|
| 41 |
+
cd battlewords
|
| 42 |
+
```
|
| 43 |
+
2. (Optional) Create and activate a virtual environment:
|
| 44 |
+
```
|
| 45 |
+
python -m venv venv
|
| 46 |
+
source venv/bin/activate # On Windows use `venv\Scripts\activate`
|
| 47 |
+
```
|
| 48 |
+
3. Install dependencies:
|
| 49 |
+
```
|
| 50 |
+
pip install -r specs/requirements.md
|
| 51 |
+
```
|
| 52 |
+
|
| 53 |
+
|
| 54 |
+
## Running BattleWords
|
| 55 |
+
|
| 56 |
+
You can run the app locally using either [uv](https://github.com/astral-sh/uv) or Streamlit directly:
|
| 57 |
+
|
| 58 |
+
```
|
| 59 |
+
uv run streamlit run app.py
|
| 60 |
+
```
|
| 61 |
+
|
| 62 |
+
or
|
| 63 |
+
```
|
| 64 |
+
streamlit run app.py
|
| 65 |
+
```
|
| 66 |
+
|
| 67 |
+
## Folder Structure
|
| 68 |
+
|
| 69 |
+
- `app.py` – Streamlit entry point
|
| 70 |
+
- `battlewords/` – Python package
|
| 71 |
+
- `models.py` – data models and types
|
| 72 |
+
- `word_loader.py` – word list loading and validation
|
| 73 |
+
- `generator.py` – word placement logic
|
| 74 |
+
- `logic.py` – game mechanics (reveal, guess, scoring)
|
| 75 |
+
- `ui.py` – Streamlit UI composition
|
| 76 |
+
- `words/wordlist.txt` – candidate words
|
| 77 |
+
- `specs/` – documentation (`specs.md`, `requirements.md`)
|
| 78 |
+
- `tests/` – unit tests
|
| 79 |
+
|
| 80 |
+
## How to Play
|
| 81 |
+
|
| 82 |
+
1. Click grid squares to reveal letters or empty spaces.
|
| 83 |
+
2. After revealing a letter, enter a guess for a word in the text box.
|
| 84 |
+
3. Earn points for correct guesses and bonus points for unrevealed letters.
|
| 85 |
+
4. The game ends when all six words are found. Your score tier is displayed.
|
| 86 |
+
|
| 87 |
+
## Development Phases
|
| 88 |
+
|
| 89 |
+
- **Proof of Concept (0.1.0):** No overlaps, basic UI, single session.
|
| 90 |
+
- **Beta (0.5.0):** Overlaps allowed on shared letters, responsive layout, keyboard support, deterministic seed.
|
| 91 |
+
- **Full (1.0.0):** Enhanced UX, persistence, leaderboards, daily/practice modes, advanced features.
|
| 92 |
+
|
| 93 |
+
See `specs/requirements.md` and `specs/specs.md` for full details and roadmap.
|
| 94 |
+
|
| 95 |
+
## License
|
| 96 |
+
|
| 97 |
+
BattlewordsTM. All Rights Reserved. All content, trademarks and logos are copyrighted by the owner.
|
| 98 |
+
|
| 99 |
+
## Hugging Face Spaces Configuration
|
| 100 |
+
|
| 101 |
+
BattleWords is deployable as a Hugging Face Space. To configure your Space, add a YAML block at the top of your `README.md`:
|
| 102 |
+
|
| 103 |
+
```yaml
|
| 104 |
+
---
|
| 105 |
+
title: BattleWords
|
| 106 |
+
emoji: 🎲
|
| 107 |
+
colorFrom: blue
|
| 108 |
+
colorTo: indigo
|
| 109 |
+
sdk: streamlit
|
| 110 |
+
sdk_version: 1.25.0
|
| 111 |
+
python_version: 3.10
|
| 112 |
+
app_file: app.py
|
| 113 |
+
tags:
|
| 114 |
+
- game
|
| 115 |
+
- vocabulary
|
| 116 |
+
- streamlit
|
| 117 |
+
- education
|
| 118 |
+
---
|
| 119 |
+
```
|
| 120 |
+
|
| 121 |
+
**Key parameters:**
|
| 122 |
+
- `title`, `emoji`, `colorFrom`, `colorTo`: Visuals for your Space.
|
| 123 |
+
- `sdk`: Use `streamlit` for Streamlit apps.
|
| 124 |
+
- `sdk_version`: Latest supported Streamlit version.
|
| 125 |
+
- `python_version`: Python version (default is 3.10).
|
| 126 |
+
- `app_file`: Entry point for your app.
|
| 127 |
+
- `tags`: List of descriptive tags.
|
| 128 |
+
|
| 129 |
+
**Dependencies:**
|
| 130 |
+
Add a `requirements.txt` with your Python dependencies (e.g., `streamlit`, etc.).
|
| 131 |
+
|
| 132 |
+
**Port:**
|
| 133 |
+
Streamlit Spaces use port `8501` by default.
|
| 134 |
+
|
| 135 |
+
**Embedding:**
|
| 136 |
+
Spaces can be embedded in other sites using an `<iframe>`:
|
| 137 |
+
|
| 138 |
+
```html
|
| 139 |
+
<iframe src="https://Surn-BattleWords.hf.space?embed=true" title="BattleWords"></iframe>
|
| 140 |
+
```
|
| 141 |
+
|
| 142 |
+
For full configuration options, see [Spaces Config Reference](https://huggingface.co/docs/hub/spaces-config-reference) and [Streamlit SDK Guide](https://huggingface.co/docs/hub/spaces-sdks-streamlit).
|
| 143 |
+
|
specs/requirements.md
CHANGED
|
@@ -1,11 +1,12 @@
|
|
| 1 |
# Battlewords: Implementation Requirements
|
| 2 |
|
| 3 |
-
This document breaks down the tasks to build Battlewords using the game rules described in `specs.md`. It is organized in phases: a minimal Proof of Concept (POC)
|
| 4 |
|
| 5 |
Assumptions
|
| 6 |
-
- Tech stack: Python 3.10+, Streamlit for UI,
|
| 7 |
- Single-player, local state stored in Streamlit session state for POC.
|
| 8 |
-
- Grid is always 12x12 with exactly six words: two 4-letter, two 5-letter, two 6-letter words; horizontal/vertical only; no shared letters or overlaps.
|
|
|
|
| 9 |
|
| 10 |
Streamlit key components (API usage plan)
|
| 11 |
- State & caching
|
|
@@ -22,22 +23,24 @@ Streamlit key components (API usage plan)
|
|
| 22 |
- `st.metric` to show score; `st.checkbox`/`st.toggle` for optional settings (e.g., show radar).
|
| 23 |
- Visualization
|
| 24 |
- `st.pyplot` for the radar mini-grid (scatter on a 12×12 axes) or `st.plotly_chart` if interactive.
|
|
|
|
| 25 |
- Control flow
|
| 26 |
-
- App reruns on interaction;
|
| 27 |
|
| 28 |
Folder Structure
|
| 29 |
- `app.py` – Streamlit entry point
|
| 30 |
- `battlewords/` – Python package
|
| 31 |
- `__init__.py`
|
| 32 |
- `models.py` – data models and types
|
| 33 |
-
- `
|
| 34 |
-
- `
|
| 35 |
-
- `
|
|
|
|
| 36 |
- `words/wordlist.txt` – candidate words
|
| 37 |
-
- `specs/` – documentation (
|
| 38 |
-
- `tests/` – unit tests
|
| 39 |
|
| 40 |
-
Phase 1: Proof of Concept
|
| 41 |
Goal: A playable, single-session game demonstrating core rules, scoring, and radar without persistence or advanced UX.
|
| 42 |
|
| 43 |
1) Data Models
|
|
@@ -52,32 +55,32 @@ Acceptance: Types exist and are consumed by generator/logic; simple constructors
|
|
| 52 |
- Add an English word list filtered to alphabetic uppercase, lengths in {4,5,6}.
|
| 53 |
- Ensure words contain no special characters; maintain reasonable difficulty.
|
| 54 |
- Streamlit: `st.cache_data` to memoize loading/filtering.
|
|
|
|
| 55 |
|
| 56 |
Acceptance: Loading function returns lists by length with >= 500 words per length or fallback minimal lists.
|
| 57 |
|
| 58 |
3) Puzzle Generation (Placement)
|
| 59 |
- Randomly place 2×4, 2×5, 2×6 letter words on a 12×12 grid.
|
| 60 |
-
- Constraints:
|
| 61 |
- Horizontal (left→right) or Vertical (top→down) only.
|
| 62 |
-
- No overlapping letters.
|
| 63 |
-
- No shared letters between different words (cells must be unique; letters adjacent orthogonally are allowed).
|
| 64 |
- Compute radar pulses as the last cell of each word.
|
| 65 |
- Retry strategy with max attempts; raise a controlled error if generation fails.
|
| 66 |
|
| 67 |
-
Acceptance: Generator returns a valid `Puzzle` passing validation checks (no collisions, in-bounds, correct counts).
|
| 68 |
|
| 69 |
4) Game Mechanics
|
| 70 |
- Reveal:
|
| 71 |
-
- Click a covered cell to reveal; if the cell is part of a word, show the letter; else mark empty.
|
| 72 |
- After a reveal action, set `can_guess=True`.
|
| 73 |
-
- Streamlit: 12×12 `st.columns` + `st.button(label, key=f"cell_{r}_{c}")` per cell; on click, update `st.session_state` and
|
| 74 |
- Guess:
|
| 75 |
- Accept a guess only if `can_guess` is True and input length ∈ {4,5,6}.
|
| 76 |
- Match guess case-insensitively against unguessed words in puzzle.
|
| 77 |
- If correct: add base points = word length; bonus points = count of unrevealed cells in that word at guess time; mark all cells of the word as revealed; add to `guessed`.
|
| 78 |
- If incorrect: no points awarded.
|
| 79 |
- After any guess, set `can_guess=False` and require another reveal before next guess.
|
| 80 |
-
- Streamlit: `with st.form("guess"):` + `st.text_input("Your guess", key="guess_text")` + `st.form_submit_button("OK", disabled=not st.session_state.can_guess)`.
|
| 81 |
- End of game when all 6 words are guessed; display summary and tier, then `st.stop()`.
|
| 82 |
|
| 83 |
Acceptance: Unit tests cover scoring, guess gating, and reveal behavior.
|
|
@@ -89,11 +92,11 @@ Acceptance: Unit tests cover scoring, guess gating, and reveal behavior.
|
|
| 89 |
- Right: Radar mini-grid via `st.pyplot` (matplotlib scatter) or `st.plotly_chart`.
|
| 90 |
- Bottom/right: Guess form using `st.form`, `st.text_input`, `st.form_submit_button`.
|
| 91 |
- Score panel showing current score using `st.metric` and `st.markdown` for last action.
|
| 92 |
-
- Optional `st.sidebar` to host reset/new game and settings.
|
| 93 |
- Visuals:
|
| 94 |
-
- Covered cell vs revealed styles: use button labels/emojis and background color hints;
|
| 95 |
|
| 96 |
-
Acceptance: Users can play end-to-end in one session; UI updates consistently; radar shows exactly 6 pulses.
|
| 97 |
|
| 98 |
6) Scoring Tiers
|
| 99 |
- After game ends, compute tier:
|
|
@@ -107,13 +110,37 @@ Acceptance: Tier text shown at game end; manual test with mocked states.
|
|
| 107 |
|
| 108 |
7) Basic Tests
|
| 109 |
- Unit tests for:
|
| 110 |
-
- Placement validity (bounds, overlap, counts).
|
| 111 |
- Scoring logic and bonus calculation.
|
| 112 |
- Guess gating (must reveal before next guess).
|
| 113 |
|
| 114 |
Acceptance: Tests run and pass locally.
|
| 115 |
|
| 116 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 117 |
Goal: Robust app with polish, persistence, test coverage, and optional advanced features.
|
| 118 |
|
| 119 |
A) UX and Visual Polish
|
|
@@ -185,9 +212,7 @@ J) Deployment
|
|
| 185 |
|
| 186 |
Milestones and Estimates (High-level)
|
| 187 |
- Phase 1 (POC): 2–4 days
|
| 188 |
-
|
| 189 |
-
- UI + scoring + radar: 1 day
|
| 190 |
-
- Tests and polish: 0.5–1 day
|
| 191 |
- Phase 2 (Full): 1–2 weeks depending on features selected
|
| 192 |
|
| 193 |
Definitions of Done (per task)
|
|
|
|
| 1 |
# Battlewords: Implementation Requirements
|
| 2 |
|
| 3 |
+
This document breaks down the tasks to build Battlewords using the game rules described in `specs.md`. It is organized in phases: a minimal Proof of Concept (POC), a Beta Version (0.5.0), and a Full Version (1.0.0).
|
| 4 |
|
| 5 |
Assumptions
|
| 6 |
+
- Tech stack: Python 3.10+, Streamlit for UI, matplotlib for radar, numpy for tick helpers.
|
| 7 |
- Single-player, local state stored in Streamlit session state for POC.
|
| 8 |
+
- Grid is always 12x12 with exactly six words: two 4-letter, two 5-letter, two 6-letter words; horizontal/vertical only; no shared letters or overlaps in POC; shared-letter overlaps allowed in Beta; no overlaps in Full.
|
| 9 |
+
- Entry point is `app.py`.
|
| 10 |
|
| 11 |
Streamlit key components (API usage plan)
|
| 12 |
- State & caching
|
|
|
|
| 23 |
- `st.metric` to show score; `st.checkbox`/`st.toggle` for optional settings (e.g., show radar).
|
| 24 |
- Visualization
|
| 25 |
- `st.pyplot` for the radar mini-grid (scatter on a 12×12 axes) or `st.plotly_chart` if interactive.
|
| 26 |
+
- Radar plot uses `ax.set_ylim(size, 0)` to invert Y so (0,0) is top-left.
|
| 27 |
- Control flow
|
| 28 |
+
- App reruns on interaction; uses `st.rerun()` after state changes (reveal, guess); `st.stop()` after game over summary to freeze UI.
|
| 29 |
|
| 30 |
Folder Structure
|
| 31 |
- `app.py` – Streamlit entry point
|
| 32 |
- `battlewords/` – Python package
|
| 33 |
- `__init__.py`
|
| 34 |
- `models.py` – data models and types
|
| 35 |
+
- `word_loader.py` – load/validate/cached word lists (uses `battlewords/words/wordlist.txt` with fallback)
|
| 36 |
+
- `generator.py` – word placement; imports from `word_loader`; avoids duplicate words
|
| 37 |
+
- `logic.py` – game mechanics (reveal, guess, scoring, tiers)
|
| 38 |
+
- `ui.py` – Streamlit UI composition; immediate rerender on reveal/guess via `st.rerun()`; inverted radar Y
|
| 39 |
- `words/wordlist.txt` – candidate words
|
| 40 |
+
- `specs/` – documentation (this file and `specs.md`)
|
| 41 |
+
- `tests/` – unit tests (optional for now)
|
| 42 |
|
| 43 |
+
Phase 1: Proof of Concept (0.1.0)
|
| 44 |
Goal: A playable, single-session game demonstrating core rules, scoring, and radar without persistence or advanced UX.
|
| 45 |
|
| 46 |
1) Data Models
|
|
|
|
| 55 |
- Add an English word list filtered to alphabetic uppercase, lengths in {4,5,6}.
|
| 56 |
- Ensure words contain no special characters; maintain reasonable difficulty.
|
| 57 |
- Streamlit: `st.cache_data` to memoize loading/filtering.
|
| 58 |
+
- Loader is centralized in `word_loader.py` and used by generator and UI.
|
| 59 |
|
| 60 |
Acceptance: Loading function returns lists by length with >= 500 words per length or fallback minimal lists.
|
| 61 |
|
| 62 |
3) Puzzle Generation (Placement)
|
| 63 |
- Randomly place 2×4, 2×5, 2×6 letter words on a 12×12 grid.
|
| 64 |
+
- Constraints (POC):
|
| 65 |
- Horizontal (left→right) or Vertical (top→down) only.
|
| 66 |
+
- No overlapping letters between different words (cells must be unique).
|
|
|
|
| 67 |
- Compute radar pulses as the last cell of each word.
|
| 68 |
- Retry strategy with max attempts; raise a controlled error if generation fails.
|
| 69 |
|
| 70 |
+
Acceptance: Generator returns a valid `Puzzle` passing validation checks (no collisions, in-bounds, correct counts, no duplicates).
|
| 71 |
|
| 72 |
4) Game Mechanics
|
| 73 |
- Reveal:
|
| 74 |
+
- Click a covered cell to reveal; if the cell is part of a word, show the letter; else mark empty (CSS class `empty`).
|
| 75 |
- After a reveal action, set `can_guess=True`.
|
| 76 |
+
- Streamlit: 12×12 `st.columns` + `st.button(label, key=f"cell_{r}_{c}")` per cell; on click, update `st.session_state` and call `st.rerun()`.
|
| 77 |
- Guess:
|
| 78 |
- Accept a guess only if `can_guess` is True and input length ∈ {4,5,6}.
|
| 79 |
- Match guess case-insensitively against unguessed words in puzzle.
|
| 80 |
- If correct: add base points = word length; bonus points = count of unrevealed cells in that word at guess time; mark all cells of the word as revealed; add to `guessed`.
|
| 81 |
- If incorrect: no points awarded.
|
| 82 |
- After any guess, set `can_guess=False` and require another reveal before next guess.
|
| 83 |
+
- Streamlit: `with st.form("guess"):` + `st.text_input("Your guess", key="guess_text")` + `st.form_submit_button("OK", disabled=not st.session_state.can_guess)`; after guess, call `st.rerun()`.
|
| 84 |
- End of game when all 6 words are guessed; display summary and tier, then `st.stop()`.
|
| 85 |
|
| 86 |
Acceptance: Unit tests cover scoring, guess gating, and reveal behavior.
|
|
|
|
| 92 |
- Right: Radar mini-grid via `st.pyplot` (matplotlib scatter) or `st.plotly_chart`.
|
| 93 |
- Bottom/right: Guess form using `st.form`, `st.text_input`, `st.form_submit_button`.
|
| 94 |
- Score panel showing current score using `st.metric` and `st.markdown` for last action.
|
| 95 |
+
- Optional `st.sidebar` to host reset/new game and settings; shows word list source/counts.
|
| 96 |
- Visuals:
|
| 97 |
+
- Covered cell vs revealed styles: use button labels/emojis and background color hints; revealed empty cells use CSS class `empty` for background.
|
| 98 |
|
| 99 |
+
Acceptance: Users can play end-to-end in one session; UI updates consistently; radar shows exactly 6 pulses; single-click reveal and guess update via rerun.
|
| 100 |
|
| 101 |
6) Scoring Tiers
|
| 102 |
- After game ends, compute tier:
|
|
|
|
| 110 |
|
| 111 |
7) Basic Tests
|
| 112 |
- Unit tests for:
|
| 113 |
+
- Placement validity (bounds, overlap, counts, no duplicate words).
|
| 114 |
- Scoring logic and bonus calculation.
|
| 115 |
- Guess gating (must reveal before next guess).
|
| 116 |
|
| 117 |
Acceptance: Tests run and pass locally.
|
| 118 |
|
| 119 |
+
Beta Version (0.5.0)
|
| 120 |
+
Goal: Introduce overlapping words on shared letters, improve UX responsiveness and input options, and add deterministic seeding.
|
| 121 |
+
|
| 122 |
+
A) Generator and Validation
|
| 123 |
+
- Allow shared-letter overlaps: words may cross on the same letter; still disallow conflicting letters on the same cell.
|
| 124 |
+
- Optional validation pass to detect and avoid unintended adjacent partial words (content curation rule).
|
| 125 |
+
- Deterministic seed support to reproduce puzzles (e.g., daily seed derived from date).
|
| 126 |
+
Acceptance:
|
| 127 |
+
- Placement permits shared-letter crossings only when letters match.
|
| 128 |
+
- With a fixed seed/date, the same puzzle is produced.
|
| 129 |
+
|
| 130 |
+
B) UI and Interaction
|
| 131 |
+
- Cell rendering with consistent sizing and responsive layout (desktop/mobile).
|
| 132 |
+
- Keyboard support for grid navigation and guessing (custom JS via `st.html` or component).
|
| 133 |
+
- Maintain radar behavior and scoring rules.
|
| 134 |
+
Acceptance:
|
| 135 |
+
- Grid scales cleanly across typical desktop and mobile widths.
|
| 136 |
+
- Users can enter guesses and move focus via keyboard.
|
| 137 |
+
|
| 138 |
+
C) Tests
|
| 139 |
+
- Property checks for overlap validity (only same letters may share a cell).
|
| 140 |
+
- Seed reproducibility tests (same seed → identical placements).
|
| 141 |
+
- Optional validation tests for adjacency curation (when enabled).
|
| 142 |
+
|
| 143 |
+
Phase 2: Full Version (1.0.0)
|
| 144 |
Goal: Robust app with polish, persistence, test coverage, and optional advanced features.
|
| 145 |
|
| 146 |
A) UX and Visual Polish
|
|
|
|
| 212 |
|
| 213 |
Milestones and Estimates (High-level)
|
| 214 |
- Phase 1 (POC): 2–4 days
|
| 215 |
+
- Beta (0.5.0): 3–5 days (overlaps, responsive UI, keyboard, deterministic seed)
|
|
|
|
|
|
|
| 216 |
- Phase 2 (Full): 1–2 weeks depending on features selected
|
| 217 |
|
| 218 |
Definitions of Done (per task)
|
specs/specs.md
CHANGED
|
@@ -10,14 +10,15 @@ Battlewords is inspired by the classic Battleship game, but uses words instead o
|
|
| 10 |
- Two five-letter words
|
| 11 |
- Two six-letter words
|
| 12 |
- Words are placed horizontally (left-right) or vertically (top-down), not diagonally.
|
| 13 |
-
-
|
| 14 |
-
- Radar screen indicates the location of the last letter of each word.
|
| 15 |
|
| 16 |
-
## Gameplay
|
| 17 |
- Players click grid squares to reveal letters or empty spaces.
|
| 18 |
-
-
|
|
|
|
| 19 |
- Use radar pulses to locate word boundaries (first and last letters).
|
| 20 |
- After revealing a letter, players may guess a word by entering it in a text box.
|
|
|
|
| 21 |
- Only one guess per letter reveal; must uncover another letter before guessing again.
|
| 22 |
|
| 23 |
## Scoring
|
|
@@ -29,16 +30,42 @@ Battlewords is inspired by the classic Battleship game, but uses words instead o
|
|
| 29 |
- Great: 38-41
|
| 30 |
- Fantastic: 42+
|
| 31 |
|
| 32 |
-
##
|
| 33 |
-
-
|
| 34 |
-
-
|
| 35 |
-
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 36 |
|
| 37 |
## UI Elements
|
| 38 |
- 12x12 grid
|
| 39 |
-
- Radar screen (shows last letter locations)
|
| 40 |
- Text box for word guesses
|
| 41 |
- Score display (shows word, base points, bonus points, total score)
|
| 42 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 43 |
## Copyright
|
| 44 |
BattlewordsTM. All Rights Reserved. All content, trademarks and logos are copyrighted by the owner.
|
|
|
|
| 10 |
- Two five-letter words
|
| 11 |
- Two six-letter words
|
| 12 |
- Words are placed horizontally (left-right) or vertically (top-down), not diagonally.
|
| 13 |
+
- Entry point is `app.py`.
|
|
|
|
| 14 |
|
| 15 |
+
## Gameplay (Common)
|
| 16 |
- Players click grid squares to reveal letters or empty spaces.
|
| 17 |
+
- Empty revealed squares are styled with CSS class `empty`.
|
| 18 |
+
- After any reveal, the app immediately reruns (`st.rerun`) to show the change.
|
| 19 |
- Use radar pulses to locate word boundaries (first and last letters).
|
| 20 |
- After revealing a letter, players may guess a word by entering it in a text box.
|
| 21 |
+
- Guess submission triggers an immediate rerun to reflect results.
|
| 22 |
- Only one guess per letter reveal; must uncover another letter before guessing again.
|
| 23 |
|
| 24 |
## Scoring
|
|
|
|
| 30 |
- Great: 38-41
|
| 31 |
- Fantastic: 42+
|
| 32 |
|
| 33 |
+
## POC (0.1.0) Rules
|
| 34 |
+
- No overlaps: words do not overlap or share letters.
|
| 35 |
+
- UI: basic grid, radar, and guess form.
|
| 36 |
+
- No keyboard interaction requirement.
|
| 37 |
+
- Seed is optional and not standardized.
|
| 38 |
+
|
| 39 |
+
## Beta (0.5.0) Additions
|
| 40 |
+
- Overlaps allowed on shared letters: words may cross only where letters match; still forbid conflicting letters in the same cell.
|
| 41 |
+
- Optional validation pass to avoid unintended adjacent partial words (content curation rule).
|
| 42 |
+
- Cell rendering with consistent sizing and responsive layout (desktop/mobile).
|
| 43 |
+
- Keyboard support for navigation and guessing (custom JS via `st.html` or a component).
|
| 44 |
+
- Deterministic seed support to reproduce puzzles (e.g., daily seed derived from date).
|
| 45 |
+
|
| 46 |
+
## Full (1.0.0) Rules
|
| 47 |
+
- No overlaps: words do not overlap or share letters.
|
| 48 |
+
- Enhanced UX polish (animations, accessibility, themes).
|
| 49 |
+
- Persistence, leaderboards, and additional modes as specified in requirements.
|
| 50 |
+
- Deterministic daily mode and practice mode supported.
|
| 51 |
|
| 52 |
## UI Elements
|
| 53 |
- 12x12 grid
|
| 54 |
+
- Radar screen (shows last letter locations); y-axis inverted so (0,0) is top-left
|
| 55 |
- Text box for word guesses
|
| 56 |
- Score display (shows word, base points, bonus points, total score)
|
| 57 |
|
| 58 |
+
## Word List
|
| 59 |
+
- External list at `battlewords/words/wordlist.txt`.
|
| 60 |
+
- Loaded by `battlewords.word_loader.load_word_list()` with caching.
|
| 61 |
+
- Filtered to uppercase A�Z, lengths in {4,5,6}; falls back if < 500 per length.
|
| 62 |
+
|
| 63 |
+
## Generator
|
| 64 |
+
- Centralized word loader.
|
| 65 |
+
- No duplicate word texts are selected.
|
| 66 |
+
|
| 67 |
+
## Entry Point
|
| 68 |
+
- The Streamlit entry point is `app.py`.
|
| 69 |
+
|
| 70 |
## Copyright
|
| 71 |
BattlewordsTM. All Rights Reserved. All content, trademarks and logos are copyrighted by the owner.
|