paper-dynasty-card-creation/calcs_batter.py
2023-09-19 09:38:18 -05:00

339 lines
9.0 KiB
Python

import pydantic
from creation_helpers import mround
from typing import Literal
class BattingCardRatingsModel(pydantic.BaseModel):
vs_hand: Literal['R', 'L', 'vR', 'vL']
all_hits: float = 0.0
other_ob: float = 0.0
all_outs: float = 0.0
all_singles: float = 0.0
all_xbh: float = 0.0
all_hr: float = 0.0
all_doubles: float = 0.0
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
def total_chances(self):
return sum([
self.homerun, self.bp_homerun, self.triple, self.double_three, self.double_two, self.double_pull,
self.single_two, self.single_one, self.single_center, self.bp_single, self.hbp, self.walk, self.strikeout,
self.lineout, self.popout, self.flyout_a, self.flyout_bq, self.flyout_lf_b, self.flyout_rf_b,
self.groundout_a, self.groundout_b, self.groundout_c
])
def rem_hits(self):
return (self.all_hits -
sum([
self.homerun, self.bp_homerun, self.triple, self.double_three, self.double_two, self.double_pull,
self.single_two, self.single_one, self.single_center, self.bp_single
]))
def rem_outs(self):
return (self.all_outs -
sum([
self.strikeout, self.lineout, self.popout, self.flyout_a, self.flyout_bq, self.flyout_lf_b,
self.flyout_rf_b, self.groundout_a, self.groundout_b, self.groundout_c
]))
def rem_other_ob(self):
return self.other_ob - self.hbp - self.walk
def total_chances(chance_data):
sum_chances = 0
for key in chance_data:
if key not in ['id', 'player_id', 'cardset_id', 'vs_hand', 'is_prep']:
sum_chances += chance_data[key]
return mround(sum_chances)
def bp_singles(all_singles):
if all_singles < 6:
return 0
else:
return 5
def wh_singles(rem_singles, hard_rate):
if rem_singles == 0 or hard_rate < .2:
return 0
elif hard_rate > .4:
return mround(rem_singles * .666)
else:
return mround(rem_singles * .333)
def one_singles(rem_singles, ifh_rate, force_rem):
if force_rem:
return mround(rem_singles)
elif rem_singles == 0 or ifh_rate < .05:
return 0
else:
return mround(rem_singles * ifh_rate * 3)
def all_homeruns(rem_hits, all_hits, hrs, hits, singles):
if rem_hits == 0 or all_hits == 0 or hrs == 0 or hits - singles == 0:
return 0
else:
return mround(min(rem_hits, all_hits * ((hrs * 1.15) / hits)))
def nd_homeruns(all_hr, hr_rate):
if all_hr == 0 or hr_rate == 0:
return 0
elif hr_rate > .2:
return mround(all_hr * .6)
else:
return mround(all_hr * .25)
def triples(all_xbh, tr_count, do_count):
if all_xbh == 0 or tr_count == 0:
return 0
else:
return mround(all_xbh * (tr_count / (tr_count + do_count)))
def two_doubles(all_doubles, soft_rate):
if all_doubles == 0 or soft_rate == 0:
return 0
elif soft_rate > .2:
return mround(all_doubles / 2)
else:
return mround(all_doubles / 4)
def hit_by_pitch(other_ob, hbps, walks):
if hbps == 0 or other_ob * (hbps / (hbps + walks)) < 1:
return 0
else:
return mround(other_ob * (hbps / (hbps + walks)), base=1.0)
def strikeouts(all_outs, k_rate):
if all_outs == 0 or k_rate == 0:
return 0
else:
return mround(all_outs * k_rate)
def flyout_a(all_flyouts, hard_rate):
if all_flyouts == 0 or hard_rate < .4:
return 0
else:
return 1
def flyout_bq(rem_flyouts, soft_rate):
if rem_flyouts == 0 or soft_rate < .1:
return 0
else:
return mround(rem_flyouts * soft_rate * 3)
def flyout_b(rem_flyouts, pull_rate, cent_rate):
if rem_flyouts == 0 or pull_rate == 0:
return 0
else:
return mround(rem_flyouts * (pull_rate + cent_rate / 2))
def popouts(rem_outs, iffb_rate):
if rem_outs == 0 or iffb_rate * rem_outs < 1:
return 0
else:
return mround(rem_outs * iffb_rate)
def groundball_a(all_groundouts, gidps, abs):
if all_groundouts == 0 or gidps == 0:
return 0
else:
return mround((min(gidps ** 2.5, abs) / abs) * all_groundouts)
def groundball_c(rem_groundouts, med_rate):
if rem_groundouts == 0 or med_rate < .4:
return 0
elif med_rate > .6:
return mround(rem_groundouts)
else:
return mround(rem_groundouts * med_rate)
def stealing(chances: int, sb2s: int, cs2s: int, sb3s: int, cs3s: int, season_pct: float):
if chances == 0 or sb2s + cs2s == 0:
return 0, 0, False, 0
total_attempts = sb2s + cs2s + sb3s + cs3s
attempt_pct = total_attempts / chances
if attempt_pct >= .08:
st_auto = True
else:
st_auto = False
# chance_odds = [x / 36 for x in range(1, 36)]
st_jump = 0
for x in range(1, 37):
if attempt_pct * 1.5 <= x / 36:
st_jump = x / 36
break
st_high = mround(20 * (sb2s / (sb2s + cs2s + cs2s)))
if st_high <= 10:
st_auto = False
if sb3s + cs3s < max((3 * season_pct), 1):
st_low = 3
else:
st_low = mround(16 * ((sb2s + sb3s) / (sb2s + sb3s + cs2s * 2 + cs3s * 2)))
if not st_auto:
st_low = min(st_low, 10)
if st_low >= st_high - 3:
if st_high == 0:
st_low = 0
st_jump = 0
elif st_high <= 3:
st_high = 4
st_low = 1
else:
st_low = st_high - 3
# if ((st_high - 7) > st_low) and st_high > 7:
# st_low = st_high - 7
return round(st_low), round(st_high), st_auto, st_jump
def stealing_line(steal_data: dict):
sd = steal_data
jump_chances = round(sd[3] * 36)
if jump_chances == 0:
good_jump = '-'
elif jump_chances <= 6:
if jump_chances == 6:
good_jump = 7
elif jump_chances == 5:
good_jump = 6
elif jump_chances == 4:
good_jump = 5
elif jump_chances == 3:
good_jump = 4
elif jump_chances == 2:
good_jump = 3
elif jump_chances == 1:
good_jump = 2
elif jump_chances == 7:
good_jump = '4,5'
elif jump_chances == 8:
good_jump = '4,6'
elif jump_chances == 9:
good_jump = '3-5'
elif jump_chances == 10:
good_jump = '2-5'
elif jump_chances == 11:
good_jump = '6,7'
elif jump_chances == 12:
good_jump = '4-6'
elif jump_chances == 13:
good_jump = '2,4-6'
elif jump_chances == 14:
good_jump = '3-6'
elif jump_chances == 15:
good_jump = '2-6'
elif jump_chances == 16:
good_jump = '2,5-6'
elif jump_chances == 17:
good_jump = '3,5-6'
elif jump_chances == 18:
good_jump = '4-6'
elif jump_chances == 19:
good_jump = '2,4-7'
elif jump_chances == 20:
good_jump = '3-7'
elif jump_chances == 21:
good_jump = '2-7'
elif jump_chances == 22:
good_jump = '2-7,12'
elif jump_chances == 23:
good_jump = '2-7,11'
elif jump_chances == 24:
good_jump = '2,4-8'
elif jump_chances == 25:
good_jump = '3-8'
elif jump_chances == 26:
good_jump = '2-8'
elif jump_chances == 27:
good_jump = '2-8,12'
elif jump_chances == 28:
good_jump = '2-8,11'
elif jump_chances == 29:
good_jump = '3-9'
elif jump_chances == 30:
good_jump = '2-9'
elif jump_chances == 31:
good_jump = '2-9,12'
elif jump_chances == 32:
good_jump = '2-9,11'
elif jump_chances == 33:
good_jump = '2-10'
elif jump_chances == 34:
good_jump = '3-11'
elif jump_chances == 35:
good_jump = '2-11'
else:
good_jump = '2-12'
return f'{"*" if sd[2] else ""}{good_jump}/- ({sd[1] if sd[1] else "-"}-{sd[0] if sd[0] else "-"})'
def running(extra_base_pct: str):
if extra_base_pct == '':
return 8
xb_pct = float(extra_base_pct.strip("%")) / 100
return round(8 + (10 * xb_pct))
def hit_and_run(ab_vl: int, ab_vr: int, hits_vl: int, hits_vr: int, hr_vl: int, hr_vr: int, so_vl: int, so_vr: int):
babip = (hits_vr + hits_vl - hr_vl - hr_vr) / (ab_vl + ab_vr - so_vl - so_vr - hr_vl - hr_vl)
if babip >= .35:
return 'A'
elif babip >= .3:
return 'B'
elif babip >= .25:
return 'C'
else:
return 'D'