- 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>
143 lines
4.9 KiB
Python
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))
|