107 lines
3.9 KiB
Python
107 lines
3.9 KiB
Python
import pandas as pd
|
|
import pydantic
|
|
from pydantic import root_validator, validator
|
|
from typing import Literal, Optional
|
|
|
|
|
|
class DataMismatchError(Exception):
|
|
pass
|
|
|
|
|
|
class BattingCardModel(pydantic.BaseModel):
|
|
player_id: Optional[int] = None
|
|
variant: int = 0
|
|
steal_low: int = 3
|
|
steal_high: int = 20
|
|
steal_auto: bool = False
|
|
steal_jump: float = 0
|
|
bunting: str = 'C'
|
|
hit_and_run: str = 'C'
|
|
running: int = 10
|
|
offense_col: int = None
|
|
hand: Literal['R', 'L', 'S'] = 'R'
|
|
|
|
|
|
class CardPositionModel(pydantic.BaseModel):
|
|
player_id: int
|
|
variant: int = 0
|
|
position: Literal['P', 'C', '1B', '2B', '3B', 'SS', 'LF', 'CF', 'RF', 'DH']
|
|
innings: int = 1
|
|
range: int = 5
|
|
error: int = 0
|
|
arm: Optional[int] = None
|
|
pb: Optional[int] = None
|
|
overthrow: Optional[int] = None
|
|
|
|
@root_validator
|
|
def position_validator(cls, values):
|
|
if values['position'] in ['C', 'LF', 'CF', 'RF'] and values['arm'] is None:
|
|
raise ValueError(f'{values["position"]} must have an arm rating')
|
|
if values['position'] == 'C' and (values['pb'] is None or values['overthrow'] is None):
|
|
raise ValueError('Catchers must have a pb and overthrow rating')
|
|
return values
|
|
|
|
|
|
class BattingCardRatingsModel(pydantic.BaseModel):
|
|
battingcard_id: int
|
|
vs_hand: Literal['R', 'L', 'vR', 'vL']
|
|
homerun: float = 0.0
|
|
bp_homerun: float = 0.0
|
|
triple: float = 0.0
|
|
double_three: float = 0.0
|
|
double_two: float = 0.0
|
|
double_pull: float = 0.0
|
|
single_two: float = 0.0
|
|
single_one: float = 0.0
|
|
single_center: float = 0.0
|
|
bp_single: float = 0.0
|
|
hbp: float = 0.0
|
|
walk: float = 0.0
|
|
strikeout: float = 0.0
|
|
lineout: float = 0.0
|
|
popout: float = 0.0
|
|
flyout_a: float = 0.0
|
|
flyout_bq: float = 0.0
|
|
flyout_lf_b: float = 0.0
|
|
flyout_rf_b: float = 0.0
|
|
groundout_a: float = 0.0
|
|
groundout_b: float = 0.0
|
|
groundout_c: float = 0.0
|
|
avg: float = 0.0
|
|
obp: float = 0.0
|
|
slg: float = 0.0
|
|
pull_rate: float = 0.0
|
|
center_rate: float = 0.0
|
|
slap_rate: float = 0.0
|
|
|
|
@validator("avg", always=True)
|
|
def avg_validator(cls, v, values, **kwargs):
|
|
return (values['homerun'] + values['bp_homerun'] / 2 + values['triple'] + values['double_three'] +
|
|
values['double_two'] + values['double_pull'] + values['single_two'] + values['single_one'] +
|
|
values['single_center'] + values['bp_single'] / 2) / 108
|
|
|
|
@validator("obp", always=True)
|
|
def obp_validator(cls, v, values, **kwargs):
|
|
return ((values['hbp'] + values['walk']) / 108) + values['avg']
|
|
|
|
@validator("slg", always=True)
|
|
def slg_validator(cls, v, values, **kwargs):
|
|
return (values['homerun'] * 4 + values['bp_homerun'] * 2 + values['triple'] * 3 + values['double_three'] * 2 +
|
|
values['double_two'] * 2 + values['double_pull'] * 2 + values['single_two'] + values['single_one'] +
|
|
values['single_center'] + values['bp_single'] / 2) / 108
|
|
|
|
@root_validator
|
|
def validate_chance_total(cls, values):
|
|
total_chances = (
|
|
values['homerun'] + values['bp_homerun'] + values['triple'] + values['double_three'] +
|
|
values['double_two'] + values['double_pull'] + values['single_two'] + values['single_one'] +
|
|
values['single_center'] + values['bp_single'] + values['hbp'] + values['walk'] +
|
|
values['strikeout'] + values['lineout'] + values['popout'] + values['flyout_a'] +
|
|
values['flyout_bq'] + values['flyout_lf_b'] + values['flyout_rf_b'] + values['groundout_a'] +
|
|
values['groundout_b'] + values['groundout_c'])
|
|
|
|
if round(total_chances) != 108:
|
|
raise ValueError(f'BC {values["battingcard_id"]} must have exactly 108 chances on the card '
|
|
f'{values["vs_hand"]}; {round(total_chances)} listed')
|
|
return values
|