1-3-play-again-skill-tracking.md 3.4 KB

Story 1.3: Play Again & Skill Tracking

Status: ready-for-dev

Story

As a player, I want to play additional rounds after the daily word, with words appropriate to my skill level, So that I can keep playing and the challenge adapts to me.

Acceptance Criteria

  1. Play Again button: Given I am on Screen 3 after completing or failing a game, when I view the screen, then a Play Again button is visible. ✅ (button exists from 1.2, just needs wiring)

  2. Play Again request: Given I tap Play Again, when the client sends POST /api/play-again { skillMetric: number }, then the server selects a word from the target bank using weighted random selection (near skill level more likely). Response: { wordId }. Client navigates to Screen 2 with empty grid.

  3. Skill from difficulty: Given I complete any game, when the final guess response includes difficulty, then the client recalculates skill metric from lifetime statistics (average attempts weighted by word difficulty) and persists it.

  4. Skill sent on play-again: Given I tap Play Again repeatedly, when I play multiple rounds, then each request sends the latest skill metric. No repeat-word prevention (target set is large enough).

  5. Default difficulty fallback: Given the server has no solver-ranked word bank (all default 3.0), when Play Again selects a word, then selection is effectively random pending solver data from Epic 2.

Tasks / Subtasks

  • [ ] Task 1: Implement POST /api/play-again endpoint (AC: 2, 5)

    • Create server/src/play-again.ts — weighted random word selection near skill level
    • Create server/src/routes/play-again.ts — POST /api/play-again, returns { wordId }
    • Register route in server/src/index.ts
  • [ ] Task 2: Wire Play Again in client (AC: 1, 2, 4)

    • Wire handlePlayAgain in App.tsx — call POST /api/play-again, reset game state, navigate to Screen 2
    • Reset useGame state for new round
  • [ ] Task 3: Implement skill metric calculation (AC: 3)

    • Update game-end effect to properly average difficulty into skill metric
    • Store updated skill metric in localStorage

Dev Notes

Building on Story 1.2

  • POST /api/guess returns difficulty on final guess ✅
  • Screen 3 has Play Again button (non-functional) ✅
  • lastDifficulty exposed from useGame hook ✅
  • state.skillMetric persisted in localStorage ✅

Architecture Compliance

  • AD-8 Weighted random selection: Words near player skill level more likely. Specific distribution is implementation detail. [Source: ARCHITECTURE-SPINE.md#AD-8]
  • AD-2 Deterministic daily word unaffected: Play Again generates different words per player. [Source: ARCHITECTURE-SPINE.md#AD-2]

Skill Metric Formula

skillMetric = (skillMetric * (gamesPlayed - 1) + difficulty) / gamesPlayed

Running average of all word difficulties the player has encountered. This converges to the player's true skill over time.

Files to Create/Modify

New: server/src/play-again.ts, server/src/routes/play-again.ts Modify: server/src/index.ts, client/src/App.tsx, client/src/hooks/useGame.ts, client/src/api.ts

References

  • [Source: _bmad-output/planning-artifacts/prds/prd-wordle-2026-07-07/prd.md#FR-11, FR-12, FR-15]
  • [Source: _bmad-output/planning-artifacts/architecture/architecture-wordle-2026-07-07/ARCHITECTURE-SPINE.md]
  • [Source: _bmad-output/planning-artifacts/epics.md#Story 1.3]