paper-dynasty-card-creation/creation_helpers.py
Cal Corum dca8eaa8cd Update creation_helpers.py
add DH support
2023-02-24 21:47:37 -06:00

691 lines
19 KiB
Python
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import csv
import random
import logging
from db_calls_card_creation import *
D20_CHANCES = {
'2': {
'chances': 1,
'inc': .05
},
'3': {
'chances': 2,
'inc': .1
},
'4': {
'chances': 3,
'inc': .15
},
'5': {
'chances': 4,
'inc': .2
},
'6': {
'chances': 5,
'inc': .25
},
'7': {
'chances': 6,
'inc': .3
},
'8': {
'chances': 5,
'inc': .25
},
'9': {
'chances': 4,
'inc': .2
},
'10': {
'chances': 3,
'inc': .15
},
'11': {
'chances': 2,
'inc': .1
},
'12': {
'chances': 1,
'inc': .05
}
}
BLANK_RESULTS = {
'vL': {
'1': {
'2': {
'result': None,
'splits': None,
'2d6': None
},
'3': {
'result': None,
'splits': None,
'2d6': None
},
'4': {
'result': None,
'splits': None,
'2d6': None
},
'5': {
'result': None,
'splits': None,
'2d6': None
},
'6': {
'result': None,
'splits': None,
'2d6': None
},
'7': {
'result': None,
'splits': None,
'2d6': None
},
'8': {
'result': None,
'splits': None,
'2d6': None
},
'9': {
'result': None,
'splits': None,
'2d6': None
},
'10': {
'result': None,
'splits': None,
'2d6': None
},
'11': {
'result': None,
'splits': None,
'2d6': None
},
'12': {
'result': None,
'splits': None,
'2d6': None
},
'splits': 0
},
'2': {
'2': {
'result': None,
'splits': None,
'2d6': None
},
'3': {
'result': None,
'splits': None,
'2d6': None
},
'4': {
'result': None,
'splits': None,
'2d6': None
},
'5': {
'result': None,
'splits': None,
'2d6': None
},
'6': {
'result': None,
'splits': None,
'2d6': None
},
'7': {
'result': None,
'splits': None,
'2d6': None
},
'8': {
'result': None,
'splits': None,
'2d6': None
},
'9': {
'result': None,
'splits': None,
'2d6': None
},
'10': {
'result': None,
'splits': None,
'2d6': None
},
'11': {
'result': None,
'splits': None,
'2d6': None
},
'12': {
'result': None,
'splits': None,
'2d6': None
},
'splits': 0
},
'3': {
'2': {
'result': None,
'splits': None,
'2d6': None
},
'3': {
'result': None,
'splits': None,
'2d6': None
},
'4': {
'result': None,
'splits': None,
'2d6': None
},
'5': {
'result': None,
'splits': None,
'2d6': None
},
'6': {
'result': None,
'splits': None,
'2d6': None
},
'7': {
'result': None,
'splits': None,
'2d6': None
},
'8': {
'result': None,
'splits': None,
'2d6': None
},
'9': {
'result': None,
'splits': None,
'2d6': None
},
'10': {
'result': None,
'splits': None,
'2d6': None
},
'11': {
'result': None,
'splits': None,
'2d6': None
},
'12': {
'result': None,
'splits': None,
'2d6': None
},
'splits': 0
}
},
'vR': {
'1': {
'2': {
'result': None,
'splits': None,
'2d6': None
},
'3': {
'result': None,
'splits': None,
'2d6': None
},
'4': {
'result': None,
'splits': None,
'2d6': None
},
'5': {
'result': None,
'splits': None,
'2d6': None
},
'6': {
'result': None,
'splits': None,
'2d6': None
},
'7': {
'result': None,
'splits': None,
'2d6': None
},
'8': {
'result': None,
'splits': None,
'2d6': None
},
'9': {
'result': None,
'splits': None,
'2d6': None
},
'10': {
'result': None,
'splits': None,
'2d6': None
},
'11': {
'result': None,
'splits': None,
'2d6': None
},
'12': {
'result': None,
'splits': None,
'2d6': None
},
'splits': 0
},
'2': {
'2': {
'result': None,
'splits': None,
'2d6': None
},
'3': {
'result': None,
'splits': None,
'2d6': None
},
'4': {
'result': None,
'splits': None,
'2d6': None
},
'5': {
'result': None,
'splits': None,
'2d6': None
},
'6': {
'result': None,
'splits': None,
'2d6': None
},
'7': {
'result': None,
'splits': None,
'2d6': None
},
'8': {
'result': None,
'splits': None,
'2d6': None
},
'9': {
'result': None,
'splits': None,
'2d6': None
},
'10': {
'result': None,
'splits': None,
'2d6': None
},
'11': {
'result': None,
'splits': None,
'2d6': None
},
'12': {
'result': None,
'splits': None,
'2d6': None
},
'splits': 0
},
'3': {
'2': {
'result': None,
'splits': None,
'2d6': None
},
'3': {
'result': None,
'splits': None,
'2d6': None
},
'4': {
'result': None,
'splits': None,
'2d6': None
},
'5': {
'result': None,
'splits': None,
'2d6': None
},
'6': {
'result': None,
'splits': None,
'2d6': None
},
'7': {
'result': None,
'splits': None,
'2d6': None
},
'8': {
'result': None,
'splits': None,
'2d6': None
},
'9': {
'result': None,
'splits': None,
'2d6': None
},
'10': {
'result': None,
'splits': None,
'2d6': None
},
'11': {
'result': None,
'splits': None,
'2d6': None
},
'12': {
'result': None,
'splits': None,
'2d6': None
},
'splits': 0
}
}
}
TESTING = False
YES = ['y', 'yes', 'yeet', 'please', 'yeah']
def mround(x, prec=2, base=.05):
return round(base * round(float(x) / base), prec)
def chances_from_row(row_num):
if row_num == '2' or row_num == '12':
return 1
if row_num == '3' or row_num == '11':
return 2
if row_num == '4' or row_num == '10':
return 3
if row_num == '5' or row_num == '9':
return 4
if row_num == '6' or row_num == '8':
return 5
if row_num == '7':
return 6
raise ValueError(f'No chance count found for row_num {row_num}')
def legal_splits(tot_chances):
legal_2d6 = []
for x in D20_CHANCES:
num_incs = mround(tot_chances) / D20_CHANCES[x]['inc']
if num_incs - int(num_incs) == 0 and int(20 - num_incs) > 0:
legal_2d6.append({
'2d6': int(x),
'incs': int(num_incs),
'bad_chances': mround(D20_CHANCES[x]['chances'] * (int(20 - num_incs) / 20)),
'bad_incs': int(20 - num_incs)
})
random.shuffle(legal_2d6)
# if TESTING: print(f'tot_chances: {myround(tot_chances)}')
# if TESTING: print(f'legal_2d6: {legal_2d6}')
return legal_2d6
def result_string(tba_data, row_num, split_min=None, split_max=None):
bold1 = f'{"<b>" if tba_data["bold"] else ""}'
bold2 = f'{"</b>" if tba_data["bold"] else ""}'
row_string = f'{"<b> </b>" if int(row_num) < 10 else ""}{row_num}'
if TESTING: print(f'adding {tba_data["string"]} to row {row_num} / '
f'split_min: {split_min} / split_max: {split_max}')
# No splits; standard result
if not split_min:
return f'{bold1}{row_string}-{tba_data["string"]}{bold2}'
# With splits
split_nums = f'{split_min if split_min != 20 else ""}{"-" if split_min != 20 else ""}{split_max}'
data_string = tba_data["sm-string"] if "sm-string" in tba_data.keys() else tba_data["string"]
spaces = 18 - len(data_string) - len(split_nums)
if 'WALK' in data_string:
spaces -= 3
elif 'SI**' in data_string:
spaces += 1
elif 'DO*' in data_string:
spaces -= 1
elif 'DO*' in data_string:
spaces -= 2
elif 'so' in data_string:
spaces += 3
elif 'gb' in data_string:
spaces -= 3
if TESTING: print(f'len(tba_data["string"]): {len(data_string)} / len(split_nums): {len(split_nums)} '
f'spaces: {spaces}')
if split_min == 1 or split_min is None:
row_output = f'{row_string}-'
else:
row_output = '<b> </b>'
if TESTING: print(f'row_output: {row_output}')
return f'{bold1}{row_output}{data_string}{" " * spaces}{split_nums}{bold2}'
def result_data(tba_data, row_num, tba_data_bottom=None, top_split_max=None, fatigue=False):
ret_data = {}
top_bold1 = f'{"<b>" if tba_data["bold"] else ""}'
top_bold2 = f'{"</b>" if tba_data["bold"] else ""}'
bot_bold1 = None
bot_bold2 = None
if tba_data_bottom:
bot_bold1 = f'{"<b>" if tba_data_bottom["bold"] else ""}'
bot_bold2 = f'{"</b>" if tba_data_bottom["bold"] else ""}'
if tba_data_bottom is None:
ret_data['2d6'] = f'{top_bold1}{int(row_num)}-{top_bold2}'
ret_data['splits'] = f'{top_bold1}{top_bold2}'
ret_data['result'] = f'{top_bold1}' \
f'{tba_data["string"]}{"" if fatigue else ""}' \
f'{top_bold2}'
else:
ret_data['2d6'] = f'{top_bold1}{int(row_num)}-{top_bold2}\n'
ret_data['splits'] = f'{top_bold1}1{"-" if top_split_max != 1 else ""}' \
f'{top_split_max if top_split_max != 1 else ""}{top_bold2}\n' \
f'{bot_bold1}{top_split_max+1}{"-20" if top_split_max != 19 else ""}{bot_bold2}'
ret_data['result'] = \
f'{top_bold1}{tba_data["sm-string"] if "sm-string" in tba_data.keys() else tba_data["string"]}' \
f'{top_bold2}\n' \
f'{bot_bold1}' \
f'{tba_data_bottom["sm-string"] if "sm-string" in tba_data_bottom.keys() else tba_data_bottom["string"]}' \
f'{bot_bold2}'
return ret_data
def get_of(batter_hand, pitcher_hand, pull_side=True):
if batter_hand == 'R':
return 'lf' if pull_side else 'rf'
if batter_hand == 'L':
return 'rf' if pull_side else 'lf'
if batter_hand == 'S':
if pitcher_hand == 'L':
return 'rf' if pull_side else 'rf'
else:
return 'lf' if pull_side else 'lf'
def get_col(col_num):
if col_num == '1':
return 'one'
if col_num == '2':
return 'two'
if col_num == '3':
return 'three'
def write_to_csv(output_path, file_name: str, row_data: list):
# Build the csv output
fpath = (output_path / f'{file_name}').with_suffix('.csv')
# logging.info(f'Printing following data to {file_name}:\n\n{row_data}')
with fpath.open(mode='w+', newline='', encoding='utf-8') as csv_File:
writer = csv.writer(csv_File)
writer.writerows(row_data)
def get_position_string(all_pos: list, inc_p: bool):
if len(all_pos) == 0:
return 'dh'
of_arm = None
of_error = None
of_innings = None
lf_range = None
lf_innings = 0
cf_range = None
cf_innings = 0
rf_range = None
rf_innings = 0
all_def = []
for x in all_pos:
if x.position == 'OF':
of_arm = f'{"+" if "-" not in x.arm else ""}{x.arm}'
of_error = x.error
of_innings = x.innings
elif x.position == 'CF':
cf_range = x.range
cf_innings = x.innings
elif x.position == 'LF':
lf_range = x.range
lf_innings = x.innings
elif x.position == 'RF':
rf_range = x.range
rf_innings = x.innings
elif x.position == 'C':
all_def.append((f'c-{x.range}({x.arm}) e{x.error} T-{x.overthrow}(pb-{x.pb})', x.innings))
elif 'P' in x.position and not inc_p:
pass
else:
all_def.append((f'{x.position.lower()}-{x.range}e{x.error}', x.innings))
if of_arm is not None:
all_of = []
if lf_innings > 0:
all_of.append((lf_range, lf_innings, 'lf'))
if cf_innings > 0:
all_of.append((cf_range, cf_innings, 'cf'))
if rf_innings > 0:
all_of.append((rf_range, rf_innings, 'rf'))
if len(all_of) > 0:
all_of.sort(key=lambda y: y[1], reverse=True)
out_string = f'{all_of[0][2]}-{all_of[0][0]}({of_arm})e{of_error}'
if len(all_of) == 2:
out_string += f', {all_of[1][2]}-{all_of[1][0]}e{of_error}'
if len(all_of) == 3:
out_string += f', {all_of[2][2]}-{all_of[2][0]}e{of_error}'
all_def.append((out_string, of_innings))
all_def.sort(key=lambda z: z[1], reverse=True)
final_defense = ''
for x in all_def:
if len(final_defense) > 0:
final_defense += f', '
final_defense += f'{x[0]}'
return final_defense
def ordered_positions(all_pos: list) -> list:
if len(all_pos) == 0:
return ['DH']
all_def = []
for x in all_pos:
if x.position not in ['OF', 'P', 'SP', 'RP', 'CP']:
all_def.append((x.innings, x.position))
all_def.sort(key=lambda y: y[0], reverse=True)
return [x[1] for x in all_def]
def ordered_pitching_positions(all_pos: list) -> list:
all_def = []
for x in all_pos:
if x.position in ['SP', 'RP', 'CP']:
all_def.append((x.innings, x.position))
all_def.sort(key=lambda y: y[0], reverse=True)
return [x[1] for x in all_def]
def defense_rg(all_pos: list) -> list:
rg_data = [
None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None,
None, None, None, None, None, None
]
all_pitcher = True
for line in all_pos:
if 'P' not in line.position:
all_pitcher = False
break
for line in all_pos:
if line.position == 'P' and all_pitcher:
this_pit = PitcherData.get_or_none(PitcherData.player == line.player, PitcherData.cardset == line.cardset)
if this_pit:
rg_data[0] = line.range
rg_data[9] = line.error
rg_data[22] = this_pit.wild_pitch
rg_data[23] = this_pit.balk
elif line.position == 'C':
rg_data[1] = line.range
rg_data[10] = line.error
rg_data[19] = line.arm
rg_data[20] = line.overthrow
rg_data[21] = line.pb
elif line.position == '1B':
rg_data[2] = line.range
rg_data[11] = line.error
elif line.position == '2B':
rg_data[3] = line.range
rg_data[12] = line.error
elif line.position == '3B':
rg_data[4] = line.range
rg_data[13] = line.error
elif line.position == 'SS':
rg_data[5] = line.range
rg_data[14] = line.error
elif line.position == 'LF':
rg_data[6] = line.range
elif line.position == 'CF':
rg_data[7] = line.range
elif line.position == 'RF':
rg_data[8] = line.range
elif line.position == 'OF':
rg_data[15] = line.error
rg_data[16] = line.error
rg_data[17] = line.error
rg_data[18] = line.arm
return rg_data