Moved AI lineup creation to db
This commit is contained in:
parent
b40409e844
commit
0a59d3e98d
109
app/db_engine.py
109
app/db_engine.py
@ -26,6 +26,27 @@ logging.basicConfig(
|
||||
level=log_level
|
||||
)
|
||||
|
||||
CARDSETS = {
|
||||
'ranked': {
|
||||
'primary': [9, 10, 13] # 2023, 23 Promos, 2018
|
||||
},
|
||||
'minor-league': {
|
||||
'primary': [13, 8], # 2018, Mario
|
||||
'secondary': [9, 3] # 2023, 2022
|
||||
},
|
||||
'major-league': {
|
||||
'primary': [13, 9, 8, 6], # 2018, 2023, Mario, 2013
|
||||
'secondary': [3, 12] # 2022, 2008
|
||||
},
|
||||
'hall-of-fame': {
|
||||
'primary': [1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
|
||||
},
|
||||
'tens': {
|
||||
'primary': [11, 7, 6, 12], # 2016, 2012, 2013, 2008, Mario
|
||||
'secondary': [13, 5] # 2018, 2019
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def model_csv_headers(this_obj, exclude=None) -> List:
|
||||
data = model_to_dict(this_obj, recurse=False, exclude=exclude)
|
||||
@ -695,6 +716,94 @@ CardPosition.add_index(pos_index)
|
||||
db.create_tables([BattingCard, BattingCardRatings, PitchingCard, PitchingCardRatings, CardPosition])
|
||||
|
||||
|
||||
class StratGame(BaseModel):
|
||||
season = IntegerField()
|
||||
game_type = CharField()
|
||||
away_team = ForeignKeyField(Team)
|
||||
home_team = ForeignKeyField(Team)
|
||||
|
||||
week = IntegerField(default=1)
|
||||
away_score = IntegerField(default=0)
|
||||
home_score = IntegerField(default=0)
|
||||
away_team_value = IntegerField(null=True)
|
||||
home_team_value = IntegerField(null=True)
|
||||
away_team_ranking = IntegerField(null=True)
|
||||
home_team_ranking = IntegerField(null=True)
|
||||
ranked = BooleanField(default=False)
|
||||
short_game = BooleanField(default=False)
|
||||
|
||||
|
||||
class StratPlay(BaseModel):
|
||||
game = ForeignKeyField(StratGame)
|
||||
play_num = IntegerField()
|
||||
batter = ForeignKeyField(Player, null=True)
|
||||
batter_team = ForeignKeyField(Team, null=True)
|
||||
pitcher = ForeignKeyField(Player)
|
||||
pitcher_team = ForeignKeyField(Team)
|
||||
on_base_code = CharField()
|
||||
inning_half = CharField()
|
||||
inning_num = IntegerField()
|
||||
batting_order = IntegerField()
|
||||
starting_outs = IntegerField()
|
||||
away_score = IntegerField()
|
||||
home_score = IntegerField()
|
||||
batter_pos = CharField(null=True)
|
||||
|
||||
# These <base>_final fields track the base this runner advances to post-play (None) if out
|
||||
on_first = ForeignKeyField(Player, null=True)
|
||||
on_first_final = IntegerField(null=True)
|
||||
on_second = ForeignKeyField(Player, null=True)
|
||||
on_second_final = IntegerField(null=True)
|
||||
on_third = ForeignKeyField(Player, null=True)
|
||||
on_third_final = IntegerField(null=True)
|
||||
batter_final = IntegerField(null=True)
|
||||
|
||||
pa = IntegerField(default=0)
|
||||
ab = IntegerField(default=0)
|
||||
e_run = IntegerField(default=0)
|
||||
run = IntegerField(default=0)
|
||||
hit = IntegerField(default=0)
|
||||
rbi = IntegerField(default=0)
|
||||
double = IntegerField(default=0)
|
||||
triple = IntegerField(default=0)
|
||||
homerun = IntegerField(default=0)
|
||||
bb = IntegerField(default=0)
|
||||
so = IntegerField(default=0)
|
||||
hbp = IntegerField(default=0)
|
||||
sac = IntegerField(default=0)
|
||||
ibb = IntegerField(default=0)
|
||||
gidp = IntegerField(default=0)
|
||||
bphr = IntegerField(default=0)
|
||||
bpfo = IntegerField(default=0)
|
||||
bp1b = IntegerField(default=0)
|
||||
bplo = IntegerField(default=0)
|
||||
sb = IntegerField(default=0)
|
||||
cs = IntegerField(default=0)
|
||||
outs = IntegerField(default=0)
|
||||
wpa = FloatField(default=0)
|
||||
|
||||
# These <position> fields are only required if the play is an x-check or baserunning play
|
||||
catcher = ForeignKeyField(Player, null=True)
|
||||
catcher_team = ForeignKeyField(Team, null=True)
|
||||
defender = ForeignKeyField(Player, null=True)
|
||||
defender_team = ForeignKeyField(Team, null=True)
|
||||
runner = ForeignKeyField(Player, null=True)
|
||||
runner_team = ForeignKeyField(Team, null=True)
|
||||
|
||||
check_pos = CharField(null=True)
|
||||
error = IntegerField(default=0)
|
||||
wild_pitch = IntegerField(default=0)
|
||||
passed_ball = IntegerField(default=0)
|
||||
pick_off = IntegerField(default=0)
|
||||
balk = IntegerField(default=0)
|
||||
is_go_ahead = BooleanField(default=False)
|
||||
is_tied = BooleanField(default=False)
|
||||
is_new_inning = BooleanField(default=False)
|
||||
|
||||
|
||||
db.create_tables([StratGame, StratPlay])
|
||||
|
||||
|
||||
db.close()
|
||||
|
||||
# scout_db = SqliteDatabase(
|
||||
|
||||
@ -125,8 +125,7 @@ async def get_card_ratings(
|
||||
for x in return_vals:
|
||||
x.update(x['battingcard'])
|
||||
x['player_id'] = x['battingcard']['player']['player_id']
|
||||
del x['battingcard']
|
||||
del x['player']
|
||||
del x['battingcard'], x['player']
|
||||
|
||||
db.close()
|
||||
return Response(content=pd.DataFrame(return_vals).to_csv(index=False), media_type='text/csv')
|
||||
|
||||
@ -4,7 +4,7 @@ import logging
|
||||
import pydantic
|
||||
from pandas import DataFrame
|
||||
|
||||
from ..db_engine import db, Card, model_to_dict, Team, Player, Pack, Paperdex
|
||||
from ..db_engine import db, Card, model_to_dict, Team, Player, Pack, Paperdex, CARDSETS
|
||||
from ..dependencies import oauth2_scheme, valid_token, LOG_DATA
|
||||
|
||||
logging.basicConfig(
|
||||
@ -218,15 +218,18 @@ async def v1_cards_legal_check(
|
||||
status_code=401,
|
||||
detail='Unauthorized'
|
||||
)
|
||||
if rarity_name not in ['ranked']:
|
||||
if rarity_name not in CARDSETS.keys():
|
||||
return f'Rarity name {rarity_name} not a valid check'
|
||||
|
||||
bad_cards = []
|
||||
all_cards = Card.select().where(Card.id << card_id)
|
||||
|
||||
for x in all_cards:
|
||||
if x.player.cardset_id not in [3, 4, 9, 10]:
|
||||
bad_cards.append(x.player.description)
|
||||
if x.player.cardset_id not in CARDSETS[rarity_name]:
|
||||
if x.player.p_name in x.player.description:
|
||||
bad_cards.append(x.player.description)
|
||||
else:
|
||||
bad_cards.append(f'{x.player.description} {x.player.p_name}')
|
||||
|
||||
return {'count': len(bad_cards), 'bad_cards': bad_cards}
|
||||
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from fastapi import APIRouter, Depends, HTTPException, Response
|
||||
from pandas import DataFrame
|
||||
from typing import Optional
|
||||
import logging
|
||||
import pydantic
|
||||
|
||||
@ -8,7 +8,8 @@ import pydantic
|
||||
from pandas import DataFrame
|
||||
|
||||
from ..db_engine import db, Team, model_to_dict, fn, Pack, Card, Player, Paperdex, Notification, PackType, \
|
||||
Rarity, Current, query_to_csv, complex_data_to_csv
|
||||
Rarity, Current, query_to_csv, complex_data_to_csv, CARDSETS, CardPosition, BattingCardRatings, BattingCard, \
|
||||
PitchingCard, PitchingCardRatings
|
||||
from ..dependencies import oauth2_scheme, valid_token, LOG_DATA, int_timestamp
|
||||
|
||||
logging.basicConfig(
|
||||
@ -153,6 +154,274 @@ async def get_one_team(team_id, csv: Optional[bool] = False):
|
||||
return return_val
|
||||
|
||||
|
||||
@router.get('/{team_id}/lineup/{difficulty_name}')
|
||||
async def get_team_lineup(team_id: int, difficulty_name: str, pitcher_name: str, d_rank: int = 5, o_rank: int = 5):
|
||||
"""
|
||||
d_rank: int - 10: best overall, 9: prioritize range, 8: prioritize error
|
||||
"""
|
||||
this_team = Team.get_or_none(Team.id == team_id)
|
||||
if this_team is None:
|
||||
db.close()
|
||||
raise HTTPException(status_code=404, detail=f'Team id {team_id} not found')
|
||||
|
||||
if difficulty_name not in CARDSETS.keys():
|
||||
db.close()
|
||||
raise HTTPException(status_code=400, detail=f'Difficulty name {difficulty_name} not a valid check')
|
||||
|
||||
# all_players = Player.select().where(
|
||||
# (fn.Lower(Player.p_name) != pitcher_name.lower()) & (Player.mlbclub == this_team.lname)
|
||||
# )
|
||||
all_players = Player.select().where(Player.mlbclub == this_team.lname)
|
||||
|
||||
legal_players = all_players.where(Player.cardset_id << CARDSETS[difficulty_name]['primary'])
|
||||
if 'secondary' in CARDSETS[difficulty_name]:
|
||||
backup_players = all_players.where(Player.cardset_id << CARDSETS[difficulty_name]['secondary'])
|
||||
else:
|
||||
backup_players = None
|
||||
|
||||
logging.info(f'legal_players: {legal_players.count()}')
|
||||
if backup_players is not None:
|
||||
logging.info(f'backup_players: {backup_players.count()}')
|
||||
player_names = []
|
||||
starting_nine = {
|
||||
'C': {'player': None, 'vl': None, 'vr': None, 'ops': 0},
|
||||
'1B': {'player': None, 'vl': None, 'vr': None, 'ops': 0},
|
||||
'2B': {'player': None, 'vl': None, 'vr': None, 'ops': 0},
|
||||
'3B': {'player': None, 'vl': None, 'vr': None, 'ops': 0},
|
||||
'SS': {'player': None, 'vl': None, 'vr': None, 'ops': 0},
|
||||
'LF': {'player': None, 'vl': None, 'vr': None, 'ops': 0},
|
||||
'CF': {'player': None, 'vl': None, 'vr': None, 'ops': 0},
|
||||
'RF': {'player': None, 'vl': None, 'vr': None, 'ops': 0},
|
||||
'DH': {'player': None, 'vl': None, 'vr': None, 'ops': 0}
|
||||
}
|
||||
|
||||
def get_bratings(player_id):
|
||||
this_bcard = BattingCard.get_or_none(BattingCard.player_id == player_id)
|
||||
vl_ratings = BattingCardRatings.get_or_none(
|
||||
BattingCardRatings.battingcard == this_bcard, BattingCardRatings.vs_hand == 'L'
|
||||
)
|
||||
vl_ops = vl_ratings.obp + vl_ratings.slg
|
||||
vr_ratings = BattingCardRatings.get_or_none(
|
||||
BattingCardRatings.battingcard == this_bcard, BattingCardRatings.vs_hand == 'R'
|
||||
)
|
||||
vr_ops = vr_ratings.obp + vr_ratings.slg
|
||||
return model_to_dict(vl_ratings), model_to_dict(vr_ratings), (vl_ops + vr_ops + min(vl_ops, vr_ops)) / 3
|
||||
|
||||
for position in starting_nine.keys():
|
||||
if position == 'DH':
|
||||
# all_bcards = BattingCard.select().where(BattingCard.player << legal_players)
|
||||
# all_batters = BattingCardRatings.select().where(
|
||||
# BattingCardRatings.battingcard << all_bcards
|
||||
# ).order_by(BattingCardRatings.obp + BattingCardRatings.sl)
|
||||
#
|
||||
# for x in all_batters:
|
||||
# if x.battingcard.player.p_name not in player_names:
|
||||
# starting_nine['DH'] = x.battingcard.player
|
||||
# break
|
||||
logging.info(f'Searching for a DH!')
|
||||
dh_query = legal_players.order_by(Player.cost.desc())
|
||||
for x in dh_query:
|
||||
logging.info(f'checking {x.p_name} for {position}')
|
||||
if x.p_name not in player_names and 'P' not in x.pos_1:
|
||||
logging.info(f'adding!')
|
||||
starting_nine['DH']['player'] = model_to_dict(x)
|
||||
try:
|
||||
vl, vr, total_ops = get_bratings(x.player_id)
|
||||
except AttributeError as e:
|
||||
logging.info(f'Could not find batting lines')
|
||||
else:
|
||||
starting_nine['DH']['vl'] = vl
|
||||
starting_nine['DH']['vr'] = vr
|
||||
starting_nine['DH']['ops'] = total_ops
|
||||
player_names.append(x.p_name)
|
||||
break
|
||||
|
||||
if starting_nine['DH']['player'] is None:
|
||||
dh_query = backup_players.order_by(Player.cost.desc())
|
||||
for x in dh_query:
|
||||
logging.info(f'checking {x.p_name} for {position}')
|
||||
if x.p_name not in player_names:
|
||||
logging.info(f'adding!')
|
||||
starting_nine['DH']['player'] = model_to_dict(x)
|
||||
try:
|
||||
vl, vr, total_ops = get_bratings(x.player_id)
|
||||
except AttributeError as e:
|
||||
logging.info(f'Could not find batting lines')
|
||||
else:
|
||||
vl, vr, total_ops = get_bratings(x.player_id)
|
||||
starting_nine['DH']['vl'] = vl
|
||||
starting_nine['DH']['vr'] = vr
|
||||
starting_nine['DH']['ops'] = total_ops
|
||||
player_names.append(x.p_name)
|
||||
break
|
||||
|
||||
else:
|
||||
pos_group = CardPosition.select().where(
|
||||
(CardPosition.position == position) & (CardPosition.player << legal_players)
|
||||
)
|
||||
backup_group = CardPosition.select().where(
|
||||
(CardPosition.position == position) & (CardPosition.player << backup_players)
|
||||
)
|
||||
if difficulty_name == 'minor-league':
|
||||
pos_group = pos_group.order_by(CardPosition.innings.desc())
|
||||
elif d_rank == 10:
|
||||
pos_group = pos_group.order_by((CardPosition.range * 5) + CardPosition.error)
|
||||
elif d_rank == 9:
|
||||
pos_group = pos_group.order_by(CardPosition.range)
|
||||
elif d_rank == 8:
|
||||
pos_group = pos_group.order_by(CardPosition.error.desc())
|
||||
|
||||
logging.info(f'pos_group: {pos_group}\n{starting_nine}\n{player_names}\n\n')
|
||||
if difficulty_name == 'minor-league':
|
||||
for x in pos_group:
|
||||
logging.info(f'checking {x.player.p_name} for {position}')
|
||||
if x.player.p_name not in player_names and x.player.p_name.lower() != pitcher_name:
|
||||
logging.info(f'adding!')
|
||||
starting_nine[position]['player'] = model_to_dict(x.player)
|
||||
vl, vr, total_ops = get_bratings(x.player.player_id)
|
||||
starting_nine[position]['vl'] = vl
|
||||
starting_nine[position]['vr'] = vr
|
||||
starting_nine[position]['ops'] = total_ops
|
||||
player_names.append(x.player.p_name)
|
||||
break
|
||||
|
||||
if starting_nine[position]['player'] is None:
|
||||
for x in backup_group:
|
||||
logging.info(f'checking {x.player.p_name} for {position}')
|
||||
if x.player.p_name not in player_names and x.player.p_name.lower() != pitcher_name:
|
||||
logging.info(f'adding!')
|
||||
starting_nine[position]['player'] = model_to_dict(x.player)
|
||||
vl, vr, total_ops = get_bratings(x.player.player_id)
|
||||
starting_nine[position]['vl'] = vl
|
||||
starting_nine[position]['vr'] = vr
|
||||
starting_nine[position]['ops'] = total_ops
|
||||
player_names.append(x.player.p_name)
|
||||
break
|
||||
|
||||
# all_bcards = BattingCard.select().where(BattingCard.player << starting_nine.values())
|
||||
# all_ratings = BattingCardRatings.select().where(BattingCardRatings.battingcard << all_bcards)
|
||||
#
|
||||
# vl_query = all_ratings.where(BattingCardRatings.vs_hand == 'L')
|
||||
# vr_query = all_ratings.where(BattingCardRatings.vs_hand == 'R')
|
||||
#
|
||||
# vl_vals = [model_to_dict(x) for x in vl_query]
|
||||
# for x in vl_vals:
|
||||
# x.update(x['battingcard'])
|
||||
# x['player_id'] = x['battingcard']['player']['player_id']
|
||||
# x['player_name'] = x['battingcard']['player']['p_name']
|
||||
# x['rarity'] = x['battingcard']['player']['rarity']['name']
|
||||
# x['cardset_id'] = x['battingcard']['player']['cardset']['id']
|
||||
# x['cardset_name'] = x['battingcard']['player']['cardset']['name']
|
||||
# del x['player']
|
||||
#
|
||||
# vr_vals = [model_to_dict(x) for x in vr_query]
|
||||
# for x in vr_vals:
|
||||
# x['player_id'] = x['battingcard']['player']['player_id']
|
||||
# del x['battingcard']
|
||||
#
|
||||
# vl = pd.DataFrame(vl_vals)
|
||||
# vr = pd.DataFrame(vr_vals)
|
||||
# db.close()
|
||||
#
|
||||
# output = pd.merge(vl, vr, on='player_id', suffixes=('_vl', '_vr'))
|
||||
#
|
||||
# def get_total_ops(df_data):
|
||||
# ops_vl = df_data['obp_vL'] + df_data['slg_vL']
|
||||
# ops_vr = df_data['obp_vR'] + df_data['slg_vR']
|
||||
# return (ops_vr + ops_vl + min(ops_vl, ops_vr)) / 3
|
||||
# output['total_OPS'] = output.apply(get_total_ops, axis=1)
|
||||
# output = output.sort_values(by=['total_OPS'], ascending=False)
|
||||
|
||||
sorted_nine = sorted(starting_nine.items(), key=lambda item: item[1]['ops'], reverse=True)
|
||||
return {
|
||||
'json': dict(sorted_nine),
|
||||
'array': sorted_nine
|
||||
}
|
||||
|
||||
|
||||
@router.get('/{team_id}/sp/{difficulty_name}')
|
||||
async def get_team_sp(team_id: int, difficulty_name: str, sp_rank: int):
|
||||
logging.info(f'get_team_sp - team_id: {team_id} / difficulty_name: {difficulty_name} / sp_rank: {sp_rank}')
|
||||
this_team = Team.get_or_none(Team.id == team_id)
|
||||
if this_team is None:
|
||||
db.close()
|
||||
raise HTTPException(status_code=404, detail=f'Team id {team_id} not found')
|
||||
|
||||
if difficulty_name not in CARDSETS.keys():
|
||||
db.close()
|
||||
raise HTTPException(status_code=400, detail=f'Difficulty name {difficulty_name} not a valid check')
|
||||
|
||||
all_players = Player.select().where(Player.mlbclub == this_team.lname)
|
||||
|
||||
legal_players = all_players.where(Player.cardset_id << CARDSETS[difficulty_name]['primary'])
|
||||
if 'secondary' in CARDSETS[difficulty_name]:
|
||||
backup_players = all_players.where(Player.cardset_id << CARDSETS[difficulty_name]['secondary'])
|
||||
else:
|
||||
backup_players = None
|
||||
|
||||
def sort_starters(starter_query) -> DataFrame | None:
|
||||
all_s = [model_to_dict(x, recurse=False) for x in starter_query]
|
||||
if len(all_s) == 0:
|
||||
logging.error(f'Empty starter_query: {starter_query}')
|
||||
return None
|
||||
|
||||
starter_df = pd.DataFrame(all_s).set_index('player', drop=False)
|
||||
logging.debug(f'starter_df: {starter_df}')
|
||||
|
||||
def get_total_ops(df_data):
|
||||
vlval = PitchingCardRatings.get_or_none(
|
||||
PitchingCardRatings.pitchingcard_id == df_data['id'], PitchingCardRatings.vs_hand == 'L')
|
||||
vrval = PitchingCardRatings.get_or_none(
|
||||
PitchingCardRatings.pitchingcard_id == df_data['id'], PitchingCardRatings.vs_hand == 'R')
|
||||
|
||||
ops_vl = vlval.obp + vlval.slg
|
||||
ops_vr = vrval.obp + vrval.slg
|
||||
return (ops_vr + ops_vl + min(ops_vl, ops_vr)) / 3
|
||||
|
||||
starter_df['total_ops'] = starter_df.apply(get_total_ops, axis=1)
|
||||
return starter_df.sort_values(by='total_ops')
|
||||
|
||||
# Find SP in primary cardsets
|
||||
s_query = PitchingCard.select().join(Player).where(
|
||||
(PitchingCard.player << legal_players) & (PitchingCard.starter_rating >= 4)
|
||||
)
|
||||
all_starters = sort_starters(s_query)
|
||||
logging.debug(f'sorted: {all_starters}')
|
||||
|
||||
if all_starters is not None and len(all_starters.index) >= sp_rank:
|
||||
this_player_id = all_starters.iloc[sp_rank - 1].player
|
||||
this_player = model_to_dict(Player.get_by_id(this_player_id), recurse=False)
|
||||
db.close()
|
||||
return this_player
|
||||
|
||||
if all_starters is not None and len(all_starters.index) > 0:
|
||||
this_player_id = all_starters.iloc[len(all_starters.index) - 1].player
|
||||
this_player = model_to_dict(Player.get_by_id(this_player_id), recurse=False)
|
||||
db.close()
|
||||
return this_player
|
||||
|
||||
# Include backup cardsets
|
||||
s_query = PitchingCard.select().where(
|
||||
(PitchingCard.player << backup_players) & (PitchingCard.starter_rating >= 4)
|
||||
)
|
||||
all_starters = sort_starters(s_query)
|
||||
logging.debug(f'sorted: {all_starters}')
|
||||
|
||||
if all_starters is not None and len(all_starters.index) >= sp_rank:
|
||||
this_player_id = all_starters.iloc[sp_rank - 1].player
|
||||
this_player = model_to_dict(Player.get_by_id(this_player_id), recurse=False)
|
||||
db.close()
|
||||
return this_player
|
||||
|
||||
if all_starters is not None and len(all_starters.index) > 0:
|
||||
this_player_id = all_starters.iloc[len(all_starters.index) - 1].player
|
||||
this_player = model_to_dict(Player.get_by_id(this_player_id), recurse=False)
|
||||
db.close()
|
||||
return this_player
|
||||
|
||||
raise HTTPException(status_code=500, detail=f'No SP #{sp_rank} found for Team {team_id}')
|
||||
|
||||
|
||||
@router.get('/{team_id}/buy/players')
|
||||
async def team_buy_players(team_id: int, ids: str, ts: str):
|
||||
try:
|
||||
|
||||
Loading…
Reference in New Issue
Block a user