Surn commited on
Commit
3666fb8
Β·
1 Parent(s): f4f5889

Documentation Update

Browse files
Files changed (4) hide show
  1. README.md +22 -0
  2. requirements.txt +1 -0
  3. specs/requirements.md +47 -40
  4. specs/specs.md +0 -1
README.md CHANGED
@@ -28,6 +28,7 @@ BattleWords is a vocabulary learning game inspired by classic Battleship mechani
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)
@@ -85,6 +86,27 @@ streamlit run app.py
85
  3. Earn points for correct guesses and bonus points for unrevealed letters.
86
  4. **The game ends when all six words are found or all word letters are revealed. Your score tier is displayed.**
87
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
88
  ## Development Phases
89
 
90
  - **Proof of Concept (0.1.0):** No overlaps, basic UI, single session.
 
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
+ - Wordlist sidebar controls (picker + one-click sort)
32
  - Deterministic seed support (Beta/Full)
33
  - Keyboard navigation and guessing (Beta/Full)
34
  - Overlapping words on shared letters (Beta)
 
86
  3. Earn points for correct guesses and bonus points for unrevealed letters.
87
  4. **The game ends when all six words are found or all word letters are revealed. Your score tier is displayed.**
88
 
89
+ ## Changelog
90
+
91
+ - 0.1.5
92
+ - Hit/Miss circular indicator.
93
+ - Completed words render as non-interactive styled cells.
94
+ - Tooltips show cell coordinates for buttons and revealed cells.
95
+ - Stable letter map rebuild after reveals.
96
+
97
+ - 0.1.4
98
+ - Radar rewritten as an animated GIF with metallic gradient background and scope overlay.
99
+ - Session-level caching of the generated radar GIF to avoid regeneration during a session.
100
+ - Mobile layout improvements: radar above grid on small screens; tighter grid gaps and horizontal scrolling per row.
101
+
102
+ - 0.1.3
103
+ - Sidebar wordlist picker and `Sort Wordlist` action (length-first then alphabetic) with a 5-second feedback delay before restarting a new game.
104
+ - Score panel improvements, per-word points, and emphasized final score styling.
105
+
106
+ ## Known Issues / TODO
107
+
108
+ - Word list loading bug: the app may not select the proper word lists in some environments. Investigate `word_loader.get_wordlist_files()` / `load_word_list()` and sidebar selection persistence to ensure the chosen file is correctly used by the generator.
109
+
110
  ## Development Phases
111
 
112
  - **Proof of Concept (0.1.0):** No overlaps, basic UI, single session.
requirements.txt CHANGED
@@ -3,6 +3,7 @@ pandas
3
  streamlit
4
  matplotlib
5
  numpy
 
6
  pytest
7
  flake8
8
  mypy
 
3
  streamlit
4
  matplotlib
5
  numpy
6
+ Pillow
7
  pytest
8
  flake8
9
  mypy
specs/requirements.md CHANGED
@@ -3,14 +3,18 @@
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
13
- - `st.session_state` for `puzzle`, `revealed`, `guessed`, `score`, `can_guess`, `last_action`.
 
 
 
 
14
  - `st.cache_data` to load and filter the word list.
15
  - Layout & structure
16
  - `st.title`, `st.subheader`, `st.markdown` for headers/instructions.
@@ -18,12 +22,13 @@ Streamlit key components (API usage plan)
18
  - `st.expander` for inline help/intel tips.
19
  - Widgets (interaction)
20
  - `st.button` for each grid cell (144 total) with unique `key` to handle reveals.
21
- - `st.form` + `st.text_input` + `st.form_submit_button("OK")` for controlled word guessing.
22
- - `st.button("New Game")` or `st.link_button` to reset state.
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
 
@@ -35,10 +40,10 @@ Folder Structure
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.
@@ -73,59 +78,61 @@ Acceptance: Generator returns a valid `Puzzle` passing validation checks (no col
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 or all word letters are revealed; display summary and tier, then `st.stop()`.**
 
85
 
86
  Acceptance: Unit tests cover scoring, guess gating, and reveal behavior.
87
 
88
  5) UI (Streamlit)
89
  - Layout:
90
  - Title and brief instructions via `st.title`, `st.subheader`, `st.markdown`.
91
- - Left: 12Γ—12 grid using `st.columns(12)` of `st.button`s.
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:
103
  - Good: 34–37
104
  - Great: 38–41
105
  - Fantastic: 42+
106
- - Display final summary with found words, per-word points, total.
107
- - Streamlit: show results in a `st.container` or `st.expander("Game summary")`.
108
-
109
- Acceptance: Tier text shown at game end; manual test with mocked states.
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).
 
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, Pillow for animated GIFs.
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
13
+ - `st.session_state` for `puzzle`, `grid_size`, `revealed`, `guessed`, `score`, `last_action`, `can_guess`.
14
+ - `st.session_state.points_by_word` for per-word score breakdown.
15
+ - `st.session_state.letter_map` derived from puzzle.
16
+ - `st.session_state.selected_wordlist` for sidebar picker.
17
+ - `st.session_state.radar_gif_path` for session-persistent radar animation.
18
  - `st.cache_data` to load and filter the word list.
19
  - Layout & structure
20
  - `st.title`, `st.subheader`, `st.markdown` for headers/instructions.
 
22
  - `st.expander` for inline help/intel tips.
23
  - Widgets (interaction)
24
  - `st.button` for each grid cell (144 total) with unique `key` to handle reveals.
25
+ - `st.form` + `st.text_input` + `st.form_submit_button("OK")` for controlled word guessing (disabled until a reveal).
26
+ - `st.button("New Game")` to reset state; sidebar `selectbox` for wordlist selection and `Sort Wordlist` button (length+alpha).
27
+ - `st.metric` to show score.
28
  - Visualization
29
+ - Animated radar using matplotlib `FuncAnimation` + `PillowWriter` saved to GIF.
30
+ - Scope overlay image generated once and reused; metallic gradient background.
31
+ - Radar plot uses inverted Y so (0,0) is top-left.
32
  - Control flow
33
  - App reruns on interaction; uses `st.rerun()` after state changes (reveal, guess); `st.stop()` after game over summary to freeze UI.
34
 
 
40
  - `word_loader.py` – load/validate/cached word lists (uses `battlewords/words/wordlist.txt` with fallback)
41
  - `generator.py` – word placement; imports from `word_loader`; avoids duplicate words
42
  - `logic.py` – game mechanics (reveal, guess, scoring, tiers)
43
+ - `ui.py` – Streamlit UI composition; animated radar; immediate rerender on reveal/guess via `st.rerun()`; inverted radar Y
44
  - `words/wordlist.txt` – candidate words
45
  - `specs/` – documentation (this file and `specs.md`)
46
+ - `tests/` – unit tests
47
 
48
  Phase 1: Proof of Concept (0.1.0)
49
  Goal: A playable, single-session game demonstrating core rules, scoring, and radar without persistence or advanced UX.
 
78
  - Reveal:
79
  - Click a covered cell to reveal; if the cell is part of a word, show the letter; else mark empty (CSS class `empty`).
80
  - After a reveal action, set `can_guess=True`.
 
81
  - Guess:
82
  - Accept a guess only if `can_guess` is True and input length ∈ {4,5,6}.
83
  - Match guess case-insensitively against unguessed words in puzzle.
84
  - 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`.
85
  - If incorrect: no points awarded.
86
  - After any guess, set `can_guess=False` and require another reveal before next guess.
87
+ - Exception in 0.1.5: after a correct guess, another guess is allowed without a reveal (`can_guess=True`).
88
+ - Streamlit: `with st.form("guess"):` + `st.text_input("Your guess")` + `st.form_submit_button("OK", disabled=not can_guess)`; after guess, call `st.rerun()`.
89
+ - End of game when all 6 words are guessed or all word letters are revealed; display summary and tier, then `st.stop()`.
90
 
91
  Acceptance: Unit tests cover scoring, guess gating, and reveal behavior.
92
 
93
  5) UI (Streamlit)
94
  - Layout:
95
  - Title and brief instructions via `st.title`, `st.subheader`, `st.markdown`.
96
+ - Left: 12Γ—12 grid using `st.columns(12)`.
97
+ - Right: Animated radar, Hit/Miss indicator, guess form, and score panel.
98
+ - Sidebar: New Game, wordlist selectbox, Sort Wordlist action.
 
 
99
  - Visuals:
100
+ - Covered vs revealed styles; revealed empty cells use CSS class `empty`.
101
+ - Completed word cells styled with `bw-cell-complete`; cell tooltips show coordinates.
102
 
103
+ Acceptance: Users can play end-to-end; radar shows exactly 6 pulses; reveal and guess update via rerun; completed words are visually distinct.
104
 
105
  6) Scoring Tiers
106
  - After game ends, compute tier:
107
  - Good: 34–37
108
  - Great: 38–41
109
  - Fantastic: 42+
 
 
 
 
110
 
111
  7) Basic Tests
112
+ - Placement validity (bounds, overlap, counts, no duplicate words).
113
+ - Scoring logic and bonus calculation.
114
+ - Guess gating (reveal required except chaining after correct guess).
115
+
116
+ Current Deltas (0.1.3 β†’ 0.1.5)
117
+ - 0.1.3
118
+ - Sidebar wordlist select; sorting persists length-then-alpha ordering; auto new-game after 5s notice.
119
+ - Score panel improvements; per-word points; final score styling.
120
+ - 0.1.4
121
+ - Animated radar GIF with metallic gradient and scope overlay; session reuse via `radar_gif_path`.
122
+ - Mobile layout improvements; tighter grid spacing and horizontal scroll per row.
123
+ - 0.1.5
124
+ - Hit/Miss indicator derived from `last_action`.
125
+ - Completed word cells render as non-buttons with tooltips.
126
+ - Helper functions for scope image and stable letter map rebuild.
127
+
128
+ Known Issues / TODO
129
+ - Word list selection bug: improper list fetched/propagated in some runs.
130
+ - Verify `get_wordlist_files()` returns correct filenames and `selected_wordlist` persists across `_new_game()`.
131
+ - Ensure `load_word_list(selected_wordlist)` loads the chosen file and matches `generate_puzzle(words_by_len=...)` expected shape.
132
+ - Add tests for selection, sorting, and fallback behavior.
133
+
134
+ Beta (0.5.0) – Planned
135
+ - Allow shared-letter overlaps when letters match; deterministic seeding; keyboard navigation.
136
 
137
  B) UI and Interaction
138
  - Cell rendering with consistent sizing and responsive layout (desktop/mobile).
specs/specs.md CHANGED
@@ -39,7 +39,6 @@ Battlewords is inspired by the classic Battleship game, but uses words instead o
39
  - Seed is optional and not standardized.
40
 
41
  ## Beta (0.5.0) Additions
42
- - Overlaps allowed on shared letters: words may cross only where letters match; still forbid conflicting letters in the same cell.
43
  - Optional validation pass to avoid unintended adjacent partial words (content curation rule).
44
  - Cell rendering with consistent sizing and responsive layout (desktop/mobile).
45
  - Keyboard support for navigation and guessing (custom JS via `st.html` or a component).
 
39
  - Seed is optional and not standardized.
40
 
41
  ## Beta (0.5.0) Additions
 
42
  - Optional validation pass to avoid unintended adjacent partial words (content curation rule).
43
  - Cell rendering with consistent sizing and responsive layout (desktop/mobile).
44
  - Keyboard support for navigation and guessing (custom JS via `st.html` or a component).