Merge pull request #3 from calcorum/claude/review-terminal-client-gaps-011CUnv9ai4Bb42rumf5Wriu
This commit is contained in:
commit
b15b63fabe
@ -666,6 +666,315 @@ class GameCommands:
|
||||
logger.exception("Manual outcome error")
|
||||
return False
|
||||
|
||||
async def force_wild_pitch(self, game_id: UUID) -> bool:
|
||||
"""
|
||||
Force a wild pitch interrupt play.
|
||||
|
||||
Wild pitch advances all runners one base.
|
||||
|
||||
Args:
|
||||
game_id: Game to force wild pitch in
|
||||
|
||||
Returns:
|
||||
True if successful, False otherwise
|
||||
"""
|
||||
display.print_info("🎯 Forcing interrupt: WILD PITCH")
|
||||
return await self.resolve_play(game_id, PlayOutcome.WILD_PITCH)
|
||||
|
||||
async def force_passed_ball(self, game_id: UUID) -> bool:
|
||||
"""
|
||||
Force a passed ball interrupt play.
|
||||
|
||||
Passed ball advances all runners one base.
|
||||
|
||||
Args:
|
||||
game_id: Game to force passed ball in
|
||||
|
||||
Returns:
|
||||
True if successful, False otherwise
|
||||
"""
|
||||
display.print_info("🎯 Forcing interrupt: PASSED BALL")
|
||||
return await self.resolve_play(game_id, PlayOutcome.PASSED_BALL)
|
||||
|
||||
def roll_jump(self, league: str = 'sba', game_id: Optional[UUID] = None) -> bool:
|
||||
"""
|
||||
Roll jump dice for stolen base testing.
|
||||
|
||||
Jump roll: 1d20 check + conditional 2d6 or 1d20
|
||||
- check_roll == 1: Pickoff attempt (uses resolution_roll)
|
||||
- check_roll == 2: Balk check (uses resolution_roll)
|
||||
- check_roll >= 3: Normal jump (uses 2d6)
|
||||
|
||||
Args:
|
||||
league: League ID ('sba' or 'pd')
|
||||
game_id: Optional game ID for context
|
||||
|
||||
Returns:
|
||||
True if successful, False otherwise
|
||||
"""
|
||||
try:
|
||||
from app.core.roll_types import RollType
|
||||
|
||||
# Roll jump dice
|
||||
roll = dice_system.roll_jump(league_id=league, game_id=game_id)
|
||||
|
||||
# Display results
|
||||
display.print_success("✓ Jump roll completed!")
|
||||
display.console.print(f"\n[bold cyan]Jump Roll Results:[/bold cyan]")
|
||||
display.console.print(f" [cyan]Roll ID:[/cyan] {roll.roll_id}")
|
||||
display.console.print(f" [cyan]League:[/cyan] {league.upper()}")
|
||||
display.console.print(f" [cyan]Check Roll (1d20):[/cyan] {roll.check_roll}")
|
||||
|
||||
if roll.is_pickoff_check:
|
||||
display.console.print(f"\n[bold red]🎯 PICKOFF ATTEMPT![/bold red]")
|
||||
display.console.print(f" [cyan]Resolution (1d20):[/cyan] {roll.resolution_roll}")
|
||||
display.console.print(f"\n[dim]Pitcher attempts to pick off runner[/dim]")
|
||||
elif roll.is_balk_check:
|
||||
display.console.print(f"\n[bold yellow]⚠️ BALK CHECK![/bold yellow]")
|
||||
display.console.print(f" [cyan]Resolution (1d20):[/cyan] {roll.resolution_roll}")
|
||||
display.console.print(f"\n[dim]Pitcher may have committed balk[/dim]")
|
||||
else:
|
||||
display.console.print(f" [cyan]Jump Dice (2d6):[/cyan] {roll.jump_total} ({roll.jump_dice_a}+{roll.jump_dice_b})")
|
||||
display.console.print(f"\n[green]Normal steal attempt - use jump total for success check[/green]")
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
display.print_error(f"Failed to roll jump: {e}")
|
||||
logger.exception("Jump roll error")
|
||||
return False
|
||||
|
||||
def test_jump(self, count: int = 10, league: str = 'sba') -> bool:
|
||||
"""
|
||||
Test jump roll distribution.
|
||||
|
||||
Rolls N jump rolls and displays distribution statistics.
|
||||
|
||||
Args:
|
||||
count: Number of rolls to test
|
||||
league: League ID ('sba' or 'pd')
|
||||
|
||||
Returns:
|
||||
True if successful, False otherwise
|
||||
"""
|
||||
try:
|
||||
from collections import Counter
|
||||
from rich.table import Table
|
||||
|
||||
display.print_info(f"Rolling {count} jump rolls for {league.upper()} league...")
|
||||
|
||||
# Roll multiple times
|
||||
pickoff_count = 0
|
||||
balk_count = 0
|
||||
normal_count = 0
|
||||
jump_totals = []
|
||||
|
||||
for _ in range(count):
|
||||
roll = dice_system.roll_jump(league_id=league)
|
||||
if roll.is_pickoff_check:
|
||||
pickoff_count += 1
|
||||
elif roll.is_balk_check:
|
||||
balk_count += 1
|
||||
else:
|
||||
normal_count += 1
|
||||
jump_totals.append(roll.jump_total)
|
||||
|
||||
# Display summary
|
||||
display.print_success(f"✓ Completed {count} jump rolls")
|
||||
|
||||
# Event distribution table
|
||||
event_table = Table(title="Jump Roll Event Distribution", show_header=True, header_style="bold cyan")
|
||||
event_table.add_column("Event Type", style="yellow", width=20)
|
||||
event_table.add_column("Count", style="green", width=10, justify="right")
|
||||
event_table.add_column("Percentage", style="cyan", width=12, justify="right")
|
||||
event_table.add_column("Expected", style="dim", width=12, justify="right")
|
||||
|
||||
pickoff_pct = (pickoff_count / count) * 100
|
||||
balk_pct = (balk_count / count) * 100
|
||||
normal_pct = (normal_count / count) * 100
|
||||
|
||||
event_table.add_row("Pickoff Check", str(pickoff_count), f"{pickoff_pct:.1f}%", "5.0%")
|
||||
event_table.add_row("Balk Check", str(balk_count), f"{balk_pct:.1f}%", "5.0%")
|
||||
event_table.add_row("Normal Jump", str(normal_count), f"{normal_pct:.1f}%", "90.0%")
|
||||
|
||||
display.console.print(event_table)
|
||||
|
||||
# Jump total distribution (for normal rolls)
|
||||
if jump_totals:
|
||||
display.console.print(f"\n[bold cyan]Jump Total Distribution (2d6):[/bold cyan]")
|
||||
counter = Counter(jump_totals)
|
||||
|
||||
jump_table = Table(show_header=True, header_style="bold cyan")
|
||||
jump_table.add_column("Total", style="yellow", width=10, justify="right")
|
||||
jump_table.add_column("Count", style="green", width=10, justify="right")
|
||||
jump_table.add_column("Percentage", style="cyan", width=12, justify="right")
|
||||
jump_table.add_column("Visual", style="white", width=30)
|
||||
|
||||
for total in range(2, 13): # 2-12 possible with 2d6
|
||||
count_val = counter.get(total, 0)
|
||||
pct = (count_val / len(jump_totals)) * 100 if jump_totals else 0
|
||||
bar = "█" * int(pct / 2) # Scale bar
|
||||
jump_table.add_row(str(total), str(count_val), f"{pct:.1f}%", bar)
|
||||
|
||||
display.console.print(jump_table)
|
||||
|
||||
# Statistics
|
||||
if jump_totals:
|
||||
avg = sum(jump_totals) / len(jump_totals)
|
||||
display.console.print(f"\n[dim]Average jump total: {avg:.2f} (expected: 7.0)[/dim]")
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
display.print_error(f"Failed to test jump rolls: {e}")
|
||||
logger.exception("Test jump error")
|
||||
return False
|
||||
|
||||
def roll_fielding(self, position: str, league: str = 'sba', game_id: Optional[UUID] = None) -> bool:
|
||||
"""
|
||||
Roll fielding check dice for testing.
|
||||
|
||||
Fielding roll: 1d20 + 3d6 + 1d100
|
||||
- d20: Range check
|
||||
- 3d6: Error total (3-18)
|
||||
- d100: Rare play check
|
||||
|
||||
Args:
|
||||
position: Defensive position (P, C, 1B, 2B, 3B, SS, LF, CF, RF)
|
||||
league: League ID ('sba' or 'pd')
|
||||
game_id: Optional game ID for context
|
||||
|
||||
Returns:
|
||||
True if successful, False otherwise
|
||||
"""
|
||||
try:
|
||||
# Validate position
|
||||
valid_positions = ['P', 'C', '1B', '2B', '3B', 'SS', 'LF', 'CF', 'RF']
|
||||
position = position.upper()
|
||||
if position not in valid_positions:
|
||||
display.print_error(f"Invalid position: {position}")
|
||||
display.console.print(f"[dim]Valid positions: {', '.join(valid_positions)}[/dim]")
|
||||
return False
|
||||
|
||||
# Roll fielding dice
|
||||
roll = dice_system.roll_fielding(position=position, league_id=league, game_id=game_id)
|
||||
|
||||
# Display results
|
||||
display.print_success(f"✓ Fielding roll completed for {position}!")
|
||||
display.console.print(f"\n[bold cyan]Fielding Roll Results:[/bold cyan]")
|
||||
display.console.print(f" [cyan]Roll ID:[/cyan] {roll.roll_id}")
|
||||
display.console.print(f" [cyan]Position:[/cyan] {roll.position}")
|
||||
display.console.print(f" [cyan]League:[/cyan] {league.upper()}")
|
||||
display.console.print(f"\n[bold]Dice Components:[/bold]")
|
||||
display.console.print(f" [cyan]Range (1d20):[/cyan] {roll.d20}")
|
||||
display.console.print(f" [cyan]Error Dice (3d6):[/cyan] {roll.error_total} ({roll.d6_one}+{roll.d6_two}+{roll.d6_three})")
|
||||
display.console.print(f" [cyan]Rare Play (1d100):[/cyan] {roll.d100}")
|
||||
|
||||
if roll.is_rare_play:
|
||||
if league == 'sba':
|
||||
display.console.print(f"\n[bold yellow]⚠️ RARE PLAY! (d100 = 1)[/bold yellow]")
|
||||
else:
|
||||
display.console.print(f"\n[bold yellow]⚠️ RARE PLAY! (error_total = 5)[/bold yellow]")
|
||||
display.console.print(f"[dim]Unusual fielding event may occur[/dim]")
|
||||
|
||||
return True
|
||||
|
||||
except ValueError as e:
|
||||
display.print_error(f"Validation error: {e}")
|
||||
return False
|
||||
except Exception as e:
|
||||
display.print_error(f"Failed to roll fielding: {e}")
|
||||
logger.exception("Fielding roll error")
|
||||
return False
|
||||
|
||||
def test_fielding(self, position: str, count: int = 10, league: str = 'sba') -> bool:
|
||||
"""
|
||||
Test fielding roll distribution for a position.
|
||||
|
||||
Rolls N fielding rolls and displays distribution statistics.
|
||||
|
||||
Args:
|
||||
position: Defensive position (P, C, 1B, 2B, 3B, SS, LF, CF, RF)
|
||||
count: Number of rolls to test
|
||||
league: League ID ('sba' or 'pd')
|
||||
|
||||
Returns:
|
||||
True if successful, False otherwise
|
||||
"""
|
||||
try:
|
||||
from collections import Counter
|
||||
from rich.table import Table
|
||||
|
||||
# Validate position
|
||||
valid_positions = ['P', 'C', '1B', '2B', '3B', 'SS', 'LF', 'CF', 'RF']
|
||||
position = position.upper()
|
||||
if position not in valid_positions:
|
||||
display.print_error(f"Invalid position: {position}")
|
||||
display.console.print(f"[dim]Valid positions: {', '.join(valid_positions)}[/dim]")
|
||||
return False
|
||||
|
||||
display.print_info(f"Rolling {count} fielding checks for {position} in {league.upper()} league...")
|
||||
|
||||
# Roll multiple times
|
||||
d20_values = []
|
||||
error_totals = []
|
||||
d100_values = []
|
||||
rare_play_count = 0
|
||||
|
||||
for _ in range(count):
|
||||
roll = dice_system.roll_fielding(position=position, league_id=league)
|
||||
d20_values.append(roll.d20)
|
||||
error_totals.append(roll.error_total)
|
||||
d100_values.append(roll.d100)
|
||||
if roll.is_rare_play:
|
||||
rare_play_count += 1
|
||||
|
||||
# Display summary
|
||||
display.print_success(f"✓ Completed {count} fielding rolls for {position}")
|
||||
|
||||
# Summary statistics
|
||||
display.console.print(f"\n[bold cyan]Summary Statistics:[/bold cyan]")
|
||||
display.console.print(f" [cyan]Rare Plays:[/cyan] {rare_play_count} ({(rare_play_count/count)*100:.1f}%)")
|
||||
display.console.print(f" [cyan]Avg Range (d20):[/cyan] {sum(d20_values)/len(d20_values):.2f} (expected: 10.5)")
|
||||
display.console.print(f" [cyan]Avg Error Total (3d6):[/cyan] {sum(error_totals)/len(error_totals):.2f} (expected: 10.5)")
|
||||
|
||||
# Error total distribution
|
||||
display.console.print(f"\n[bold cyan]Error Total Distribution (3d6):[/bold cyan]")
|
||||
counter = Counter(error_totals)
|
||||
|
||||
error_table = Table(show_header=True, header_style="bold cyan")
|
||||
error_table.add_column("Total", style="yellow", width=10, justify="right")
|
||||
error_table.add_column("Count", style="green", width=10, justify="right")
|
||||
error_table.add_column("Percentage", style="cyan", width=12, justify="right")
|
||||
error_table.add_column("Visual", style="white", width=30)
|
||||
|
||||
for total in range(3, 19): # 3-18 possible with 3d6
|
||||
count_val = counter.get(total, 0)
|
||||
pct = (count_val / count) * 100
|
||||
bar = "█" * int(pct / 2) # Scale bar
|
||||
error_table.add_row(str(total), str(count_val), f"{pct:.1f}%", bar)
|
||||
|
||||
display.console.print(error_table)
|
||||
|
||||
# Rare play info
|
||||
if league == 'sba':
|
||||
expected_rare = 1.0 # 1% (d100 = 1)
|
||||
else:
|
||||
expected_rare = 2.78 # ~2.78% (3d6 = 5)
|
||||
|
||||
display.console.print(f"\n[dim]Expected rare play rate: {expected_rare:.2f}%[/dim]")
|
||||
display.console.print(f"[dim]Observed rare play rate: {(rare_play_count/count)*100:.2f}%[/dim]")
|
||||
|
||||
return True
|
||||
|
||||
except ValueError as e:
|
||||
display.print_error(f"Validation error: {e}")
|
||||
return False
|
||||
except Exception as e:
|
||||
display.print_error(f"Failed to test fielding rolls: {e}")
|
||||
logger.exception("Test fielding error")
|
||||
return False
|
||||
|
||||
|
||||
# Singleton instance
|
||||
game_commands = GameCommands()
|
||||
|
||||
@ -41,6 +41,9 @@ class CompletionHelper:
|
||||
'bp_homerun', 'bp_single', 'bp_flyout', 'bp_lineout'
|
||||
]
|
||||
|
||||
# Valid positions for fielding rolls
|
||||
VALID_POSITIONS = ['P', 'C', '1B', '2B', '3B', 'SS', 'LF', 'CF', 'RF']
|
||||
|
||||
@staticmethod
|
||||
def filter_completions(text: str, options: List[str]) -> List[str]:
|
||||
"""
|
||||
@ -259,6 +262,87 @@ class GameREPLCompletions:
|
||||
|
||||
return []
|
||||
|
||||
# ==================== New Command Completions ====================
|
||||
|
||||
def complete_roll_jump(self, text: str, line: str, begidx: int, endidx: int) -> List[str]:
|
||||
"""
|
||||
Complete roll_jump command.
|
||||
|
||||
Usage: roll_jump [league]
|
||||
"""
|
||||
return self.completion_helper.filter_completions(
|
||||
text, self.completion_helper.VALID_LEAGUES
|
||||
)
|
||||
|
||||
def complete_test_jump(self, text: str, line: str, begidx: int, endidx: int) -> List[str]:
|
||||
"""
|
||||
Complete test_jump command.
|
||||
|
||||
Usage: test_jump [count] [league]
|
||||
"""
|
||||
parts = line.split()
|
||||
num_args = len(parts) - 1 # Exclude command name
|
||||
|
||||
if num_args == 0 or (num_args == 1 and not text):
|
||||
# Suggest common counts
|
||||
common_counts = ['10', '50', '100', '500', '1000']
|
||||
return self.completion_helper.filter_completions(text, common_counts)
|
||||
elif num_args == 1 or (num_args == 2 and not text):
|
||||
# Suggest leagues
|
||||
return self.completion_helper.filter_completions(
|
||||
text, self.completion_helper.VALID_LEAGUES
|
||||
)
|
||||
|
||||
return []
|
||||
|
||||
def complete_roll_fielding(self, text: str, line: str, begidx: int, endidx: int) -> List[str]:
|
||||
"""
|
||||
Complete roll_fielding command.
|
||||
|
||||
Usage: roll_fielding <position> [league]
|
||||
"""
|
||||
parts = line.split()
|
||||
num_args = len(parts) - 1 # Exclude command name
|
||||
|
||||
if num_args == 0 or (num_args == 1 and not text):
|
||||
# Suggest positions
|
||||
return self.completion_helper.filter_completions(
|
||||
text, self.completion_helper.VALID_POSITIONS
|
||||
)
|
||||
elif num_args == 1 or (num_args == 2 and not text):
|
||||
# Suggest leagues
|
||||
return self.completion_helper.filter_completions(
|
||||
text, self.completion_helper.VALID_LEAGUES
|
||||
)
|
||||
|
||||
return []
|
||||
|
||||
def complete_test_fielding(self, text: str, line: str, begidx: int, endidx: int) -> List[str]:
|
||||
"""
|
||||
Complete test_fielding command.
|
||||
|
||||
Usage: test_fielding <position> [count] [league]
|
||||
"""
|
||||
parts = line.split()
|
||||
num_args = len(parts) - 1 # Exclude command name
|
||||
|
||||
if num_args == 0 or (num_args == 1 and not text):
|
||||
# Suggest positions
|
||||
return self.completion_helper.filter_completions(
|
||||
text, self.completion_helper.VALID_POSITIONS
|
||||
)
|
||||
elif num_args == 1 or (num_args == 2 and not text):
|
||||
# Suggest common counts
|
||||
common_counts = ['10', '50', '100', '500', '1000']
|
||||
return self.completion_helper.filter_completions(text, common_counts)
|
||||
elif num_args == 2 or (num_args == 3 and not text):
|
||||
# Suggest leagues
|
||||
return self.completion_helper.filter_completions(
|
||||
text, self.completion_helper.VALID_LEAGUES
|
||||
)
|
||||
|
||||
return []
|
||||
|
||||
# ==================== Helper Methods ====================
|
||||
|
||||
def completedefault(self, text: str, line: str, begidx: int, endidx: int) -> List[str]:
|
||||
|
||||
@ -676,6 +676,196 @@ Press Ctrl+D or type 'quit' to exit.
|
||||
"""Show detailed help for clear command."""
|
||||
show_help('clear')
|
||||
|
||||
# ==================== Interrupt Play Commands ====================
|
||||
|
||||
def do_force_wild_pitch(self, arg):
|
||||
"""
|
||||
Force a wild pitch interrupt play.
|
||||
|
||||
Usage: force_wild_pitch
|
||||
|
||||
Wild pitch advances all runners one base. This is an interrupt play
|
||||
(pa=0) and does not count as a plate appearance.
|
||||
|
||||
Example:
|
||||
force_wild_pitch # Runner on 2nd advances to 3rd
|
||||
"""
|
||||
async def _force_wild_pitch():
|
||||
try:
|
||||
gid = self._ensure_game()
|
||||
await self._ensure_game_loaded(gid)
|
||||
await game_commands.force_wild_pitch(gid)
|
||||
except ValueError:
|
||||
pass # Already printed error
|
||||
|
||||
self._run_async(_force_wild_pitch())
|
||||
|
||||
def do_force_passed_ball(self, arg):
|
||||
"""
|
||||
Force a passed ball interrupt play.
|
||||
|
||||
Usage: force_passed_ball
|
||||
|
||||
Passed ball advances all runners one base. This is an interrupt play
|
||||
(pa=0) and does not count as a plate appearance.
|
||||
|
||||
Example:
|
||||
force_passed_ball # Runner on 1st advances to 2nd
|
||||
"""
|
||||
async def _force_passed_ball():
|
||||
try:
|
||||
gid = self._ensure_game()
|
||||
await self._ensure_game_loaded(gid)
|
||||
await game_commands.force_passed_ball(gid)
|
||||
except ValueError:
|
||||
pass # Already printed error
|
||||
|
||||
self._run_async(_force_passed_ball())
|
||||
|
||||
# ==================== Jump Roll Testing Commands ====================
|
||||
|
||||
def do_roll_jump(self, arg):
|
||||
"""
|
||||
Roll jump dice for stolen base testing.
|
||||
|
||||
Usage: roll_jump [league]
|
||||
|
||||
Jump roll components:
|
||||
- 1d20 check roll (1=pickoff, 2=balk, 3+=normal)
|
||||
- 2d6 for normal jump (if check >= 3)
|
||||
- 1d20 resolution (if check == 1 or 2)
|
||||
|
||||
Arguments:
|
||||
league 'sba' or 'pd' (default: sba)
|
||||
|
||||
Examples:
|
||||
roll_jump # Roll for SBA league
|
||||
roll_jump pd # Roll for PD league
|
||||
|
||||
The jump roll determines steal attempt outcomes:
|
||||
- Pickoff check (5%): Pitcher attempts to pick off runner
|
||||
- Balk check (5%): Pitcher may commit balk
|
||||
- Normal jump (90%): Use 2d6 total for steal success check
|
||||
"""
|
||||
parts = arg.split()
|
||||
league = parts[0] if parts else 'sba'
|
||||
|
||||
if league not in ['sba', 'pd']:
|
||||
display.print_error("League must be 'sba' or 'pd'")
|
||||
return
|
||||
|
||||
game_commands.roll_jump(league, self.current_game_id)
|
||||
|
||||
def do_test_jump(self, arg):
|
||||
"""
|
||||
Test jump roll distribution.
|
||||
|
||||
Usage: test_jump [count] [league]
|
||||
|
||||
Rolls N jump rolls and displays distribution statistics including:
|
||||
- Pickoff check frequency (expected: 5%)
|
||||
- Balk check frequency (expected: 5%)
|
||||
- Normal jump frequency (expected: 90%)
|
||||
- Jump total distribution (2d6, expected avg: 7.0)
|
||||
|
||||
Arguments:
|
||||
count Number of rolls (default: 10)
|
||||
league 'sba' or 'pd' (default: sba)
|
||||
|
||||
Examples:
|
||||
test_jump # 10 rolls for SBA
|
||||
test_jump 100 # 100 rolls for SBA
|
||||
test_jump 50 pd # 50 rolls for PD
|
||||
"""
|
||||
parts = arg.split()
|
||||
count = int(parts[0]) if parts else 10
|
||||
league = parts[1] if len(parts) > 1 else 'sba'
|
||||
|
||||
if league not in ['sba', 'pd']:
|
||||
display.print_error("League must be 'sba' or 'pd'")
|
||||
return
|
||||
|
||||
game_commands.test_jump(count, league)
|
||||
|
||||
# ==================== Fielding Roll Testing Commands ====================
|
||||
|
||||
def do_roll_fielding(self, arg):
|
||||
"""
|
||||
Roll fielding check dice for testing.
|
||||
|
||||
Usage: roll_fielding <position> [league]
|
||||
|
||||
Fielding roll components:
|
||||
- 1d20: Range check
|
||||
- 3d6: Error total (3-18)
|
||||
- 1d100: Rare play check
|
||||
|
||||
Arguments:
|
||||
position P, C, 1B, 2B, 3B, SS, LF, CF, RF (required)
|
||||
league 'sba' or 'pd' (default: sba)
|
||||
|
||||
Examples:
|
||||
roll_fielding SS # Roll for shortstop (SBA)
|
||||
roll_fielding P pd # Roll for pitcher (PD)
|
||||
roll_fielding CF # Roll for center field
|
||||
|
||||
Rare plays:
|
||||
- SBA: d100 = 1 (1% chance)
|
||||
- PD: error_total = 5 (~2.78% chance)
|
||||
"""
|
||||
parts = arg.split()
|
||||
if not parts:
|
||||
display.print_error("Usage: roll_fielding <position> [league]")
|
||||
display.console.print("[dim]Valid positions: P, C, 1B, 2B, 3B, SS, LF, CF, RF[/dim]")
|
||||
return
|
||||
|
||||
position = parts[0]
|
||||
league = parts[1] if len(parts) > 1 else 'sba'
|
||||
|
||||
if league not in ['sba', 'pd']:
|
||||
display.print_error("League must be 'sba' or 'pd'")
|
||||
return
|
||||
|
||||
game_commands.roll_fielding(position, league, self.current_game_id)
|
||||
|
||||
def do_test_fielding(self, arg):
|
||||
"""
|
||||
Test fielding roll distribution for a position.
|
||||
|
||||
Usage: test_fielding <position> [count] [league]
|
||||
|
||||
Rolls N fielding rolls and displays distribution statistics including:
|
||||
- Rare play frequency
|
||||
- Average range roll (d20, expected: 10.5)
|
||||
- Average error total (3d6, expected: 10.5)
|
||||
- Error total distribution (3-18)
|
||||
|
||||
Arguments:
|
||||
position P, C, 1B, 2B, 3B, SS, LF, CF, RF (required)
|
||||
count Number of rolls (default: 10)
|
||||
league 'sba' or 'pd' (default: sba)
|
||||
|
||||
Examples:
|
||||
test_fielding SS # 10 rolls for shortstop (SBA)
|
||||
test_fielding 2B 100 # 100 rolls for second base
|
||||
test_fielding CF 50 pd # 50 rolls for center field (PD)
|
||||
"""
|
||||
parts = arg.split()
|
||||
if not parts:
|
||||
display.print_error("Usage: test_fielding <position> [count] [league]")
|
||||
display.console.print("[dim]Valid positions: P, C, 1B, 2B, 3B, SS, LF, CF, RF[/dim]")
|
||||
return
|
||||
|
||||
position = parts[0]
|
||||
count = int(parts[1]) if len(parts) > 1 else 10
|
||||
league = parts[2] if len(parts) > 2 else 'sba'
|
||||
|
||||
if league not in ['sba', 'pd']:
|
||||
display.print_error("League must be 'sba' or 'pd'")
|
||||
return
|
||||
|
||||
game_commands.test_fielding(position, count, league)
|
||||
|
||||
# ==================== REPL Control Commands ====================
|
||||
|
||||
def do_clear(self, arg):
|
||||
|
||||
Loading…
Reference in New Issue
Block a user