paper-dynasty-card-creation/rank_pitching_staffs.py
Cal Corum 96f3721780 CLAUDE: Add S3 upload script and cardset analysis tools
- Add check_cards_and_upload.py: Fetches card images from API and uploads to AWS S3
  - Uses persistent aiohttp session for efficient connection reuse
  - Supports cache-busting query parameters (?d=date) for Discord compatibility
  - S3 URL structure: cards/cardset-{id:03d}/player-{id}/{type}card.png
  - Configurable upload and player URL update flags

- Add analyze_cardset_rarity.py: Analyzes players by franchise and rarity
  - Groups batters, pitchers, and combined totals
  - Displays counts for all rarity tiers by franchise
  - Provides comprehensive breakdown of cardset composition

- Add rank_pitching_staffs.py: Ranks teams 1-30 by pitching staff quality
  - Point system based on rarity tiers (HoF=5, MVP=4, AS=3, etc.)
  - Shows detailed rosters for top 5 and bottom 5 teams
  - Useful for balance analysis and cardset evaluation

- Update CLAUDE.md with new scripts documentation

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-09 06:11:16 -06:00

143 lines
4.9 KiB
Python

import asyncio
from collections import defaultdict
from db_calls import db_get
async def rank_pitching_staffs(cardset_id: int = 27):
"""Rank teams by pitching staff quality based on player rarity."""
print(f'Fetching players from cardset {cardset_id}...\n')
# Fetch all players from the cardset
p_query = await db_get(
'players',
params=[('cardset_id', cardset_id), ('inc_dex', False)]
)
if not p_query or p_query['count'] == 0:
print(f'No players found for cardset {cardset_id}')
return
players = p_query['players']
print(f'Found {len(players)} players\n')
# Assign point values to each rarity
rarity_points = {
'Hall of Fame': 5,
'MVP': 4,
'All-Star': 3,
'Starter': 2,
'Reserve': 1,
'Replacement': 0.5
}
# Collect pitching staff data by franchise
franchise_pitching = defaultdict(lambda: {
'pitchers': [],
'total_points': 0,
'count': 0,
'avg_points': 0,
'rarities': defaultdict(int)
})
for player in players:
franchise = player.get('franchise', 'Unknown')
rarity_obj = player.get('rarity', {})
# Extract rarity name from rarity object
if isinstance(rarity_obj, dict):
rarity = rarity_obj.get('name', 'Unknown')
else:
rarity = str(rarity_obj) if rarity_obj else 'Unknown'
# Determine if pitcher based on positions
positions = []
for i in range(1, 9):
pos = player.get(f'pos_{i}')
if pos:
positions.append(pos)
is_pitcher = any(pos in ['SP', 'RP', 'CP'] for pos in positions)
if is_pitcher and franchise != 'Unknown':
points = rarity_points.get(rarity, 0)
franchise_pitching[franchise]['pitchers'].append({
'name': player.get('p_name'),
'rarity': rarity,
'points': points
})
franchise_pitching[franchise]['total_points'] += points
franchise_pitching[franchise]['count'] += 1
franchise_pitching[franchise]['rarities'][rarity] += 1
# Calculate average points per pitcher
for franchise in franchise_pitching:
count = franchise_pitching[franchise]['count']
if count > 0:
franchise_pitching[franchise]['avg_points'] = (
franchise_pitching[franchise]['total_points'] / count
)
# Sort franchises by total points (descending)
ranked_teams = sorted(
franchise_pitching.items(),
key=lambda x: (x[1]['total_points'], x[1]['avg_points']),
reverse=True
)
# Print rankings
print('=' * 120)
print('PITCHING STAFF RANKINGS (by total rarity points)')
print('=' * 120)
print(f'{"Rank":<6} {"Franchise":<25} {"Pitchers":<10} {"Total Pts":<12} {"Avg Pts":<10} {"HoF":<6} {"MVP":<6} {"AS":<6} {"STR":<6} {"RES":<6} {"REP":<6}')
print('-' * 120)
for rank, (franchise, data) in enumerate(ranked_teams, start=1):
hof = data['rarities'].get('Hall of Fame', 0)
mvp = data['rarities'].get('MVP', 0)
all_star = data['rarities'].get('All-Star', 0)
starter = data['rarities'].get('Starter', 0)
reserve = data['rarities'].get('Reserve', 0)
replacement = data['rarities'].get('Replacement', 0)
print(f'{rank:<6} {franchise:<25} {data["count"]:<10} {data["total_points"]:<12.1f} {data["avg_points"]:<10.2f} '
f'{hof:<6} {mvp:<6} {all_star:<6} {starter:<6} {reserve:<6} {replacement:<6}')
print('=' * 120)
# Print top 5 teams with details
print('\n' + '=' * 100)
print('TOP 5 PITCHING STAFFS - DETAILED ROSTERS')
print('=' * 100)
for rank, (franchise, data) in enumerate(ranked_teams[:5], start=1):
print(f'\n#{rank} - {franchise.upper()} ({data["total_points"]:.1f} points, {data["count"]} pitchers)')
print('-' * 100)
# Sort pitchers by points
sorted_pitchers = sorted(data['pitchers'], key=lambda x: x['points'], reverse=True)
for pitcher in sorted_pitchers:
print(f' {pitcher["name"]:<30} {pitcher["rarity"]:<15} ({pitcher["points"]} pts)')
# Print bottom 5 teams
print('\n' + '=' * 100)
print('BOTTOM 5 PITCHING STAFFS - DETAILED ROSTERS')
print('=' * 100)
for rank, (franchise, data) in enumerate(ranked_teams[-5:], start=len(ranked_teams)-4):
print(f'\n#{rank} - {franchise.upper()} ({data["total_points"]:.1f} points, {data["count"]} pitchers)')
print('-' * 100)
# Sort pitchers by points
sorted_pitchers = sorted(data['pitchers'], key=lambda x: x['points'], reverse=True)
for pitcher in sorted_pitchers:
print(f' {pitcher["name"]:<30} {pitcher["rarity"]:<15} ({pitcher["points"]} pts)')
print('\n' + '=' * 100)
if __name__ == '__main__':
asyncio.run(rank_pitching_staffs(27))