Implement uncapped hit decision tree (SINGLE_UNCAPPED, DOUBLE_UNCAPPED) #6

Closed
opened 2026-02-11 20:09:45 +00:00 by cal · 0 comments
Owner

Summary

The play resolver currently stubs uncapped hits (SINGLE_UNCAPPED / DOUBLE_UNCAPPED) by treating them as SINGLE_1 and DOUBLE_2 respectively. These outcomes need proper hit-location-based runner advancement logic.

Resolution (Backend Complete)

Implemented a full interactive multi-step decision tree for uncapped hits, following the same pattern as the existing X-Check interactive workflow.

Decision Flow

  1. Lead runner advance (offensive) — attempt extra base?
  2. Defensive throw (defensive) — throw to the base?
  3. Trail runner advance (offensive) — trail runner also attempt?
  4. Throw target (defensive) — throw at lead or trail?
  5. Safe/out (offensive) — d20 speed check, declare from card

Files Modified (5)

File Changes
backend/app/models/game_models.py Added PendingUncappedHit model, extended GameState, 5 new decision phases
backend/app/core/game_engine.py Intercept in resolve_manual_play(), initiate_uncapped_hit(), 5 submit methods, 3 result builders, fixed _emit_decision_required()
backend/app/websocket/handlers.py 5 new WebSocket event handlers
backend/app/core/ai_opponent.py 5 AI decision stubs (conservative defaults)
backend/app/core/play_resolver.py Updated TODO comments to clarify fallback paths

Tests Added (3 new files, 80 tests)

File Tests Coverage
test_tt_uncapped_hits.py 8 Fallback truth tables (no eligible runners)
test_uncapped_hit_workflow.py 49 All decision branches, initiation, phase validation, result builders
test_uncapped_hit_handlers.py 23 WebSocket handler input validation and forwarding

Total: 2481 unit tests passing (80 new, 0 regressions)

Follow-up

Frontend UI for the decision workflow tracked in a separate issue.


Original description below for reference:

Original Issue

Current Behavior

  • SINGLE_UNCAPPED (si(cf) on pitching card) → falls through to _advance_on_single_1() regardless of hit location
  • DOUBLE_UNCAPPED (do(cf) on pitching card) → falls through to _advance_on_double_2() regardless of hit location

Expected Behavior

Uncapped hits should resolve runner advancement based on hit location via interactive decision tree.

Files

  • backend/app/core/play_resolver.py - Main implementation (lines 510-607)
  • backend/tests/unit/core/truth_tables/ - Test location
## Summary The play resolver currently stubs uncapped hits (`SINGLE_UNCAPPED` / `DOUBLE_UNCAPPED`) by treating them as `SINGLE_1` and `DOUBLE_2` respectively. These outcomes need proper hit-location-based runner advancement logic. ## Resolution (Backend Complete) Implemented a full interactive multi-step decision tree for uncapped hits, following the same pattern as the existing X-Check interactive workflow. ### Decision Flow 1. **Lead runner advance** (offensive) — attempt extra base? 2. **Defensive throw** (defensive) — throw to the base? 3. **Trail runner advance** (offensive) — trail runner also attempt? 4. **Throw target** (defensive) — throw at lead or trail? 5. **Safe/out** (offensive) — d20 speed check, declare from card ### Files Modified (5) | File | Changes | |------|---------| | `backend/app/models/game_models.py` | Added `PendingUncappedHit` model, extended `GameState`, 5 new decision phases | | `backend/app/core/game_engine.py` | Intercept in `resolve_manual_play()`, `initiate_uncapped_hit()`, 5 submit methods, 3 result builders, fixed `_emit_decision_required()` | | `backend/app/websocket/handlers.py` | 5 new WebSocket event handlers | | `backend/app/core/ai_opponent.py` | 5 AI decision stubs (conservative defaults) | | `backend/app/core/play_resolver.py` | Updated TODO comments to clarify fallback paths | ### Tests Added (3 new files, 80 tests) | File | Tests | Coverage | |------|-------|----------| | `test_tt_uncapped_hits.py` | 8 | Fallback truth tables (no eligible runners) | | `test_uncapped_hit_workflow.py` | 49 | All decision branches, initiation, phase validation, result builders | | `test_uncapped_hit_handlers.py` | 23 | WebSocket handler input validation and forwarding | **Total: 2481 unit tests passing (80 new, 0 regressions)** ### Follow-up Frontend UI for the decision workflow tracked in a separate issue. --- *Original description below for reference:* ## Original Issue ### Current Behavior - `SINGLE_UNCAPPED` (si(cf) on pitching card) → falls through to `_advance_on_single_1()` regardless of hit location - `DOUBLE_UNCAPPED` (do(cf) on pitching card) → falls through to `_advance_on_double_2()` regardless of hit location ### Expected Behavior Uncapped hits should resolve runner advancement based on **hit location** via interactive decision tree. ### Files - `backend/app/core/play_resolver.py` - Main implementation (lines 510-607) - `backend/tests/unit/core/truth_tables/` - Test location
cal closed this issue 2026-02-11 21:03:39 +00:00
Sign in to join this conversation.
No Label
No Milestone
No project
No Assignees
1 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: cal/strat-gameplay-webapp#6
No description provided.