Spaces:
Running
Running
File size: 12,357 Bytes
d747bc4 032159d d747bc4 032159d d747bc4 032159d d747bc4 032159d d747bc4 032159d d747bc4 032159d d747bc4 032159d d747bc4 032159d d747bc4 032159d d747bc4 032159d d747bc4 032159d d747bc4 032159d d747bc4 032159d d747bc4 032159d d747bc4 032159d 7f5ea9e d747bc4 032159d d747bc4 032159d d747bc4 032159d d747bc4 032159d d747bc4 032159d d747bc4 032159d d747bc4 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 |
# Battlewords: Implementation Requirements
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).
Assumptions
- Tech stack: Python 3.10+, Streamlit for UI, matplotlib for radar, numpy for tick helpers.
- Single-player, local state stored in Streamlit session state for POC.
- 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.
- Entry point is `app.py`.
Streamlit key components (API usage plan)
- State & caching
- `st.session_state` for `puzzle`, `revealed`, `guessed`, `score`, `can_guess`, `last_action`.
- `st.cache_data` to load and filter the word list.
- Layout & structure
- `st.title`, `st.subheader`, `st.markdown` for headers/instructions.
- `st.columns(12)` to render the 12×12 grid; `st.container` for grouping; `st.sidebar` for secondary controls/help.
- `st.expander` for inline help/intel tips.
- Widgets (interaction)
- `st.button` for each grid cell (144 total) with unique `key` to handle reveals.
- `st.form` + `st.text_input` + `st.form_submit_button("OK")` for controlled word guessing.
- `st.button("New Game")` or `st.link_button` to reset state.
- `st.metric` to show score; `st.checkbox`/`st.toggle` for optional settings (e.g., show radar).
- Visualization
- `st.pyplot` for the radar mini-grid (scatter on a 12×12 axes) or `st.plotly_chart` if interactive.
- Radar plot uses `ax.set_ylim(size, 0)` to invert Y so (0,0) is top-left.
- Control flow
- App reruns on interaction; uses `st.rerun()` after state changes (reveal, guess); `st.stop()` after game over summary to freeze UI.
Folder Structure
- `app.py` – Streamlit entry point
- `battlewords/` – Python package
- `__init__.py`
- `models.py` – data models and types
- `word_loader.py` – load/validate/cached word lists (uses `battlewords/words/wordlist.txt` with fallback)
- `generator.py` – word placement; imports from `word_loader`; avoids duplicate words
- `logic.py` – game mechanics (reveal, guess, scoring, tiers)
- `ui.py` – Streamlit UI composition; immediate rerender on reveal/guess via `st.rerun()`; inverted radar Y
- `words/wordlist.txt` – candidate words
- `specs/` – documentation (this file and `specs.md`)
- `tests/` – unit tests (optional for now)
Phase 1: Proof of Concept (0.1.0)
Goal: A playable, single-session game demonstrating core rules, scoring, and radar without persistence or advanced UX.
1) Data Models
- Define `Coord(x:int, y:int)`.
- Define `Word(text:str, start:Coord, direction:str{"H","V"}, cells:list[Coord])`.
- Define `Puzzle(words:list[Word], radar:list[Coord])` – radar holds last-letter coordinates.
- Define `GameState(grid_size:int=12, puzzle:Puzzle, revealed:set[Coord], guessed:set[str], score:int, last_action:str, can_guess:bool)`.
Acceptance: Types exist and are consumed by generator/logic; simple constructors and validators.
2) Word List
- Add an English word list filtered to alphabetic uppercase, lengths in {4,5,6}.
- Ensure words contain no special characters; maintain reasonable difficulty.
- Streamlit: `st.cache_data` to memoize loading/filtering.
- Loader is centralized in `word_loader.py` and used by generator and UI.
Acceptance: Loading function returns lists by length with >= 500 words per length or fallback minimal lists.
3) Puzzle Generation (Placement)
- Randomly place 2×4, 2×5, 2×6 letter words on a 12×12 grid.
- Constraints (POC):
- Horizontal (left→right) or Vertical (top→down) only.
- No overlapping letters between different words (cells must be unique).
- Compute radar pulses as the last cell of each word.
- Retry strategy with max attempts; raise a controlled error if generation fails.
Acceptance: Generator returns a valid `Puzzle` passing validation checks (no collisions, in-bounds, correct counts, no duplicates).
4) Game Mechanics
- Reveal:
- Click a covered cell to reveal; if the cell is part of a word, show the letter; else mark empty (CSS class `empty`).
- After a reveal action, set `can_guess=True`.
- 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()`.
- Guess:
- Accept a guess only if `can_guess` is True and input length ∈ {4,5,6}.
- Match guess case-insensitively against unguessed words in puzzle.
- 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`.
- If incorrect: no points awarded.
- After any guess, set `can_guess=False` and require another reveal before next guess.
- 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()`.
- **End of game when all 6 words are guessed or all word letters are revealed; display summary and tier, then `st.stop()`.**
Acceptance: Unit tests cover scoring, guess gating, and reveal behavior.
5) UI (Streamlit)
- Layout:
- Title and brief instructions via `st.title`, `st.subheader`, `st.markdown`.
- Left: 12×12 grid using `st.columns(12)` of `st.button`s.
- Right: Radar mini-grid via `st.pyplot` (matplotlib scatter) or `st.plotly_chart`.
- Bottom/right: Guess form using `st.form`, `st.text_input`, `st.form_submit_button`.
- Score panel showing current score using `st.metric` and `st.markdown` for last action.
- Optional `st.sidebar` to host reset/new game and settings; shows word list source/counts.
- Visuals:
- Covered cell vs revealed styles: use button labels/emojis and background color hints; revealed empty cells use CSS class `empty` for background.
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.
6) Scoring Tiers
- After game ends, compute tier:
- Good: 34–37
- Great: 38–41
- Fantastic: 42+
- Display final summary with found words, per-word points, total.
- Streamlit: show results in a `st.container` or `st.expander("Game summary")`.
Acceptance: Tier text shown at game end; manual test with mocked states.
7) Basic Tests
- Unit tests for:
- Placement validity (bounds, overlap, counts, no duplicate words).
- Scoring logic and bonus calculation.
- Guess gating (must reveal before next guess).
Acceptance: Tests run and pass locally.
Beta Version (0.5.0)
Goal: Introduce overlapping words on shared letters, improve UX responsiveness and input options, and add deterministic seeding.
A) Generator and Validation
- Allow shared-letter overlaps: words may cross on the same letter; still disallow conflicting letters on the same cell.
- Optional validation pass to detect and avoid unintended adjacent partial words (content curation rule).
- Deterministic seed support to reproduce puzzles (e.g., daily seed derived from date).
Acceptance:
- Placement permits shared-letter crossings only when letters match.
- With a fixed seed/date, the same puzzle is produced.
B) UI and Interaction
- Cell rendering with consistent sizing and responsive layout (desktop/mobile).
- Keyboard support for grid navigation and guessing (custom JS via `st.html` or component).
- Maintain radar behavior and scoring rules.
Acceptance:
- Grid scales cleanly across typical desktop and mobile widths.
- Users can enter guesses and move focus via keyboard.
C) Tests
- Property checks for overlap validity (only same letters may share a cell).
- Seed reproducibility tests (same seed → identical placements).
- Optional validation tests for adjacency curation (when enabled).
Phase 2: Full Version (1.0.0)
Goal: Robust app with polish, persistence, test coverage, and optional advanced features.
A) UX and Visual Polish
- Cell rendering with consistent sizing and responsive layout (desktop/mobile).
- Keyboard support for navigation and guessing (custom JS via `st.html` or a component if needed).
- Animations for reveals and correct guesses (CSS/JS via `st.html` or component).
- Color-blind friendly palette and accessible contrast.
- Configurable themes (light/dark) via Streamlit theme config.
- Streamlit: `st.tabs` for modes/help; `st.popover`/`st.expander` for tips; `st.toast`/`st.warning` for feedback.
B) Game Content and Generation
- Curated word lists by difficulty; exclude obscure/abusive words.
- Deterministic seed support to reproduce puzzles (e.g., daily seed based on date).
- Validation pass to ensure no unintended partial words formed adjacently (content curation rule, optional).
- Optional generator diagnostics panel for QA using `st.expander` and `st.dataframe`.
- Streamlit: `st.cache_data` for word lists; `st.cache_resource` if needed for heavier resources.
C) Game Modes and Settings
- Daily Puzzle mode (same seed for all players per day).
- Practice mode (random puzzles).
- Difficulty presets that tweak word selection (common vs. rare) but still keep 2×4, 2×5, 2×6.
- Optional hint system with limited uses (e.g., reveal a random letter in an unguessed word) with score penalty.
- Streamlit: mode selection via `st.radio`/`st.segmented_control`; settings via `st.sidebar` with `st.toggle`/`st.slider`.
D) Persistence and Profiles
- Save/Load local game state (browser cookie or Streamlit session + query params).
- Cloud persistence via lightweight backend API (FastAPI) or Streamlit secrets + hosted storage for:
- User profiles (username only), completed puzzles, scores.
- Leaderboards for Daily mode.
- Privacy notice and opt-in for storing data.
- Streamlit: `st.text_input` for username; `st.button` to save; call backend via `requests`.
E) Leaderboards and Sharing
- Global and friends leaderboards (score and completion time if captured; note: game is strategy-first, time is optional).
- Share result string with spoiler-free grid (similar to popular word games).
- Streamlit: `st.table`/`st.dataframe` for leaderboards; `st.download_button` or copy-to-clipboard via `st.text_area` + `st.button`.
F) Observability and Quality
- Logging for generator failures and gameplay events (anonymized).
- Error boundary UI with recover/retry.
- Test suite:
- Unit: generator, logic, scoring, gating, radar.
- Property-based tests for generator (e.g., Hypothesis) to stress placement constraints.
- Integration tests that simulate a full game and validate scoring.
- Visual regression snapshots of grid/radar (optional).
- CI/CD with linting (flake8/ruff), type checks (mypy/pyright), tests, and build.
- Streamlit: developer toggles in an `st.expander` to simulate states; optional `st.fragment` to limit rerenders in hotspots.
G) Performance
- Optimize generator to avoid excessive retries (precompute candidate slots, shuffle deterministically).
- Memoize derived UI state.
- Efficient grid rendering (batch updates or delta rendering where possible in Streamlit).
- Streamlit: consider `st.fragment` for the grid/radar to avoid full-page rerenders.
H) Internationalization (Optional)
- i18n-ready strings; language toggle.
- Locale-specific word lists.
- Streamlit: language toggle via `st.selectbox`.
I) Security and Abuse Prevention
- Validate all inputs (guess strings A–Z only).
- Rate-limit backend endpoints (if any) and sanitize stored data.
- Streamlit: enforce validation in the submit handler and sanitize displayed content with strict formatting.
J) Deployment
- Streamlit Community Cloud or containerized deployment (Dockerfile) to any cloud.
- Environment configuration via `.env` or Streamlit secrets.
- Streamlit: use `st.secrets` for API keys.
Milestones and Estimates (High-level)
- Phase 1 (POC): 2–4 days
- Beta (0.5.0): 3–5 days (overlaps, responsive UI, keyboard, deterministic seed)
- Phase 2 (Full): 1–2 weeks depending on features selected
Definitions of Done (per task)
- Code merged with tests and docs updated.
- No regressions in existing tests; coverage maintained or improved for core logic.
- Manual playthrough validates rules: reveal/guess gating, scoring, radar pulses, end state and tiers.
|