7.4 KiB
Manual Outcome Testing Feature
Date: 2025-10-29 Status: Implemented (Experimental) Purpose: Allow manual specification of play outcomes for testing specific scenarios
Overview
Added two new terminal client commands to support testing specific game scenarios without random dice rolls:
list_outcomes- Display all available PlayOutcome valuesresolve_with <outcome>- Resolve play with a specific outcome
Commands
list_outcomes
Displays a beautiful categorized table of all available PlayOutcome enum values.
Usage:
⚾ > list_outcomes
Output:
- Categorized table with:
- Outs: strikeout, groundball variants, flyout variants, lineouts, popouts
- Hits: single variants, double variants, triple, homerun
- Walks/HBP: walk, hbp, intentional_walk
- Errors: error
- Interrupts: wild_pitch, passed_ball, stolen_base, caught_stealing, balk, pick_off
- Ballpark: bp_homerun, bp_single, bp_flyout, bp_lineout
resolve_with
Resolves the current play with a specific outcome instead of rolling dice.
Usage:
⚾ > resolve_with single_1
⚾ > resolve_with homerun
⚾ > resolve_with groundball_a
⚾ > resolve_with double_uncapped
Features:
- Validates outcome string against PlayOutcome enum
- Provides clear error messages for invalid outcomes
- TAB completion for all outcome names
- Detailed help text with examples
Current Status: ⚠️ Experimental - Currently shows warning and uses regular dice resolution. Full forced outcome integration will be added in Week 7 as part of the strategic decision system implementation.
The command infrastructure is in place and ready for integration when the game engine supports forced outcomes.
Testing Use Cases
These commands will be useful for testing:
-
Runner Advancement Rules
# Set up bases loaded # Then force specific outcomes to test advancement resolve_with single_1 # Test standard single advancement resolve_with single_2 # Test enhanced advancement resolve_with double_2 # Runners to 2nd and home resolve_with double_3 # Runners to 3rd and home -
Double Play Mechanics
# Set up runner on first, <2 outs resolve_with groundball_a # Should check for DP opportunity resolve_with groundball_b # Standard groundout -
Uncapped Hit Decision Trees
# Test uncapped outcomes resolve_with single_uncapped resolve_with double_uncapped # Should trigger advancement decision workflows -
Scoring Scenarios
# Runner on third, test different outcomes resolve_with groundball_b # Does runner score? resolve_with flyout_b # Tag up from third? resolve_with single_1 # Should score easily -
Game State Edge Cases
# Test bases loaded, 2 outs resolve_with strikeout # Inning over resolve_with homerun # Grand slam resolve_with walk # Force in run
Implementation Details
Files Modified
-
terminal_client/commands.py- Added
PlayOutcomeimport - Enhanced
resolve_play()withforced_outcomeparameter - Added
list_outcomes()method with Rich table display
- Added
-
terminal_client/repl.py- Added
do_list_outcomes()command - Added
do_resolve_with()command with outcome parsing
- Added
-
terminal_client/completions.py- Added
VALID_OUTCOMESconstant with all PlayOutcome values - Added
complete_resolve_with()method for TAB completion
- Added
-
terminal_client/help_text.py- Added commands to "Testing & Development" section
- Added
list_outcomeshelp entry - Added
resolve_withhelp entry with examples
TAB Completion
The resolve_with command has full TAB completion support:
⚾ > resolve_with <TAB>
strikeout groundball_a groundball_b groundball_c
flyout_a flyout_b flyout_c lineout
single_1 single_2 single_uncapped double_2
double_3 double_uncapped triple homerun
walk hbp ...
⚾ > resolve_with single_<TAB>
single_1 single_2 single_uncapped
⚾ > resolve_with single_1
Error Handling
Clear error messages for invalid input:
⚾ > resolve_with
❌ Missing outcome argument
ℹ Usage: resolve_with <outcome>
ℹ Use 'list_outcomes' to see available values
⚾ > resolve_with invalid_outcome
❌ Invalid outcome: invalid_outcome
ℹ Use 'list_outcomes' to see valid values
Future Enhancements (Week 7)
When implementing Week 7 strategic decisions, integrate forced outcomes:
-
Add
resolve_play_with_outcome()to GameEngineasync def resolve_play_with_outcome( self, game_id: UUID, forced_outcome: PlayOutcome ) -> PlayResult: """ Resolve play with a specific outcome (testing only). Bypasses dice rolling and uses provided outcome directly. All other game logic (runner advancement, scoring, etc.) still applies. """ # Get current state state = state_manager.get_state(game_id) # Create PlayResult with forced outcome result = PlayResult( outcome=forced_outcome, description=f"Forced outcome: {forced_outcome.value}", outs_recorded=1 if forced_outcome.is_out() else 0, runs_scored=0, # Calculated by runner advancement hit_location=self._get_default_hit_location(forced_outcome), runner_movements=[] ) # Apply result using normal resolution logic await self._apply_play_result(state, result) return result -
Update
commands.pyto use new methodif forced_outcome: result = await game_engine.resolve_play_with_outcome(game_id, forced_outcome) else: result = await game_engine.resolve_play(game_id) -
Add runner advancement for forced outcomes
- Use RunnerAdvancer class (from Week 7 plan)
- Calculate movements based on outcome type
- Apply scoring logic
Testing
Manual testing performed:
- ✅
list_outcomesdisplays all outcomes correctly - ✅ TAB completion works for outcome names
- ✅ Invalid outcomes show clear error messages
- ✅ Help text displays correctly
- ✅ Commands integrate with existing REPL flow
Usage Examples
Basic Workflow
# Start terminal client
python -m terminal_client
# Create a game
⚾ > new_game
# Submit decisions
⚾ > defensive
⚾ > offensive
# See all available outcomes
⚾ > list_outcomes
# Try forcing a specific outcome
⚾ > resolve_with single_1
⚠️ Manual outcome selection is experimental
Using regular resolution for now (forced outcome noted)
# [Regular resolution happens]
# This will be fully functional in Week 7
# Continue testing
⚾ > status
⚾ > resolve_with homerun
Testing Runner Advancement
# Set up specific scenario
⚾ > quick_play 10 # Advance game state
# Check current state
⚾ > status
# Inning: 3 Top, Outs: 1, Runners: [1st, 3rd]
# Force single to test advancement
⚾ > defensive
⚾ > offensive
⚾ > resolve_with single_2
# Verify runner advancement logic
⚾ > status
# Runner from 3rd should score
# Runner from 1st should advance to 3rd (enhanced)
Next Steps: Week 7 implementation will add full forced outcome support to the game engine.
Documentation: See terminal_client/CLAUDE.md for full terminal client guide.