import copy
import math
import pathlib
import sys
import csv
import logging
import datetime
import asyncio

from db_calls_card_creation import *
from creation_helpers import *
import calcs_pitcher as p
import calcs_batter as b
import calcs_defense as d

date = f'{datetime.datetime.now().year}-{datetime.datetime.now().month}-{datetime.datetime.now().day}'
log_level = logging.INFO
logging.basicConfig(
    filename=f'logs/{date}.log',
    format='%(asctime)s - card-creation - %(levelname)s - %(message)s',
    level=log_level
)


"""
Data Links:
    Baserunning: https://www.baseball-reference.com/leagues/majors/2022-baserunning-batting.shtml
    Defense: https://www.baseball-reference.com/leagues/majors/2022-specialpos_p-fielding.shtml
        All 9 positions plus OF
    Pitcher Peripherals: https://www.baseball-reference.com/leagues/majors/2022-standard-pitching.shtml
    Pitching & Batting: https://www.fangraphs.com/leaders/splits-leaderboards
"""


async def main(argv):
    cardset_name = input(f'What is the name of this Cardset? ')
    # cardset_name = '2022 Live'
    cardset = Cardset.get_or_none(fn.Lower(Cardset.set_title) == cardset_name.lower())
    testing = False

    if not cardset:
        create_cardset = input(f'There is no cardset named **{cardset_name}**. Should I create it (y/n)? ')
        if create_cardset.lower() in YES:
            cardset = Cardset(set_title=cardset_name)
            cardset.save()
            print(f'Got it! Now on to the cards.')
        else:
            print(f'Okay, see you next time.')
            return

    now = datetime.datetime.now()
    output_path = pathlib.Path(f'card-output/{cardset.set_title} Cardset/')
    input_path = f'data-input/{cardset.set_title} Cardset/'

    game_count = 0
    while (game_count <= 0) or (game_count > 162):
        game_count = int(input(f'How many games out of 162 have been played? '))
    season_pct = game_count / 162
    print(f'season_pct: {season_pct}')

    # Get stat csv
    print(f'Your input files should be located in data-input/{cardset.set_title} Cardset/')
    await asyncio.sleep(1)

    lets_go = input(f'Should I run pitchers (y/n)? ')
    if lets_go in YES:
        existing_columns = CardColumns.delete().where(
            CardColumns.id.endswith(f'-{cardset.id}') & CardColumns.p_ratings.is_null(False)
        ).execute()
        existing_pitchers = PitcherRatings.delete().where(PitcherRatings.cardset == cardset).execute()
        # ratings_guide = [[
        #     'name', 'sba-id', 'hr-vL', 'bp-hr-vL', 'tr-vL', 'do***-vL', 'do**-vL', 'do-cf-vL', 'si**-vL', 'si*-vL',
        #     'si-cf-vL', 'bp-si-vL', 'hbp-vL', 'bb-vL', 'so-vL', 'fo-b-cf-vL', 'fo-b-slap-vL', 'gb-a-vL', 'gb-c-vL',
        #     'gb-x-p-vL', 'gb-x-c-vL', 'gb-x-1b-vL', 'gb-x-2b-vL', 'gb-x-3b-vL', 'gb-x-ss-vL', 'gb-x-lf-vL',
        #     'gb-x-cf-vL', 'gb-x-rf-vL',
        #     'hr-vR', 'bp-hr-vR', 'tr-vR', 'do***-vR', 'do**-vR', 'do-cf-vR', 'si**-vR', 'si*-vR',
        #     'si-cf-vR', 'bp-si-vR', 'hbp-vR', 'bb-vR', 'so-vR', 'fo-b-cf-vR', 'fo-b-slap-vR', 'gb-a-vR', 'gb-c-vR',
        #     'gb-x-p-vR', 'gb-x-c-vR', 'gb-x-1b-vR', 'gb-x-2b-vR', 'gb-x-3b-vR', 'gb-x-ss-vR', 'gb-x-lf-vR',
        #     'gb-x-cf-vR', 'gb-x-rf-vR'
        # ]]
        # card_columns = [[
        #     'name', 'sba_id', 'hand', 'vl_one_2d6', 'vl_one_results', 'vl_one_splits', 'vl_two_2d6', 'vl_two_results',
        #     'vl_two_splits', 'vl_three_2d6', 'vl_three_results', 'vl_three_splits', 'vr_one_2d6', 'vr_one_results',
        #     'vr_one_splits', 'vr_two_2d6', 'vr_two_results', 'vr_two_splits', 'vr_three_2d6', 'vr_three_results',
        #     'vr_three_splits'
        # ]]
        # rg_headers = ['name', 'hand', 'hr', 'bp-hr', 'tr', 'do***', 'do**', 'do-cf', 'si**', 'si*', 'si-cf', 'bp-si',
        #       'hbp', 'bb', 'so', 'fo-cf', 'fo-slap', 'gb-a', 'gb-c', 'gb-x-p', 'gb-x-c', 'gb-x-1b', 'gb-x-2b',
        #       'gb-x-3b', 'gb-x-ss', 'gb-x-lf', 'gb-x-cf', 'gb-x-rf']

        """
        Process pitcher stats into raw chances
        """
        count_pitchers = 0
        with open(f'{input_path}pitcher-stats.csv', 'r') as file:
            reader = csv.reader(file)

            for row in reader:
                try:
                    player = Player.get_or_none(Player.fg_id == int(row[0]))
                    if testing:
                        print(f'player fg_id: {int(row[0])} / player: {player}')
                    if player is not None and (('Promo' in cardset.set_title) or (int(row[5]) >= 30 and int(row[38]) >= 45)):
                        chance_data_vl = {
                            'id': f'{player.sba_id}-vL-{cardset.id}',
                            'player_id': player.sba_id,
                            'cardset_id': cardset.id,
                            'vs_hand': 'vL',
                            'is_prep': True,
                            'homerun': 0,
                            'bp_homerun': 0,
                            'triple': 0,
                            'double_three': 0,
                            'double_two': 0,
                            'double_cf': 0,
                            'single_two': 0,
                            'single_one': 0,
                            'single_center': 0,
                            'bp_single': 0,
                            'hbp': 0,
                            'walk': 0,
                            'strikeout': 0,
                            'fo_slap': 0,
                            'fo_center': 0,
                            'groundout_a': 0,
                            'groundout_b': 0,
                            'xcheck_p': 0,
                            'xcheck_c': 0,
                            'xcheck_1b': 0,
                            'xcheck_2b': 0,
                            'xcheck_3b': 0,
                            'xcheck_ss': 0,
                            'xcheck_lf': 0,
                            'xcheck_cf': 0,
                            'xcheck_rf': 0,
                        }
                        chance_data_vr = {
                            'id': f'{player.sba_id}-vR-{cardset.id}',
                            'player_id': player.sba_id,
                            'cardset_id': cardset.id,
                            'vs_hand': 'vR',
                            'is_prep': True,
                            'homerun': 0,
                            'bp_homerun': 0,
                            'triple': 0,
                            'double_three': 0,
                            'double_two': 0,
                            'double_cf': 0,
                            'single_two': 0,
                            'single_one': 0,
                            'single_center': 0,
                            'bp_single': 0,
                            'hbp': 0,
                            'walk': 0,
                            'strikeout': 0,
                            'fo_slap': 0,
                            'fo_center': 0,
                            'groundout_a': 0,
                            'groundout_b': 0,
                            'xcheck_p': 0,
                            'xcheck_c': 0,
                            'xcheck_1b': 0,
                            'xcheck_2b': 0,
                            'xcheck_3b': 0,
                            'xcheck_ss': 0,
                            'xcheck_lf': 0,
                            'xcheck_cf': 0,
                            'xcheck_rf': 0,
                        }

                        # Get total num hits v both
                        total_hit_mod = 5  # originally 9 to account for x-hits
                        raw_hits_vl = mround(float(row[17]) * 108)
                        raw_hits_vr = mround(float(row[50]) * 108)
                        hits_vl = max(raw_hits_vl - total_hit_mod, 5)
                        hits_vr = max(raw_hits_vr - total_hit_mod, 5)
                        soft_rate_vl = p.soft_rate(float(row[34]))
                        soft_rate_vr = p.soft_rate(float(row[67]))
                        med_rate_vl = p.med_rate(float(row[35]))
                        med_rate_vr = p.med_rate(float(row[68]))
                        hard_rate_vl = p.hard_rate(float(row[36]))
                        hard_rate_vr = p.hard_rate(float(row[69]))

                        # Get Singles
                        tot_singles_vl, tot_singles_vr = p.all_singles(row, hits_vl, hits_vr)
                        total_xbh_vl = mround(hits_vl - tot_singles_vl)
                        total_xbh_vr = mround(hits_vr - tot_singles_vr)

                        # BPSI
                        bpsi_vl, bpsi_vr = p.bp_singles(tot_singles_vl, tot_singles_vr)
                        chance_data_vl['bp_single'] = bpsi_vl
                        chance_data_vr['bp_single'] = bpsi_vr
                        tot_singles_vl = mround(tot_singles_vl - bpsi_vl)
                        tot_singles_vr = mround(tot_singles_vr - bpsi_vr)

                        # SI**
                        si2_vl, si2_vr = p.wh_singles(tot_singles_vl, tot_singles_vr, hard_rate_vl, hard_rate_vr)
                        chance_data_vl['single_two'] = si2_vl
                        chance_data_vr['single_two'] = si2_vr
                        tot_singles_vl = mround(tot_singles_vl - si2_vl)
                        tot_singles_vr = mround(tot_singles_vr - si2_vr)

                        # SI*
                        si1_vl, si1_vr = p.one_singles(tot_singles_vl, tot_singles_vr, soft_rate_vl, soft_rate_vr)
                        chance_data_vl['single_one'] = si1_vl
                        chance_data_vr['single_one'] = si1_vr
                        tot_singles_vl = mround(tot_singles_vl - si1_vl)
                        tot_singles_vr = mround(tot_singles_vr - si1_vr)

                        # SI(cf)
                        chance_data_vl['single_center'] = tot_singles_vl
                        chance_data_vr['single_center'] = tot_singles_vr

                        # Home Runs
                        hr_rate_vl = p.hr_per_fb_rate(float(row[28]))
                        hr_rate_vr = p.hr_per_fb_rate(float(row[61]))
                        hr_vl = mround(hits_vl * (float(row[12]) / float(row[7])))
                        hr_vr = mround(hits_vr * (float(row[45]) / float(row[40])))

                        bphr_vl, bphr_vr = p.bp_homerun(hr_vl, hr_vr, hr_rate_vl, hr_rate_vr)
                        chance_data_vl['bp_homerun'] = bphr_vl
                        chance_data_vr['bp_homerun'] = bphr_vr
                        chance_data_vl['homerun'] = mround(hr_vl - bphr_vl)
                        chance_data_vr['homerun'] = mround(hr_vr - bphr_vr)

                        total_xbh_vl = mround(total_xbh_vl - hr_vl)
                        total_xbh_vr = mround(total_xbh_vr - hr_vr)

                        non_hrs_vl = float(row[8]) + float(row[9])
                        non_hrs_vr = float(row[41]) + float(row[42])
                        triple_per_23b_vl = (float(row[9]) / non_hrs_vl) if non_hrs_vl > 0 else 0
                        triple_per_23b_br = (float(row[42]) / non_hrs_vr) if non_hrs_vr > 0 else 0

                        tr_vl, tr_vr = p.triples(total_xbh_vl, total_xbh_vr, triple_per_23b_vl, triple_per_23b_br)
                        chance_data_vl['triple'] = tr_vl
                        chance_data_vr['triple'] = tr_vr

                        doubles_vl = mround(total_xbh_vl - tr_vl)
                        doubles_vr = mround(total_xbh_vr - tr_vr)

                        ts_doubles_vl, ts_doubles_vr = p.two_doubles(doubles_vl, doubles_vr, soft_rate_vl, soft_rate_vr)
                        chance_data_vl['double_two'] = ts_doubles_vl
                        chance_data_vr['double_two'] = ts_doubles_vr
                        chance_data_vl['double_cf'] = mround(doubles_vl - ts_doubles_vl)
                        chance_data_vr['double_cf'] = mround(doubles_vr - ts_doubles_vr)

                        if testing:
                            print(f'vl hits: {hits_vl} / vr hits: {hits_vr}')
                            print(f'xbh vl: {total_xbh_vl}\nxbh vr: {total_xbh_vr}')
                            print(f'final hits vl: {p.total_chances(chance_data_vl)} / '
                                  f'final hits vr: {p.total_chances(chance_data_vr)}')

                        other_ob_vl = mround((float(row[18]) - float(row[17])) * 108)
                        other_ob_vr = mround((float(row[51]) - float(row[50])) * 108)
                        hbp_per_walk_vl = p.hbp_rate(float(row[15]), float(row[13]))
                        hbp_per_walk_vr = p.hbp_rate(float(row[48]), float(row[46]))

                        chance_data_vl['hbp'] = p.hbps(other_ob_vl, hbp_per_walk_vl)
                        chance_data_vr['hbp'] = p.hbps(other_ob_vr, hbp_per_walk_vr)
                        chance_data_vl['walk'] = mround(other_ob_vl - chance_data_vl['hbp'])
                        chance_data_vr['walk'] = mround(other_ob_vr - chance_data_vr['hbp'])

                        if testing:
                            print(f'ob vl: {p.total_chances(chance_data_vl)}\nob vr: {p.total_chances(chance_data_vr)}')

                        chance_data_vl['xcheck_p'] = p.xchecks('p')
                        chance_data_vl['xcheck_c'] = p.xchecks('c')
                        chance_data_vl['xcheck_1b'] = p.xchecks('1b')
                        chance_data_vl['xcheck_2b'] = p.xchecks('2b')
                        chance_data_vl['xcheck_3b'] = p.xchecks('3b')
                        chance_data_vl['xcheck_ss'] = p.xchecks('ss')
                        chance_data_vl['xcheck_lf'] = p.xchecks('lf')
                        chance_data_vl['xcheck_cf'] = p.xchecks('cf')
                        chance_data_vl['xcheck_rf'] = p.xchecks('rf')
                        chance_data_vr['xcheck_p'] = p.xchecks('p')
                        chance_data_vr['xcheck_c'] = p.xchecks('c')
                        chance_data_vr['xcheck_1b'] = p.xchecks('1b')
                        chance_data_vr['xcheck_2b'] = p.xchecks('2b')
                        chance_data_vr['xcheck_3b'] = p.xchecks('3b')
                        chance_data_vr['xcheck_ss'] = p.xchecks('ss')
                        chance_data_vr['xcheck_lf'] = p.xchecks('lf')
                        chance_data_vr['xcheck_cf'] = p.xchecks('cf')
                        chance_data_vr['xcheck_rf'] = p.xchecks('rf')

                        all_outs_vl = mround(108 - p.total_chances(chance_data_vl))
                        all_outs_vr = mround(108 - p.total_chances(chance_data_vr))

                        if testing:
                            print(f'total vl: {p.total_chances(chance_data_vl)}\ntotal vr: {p.total_chances(chance_data_vr)}\n'
                              f'outs vl: {all_outs_vl}\nouts vr: {all_outs_vr}')

                        so_pct_vl = float(row[16]) / (
                                float(row[5]) - float(row[7]) - float(row[13]) - float(row[14]) - float(row[15])
                        )
                        so_pct_vr = float(row[49]) / (
                            float(row[38]) - float(row[40]) - float(row[46]) - float(row[47]) - float(row[48])
                        )

                        # so_vl = mround(all_outs_vl * so_pct_vl * 1.2)
                        # so_vr = mround(all_outs_vr * so_pct_vr * 1.2)
                        so_vl = mround(all_outs_vl * so_pct_vl)
                        so_vr = mround(all_outs_vr * so_pct_vr)
                        chance_data_vl['strikeout'] = so_vl
                        chance_data_vr['strikeout'] = so_vr

                        rem_outs_vl = mround(all_outs_vl - so_vl)
                        rem_outs_vr = mround(all_outs_vr - so_vr)

                        fly_pct_vl = float(row[26]) / (float(row[26]) + float(row[25]))
                        fly_pct_vr = float(row[59]) / (float(row[59]) + float(row[58]))
                        all_fly_vl = mround(rem_outs_vl * fly_pct_vl)
                        all_fly_vr = mround(rem_outs_vr * fly_pct_vr)
                        opp_fly_vl = float(row[33]) / (float(row[33]) + float(row[32]))
                        opp_fly_vr = float(row[66]) / (float(row[66]) + float(row[65]))

                        chance_data_vl['fo_slap'] = p.oppo_fly(all_fly_vl, opp_fly_vl)
                        chance_data_vr['fo_slap'] = p.oppo_fly(all_fly_vr, opp_fly_vr)
                        chance_data_vl['fo_center'] = mround(all_fly_vl - chance_data_vl['fo_slap'])
                        chance_data_vr['fo_center'] = mround(all_fly_vr - chance_data_vr['fo_slap'])

                        go_vl = mround(rem_outs_vl - all_fly_vl)
                        go_vr = mround(rem_outs_vr - all_fly_vr)
                        chance_data_vl['groundout_a'] = p.groundball_a(go_vl, float(row[35]))
                        chance_data_vr['groundout_a'] = p.groundball_a(go_vr, float(row[68]))
                        chance_data_vl['groundout_b'] = mround(go_vl - chance_data_vl['groundout_a'])
                        chance_data_vr['groundout_b'] = mround(go_vr - chance_data_vr['groundout_a'])

                        if testing:
                            print(f'total vl: {p.total_chances(chance_data_vl)}\ntotal vr: {p.total_chances(chance_data_vr)}')
                            print(f'{row[2]}\nvl: {chance_data_vl}\nvr: {chance_data_vr}')

                        this_line = PitcherRatings.create(**chance_data_vl)
                        this_line.save()
                        this_line = PitcherRatings.create(**chance_data_vr)
                        this_line.save()

                        """
                        Process pitcher chances into card output and ratings guide
                        """

                        bat_hand = player.hand
                        tba = {
                            'vL': {
                                'bp-si': {
                                    'value': chance_data_vl['bp_single'],
                                    'string': '▼BP-SI',
                                    'bold': True,
                                    'actual': 0
                                },
                                'si-cf': {
                                    'value': chance_data_vl['single_center'],
                                    'string': 'SINGLE (cf)',
                                    'sm-string': 'SI (cf)',
                                    'bold': True,
                                    'actual': 0
                                },
                                'si*': {
                                    'value': chance_data_vl['single_one'],
                                    'string': 'SINGLE*',
                                    'sm-string': 'SI*',
                                    'bold': True,
                                    'actual': 0
                                },
                                'si**': {
                                    'value': chance_data_vl['single_two'],
                                    'string': 'SINGLE**',
                                    'sm-string': 'SI**',
                                    'bold': True,
                                    'actual': 0
                                },
                                'bp-hr': {
                                    'value': chance_data_vl['bp_homerun'],
                                    'string': '◆BP-HR',
                                    'bold': True,
                                    'actual': 0
                                },
                                'hr': {
                                    'value': chance_data_vl['homerun'],
                                    'string': 'HOMERUN',
                                    'sm-string': 'HR',
                                    'bold': True,
                                    'actual': 0
                                },
                                'tr': {
                                    'value': chance_data_vl['triple'],
                                    'string': 'TRIPLE',
                                    'sm-string': 'TR',
                                    'bold': True,
                                    'actual': 0
                                },
                                'do**': {
                                    'value': chance_data_vl['double_two'],
                                    'string': 'DOUBLE**',
                                    'sm-string': 'DO**',
                                    'bold': True,
                                    'actual': 0
                                },
                                'do***': {
                                    'value': chance_data_vl['double_three'],
                                    'string': 'DOUBLE***',
                                    'sm-string': 'DO***',
                                    'bold': True,
                                    'actual': 0
                                },
                                'do-cf': {
                                    'value': chance_data_vl['double_cf'],
                                    'string': f'DOUBLE (cf)',
                                    'sm-string': f'DO (cf)',
                                    'bold': True,
                                    'actual': 0
                                },
                                'hbp': {
                                    'value': chance_data_vl['hbp'],
                                    'string': 'HBP',
                                    'bold': True,
                                    'actual': 0
                                },
                                'bb': {
                                    'value': chance_data_vl['walk'],
                                    'string': 'WALK',
                                    'bold': True,
                                    'actual': 0
                                },
                                'so': {
                                    'value': chance_data_vl['strikeout'],
                                    'string': 'strikeout',
                                    # 'sm-string': 'so',
                                    'bold': False,
                                    'actual': 0,
                                },
                                'fo-slap': {
                                    'value': chance_data_vl['fo_slap'],
                                    'string': f'fly (lf) B',
                                    'sm-string': f'fly (lf) B',
                                    'bold': False,
                                    'actual': 0
                                },
                                'fo-cf': {
                                    'value': chance_data_vl['fo_center'],
                                    'string': f'fly (cf) B',
                                    'sm-string': f'fly (cf) B',
                                    'bold': False,
                                    'actual': 0
                                },
                                'gb-a': {
                                    'value': chance_data_vl['groundout_a'],
                                    'string': f'gb (2b) A',
                                    'bold': False,
                                    'actual': 0
                                },
                                'gb-c': {
                                    'value': chance_data_vl['groundout_b'],
                                    'string': f'gb (3b) B',
                                    'bold': False,
                                    'actual': 0
                                },
                                'gb-x-p': {
                                    'value': chance_data_vl['xcheck_p'],
                                    'string': 'GB (p) X',
                                    'bold': False,
                                    'actual': 0
                                },
                                'gb-x-c': {
                                    'value': chance_data_vl['xcheck_c'],
                                    'string': 'CATCH-X',
                                    'bold': False,
                                    'actual': 0
                                },
                                'gb-x-1b': {
                                    'value': chance_data_vl['xcheck_1b'],
                                    'string': 'GB (1b) X',
                                    'bold': False,
                                    'actual': 0
                                },
                                'gb-x-2b': {
                                    'value': chance_data_vl['xcheck_2b'],
                                    'string': 'GB (2b) X',
                                    'bold': False,
                                    'actual': 0
                                },
                                'gb-x-3b': {
                                    'value': chance_data_vl['xcheck_3b'],
                                    'string': 'GB (3b) X',
                                    'bold': False,
                                    'actual': 0
                                },
                                'gb-x-ss': {
                                    'value': chance_data_vl['xcheck_ss'],
                                    'string': 'GB (ss) X',
                                    'bold': False,
                                    'actual': 0
                                },
                                'gb-x-lf': {
                                    'value': chance_data_vl['xcheck_lf'],
                                    'string': 'FLY (lf) X',
                                    'bold': False,
                                    'actual': 0
                                },
                                'gb-x-cf': {
                                    'value': chance_data_vl['xcheck_cf'],
                                    'string': 'FLY (cf) X',
                                    'bold': False,
                                    'actual': 0
                                },
                                'gb-x-rf': {
                                    'value': chance_data_vl['xcheck_rf'],
                                    'string': 'FLY (rf) X',
                                    'bold': False,
                                    'actual': 0
                                },
                                'fatigue': 0
                            },
                            'vR': {
                                'bp-si': {
                                    'value': chance_data_vr['bp_single'],
                                    'string': '▼BP-SI',
                                    'bold': True,
                                    'actual': 0
                                },
                                'si-cf': {
                                    'value': chance_data_vr['single_center'],
                                    'string': 'SINGLE (cf)',
                                    'sm-string': 'SI (cf)',
                                    'bold': True,
                                    'actual': 0
                                },
                                'si*': {
                                    'value': chance_data_vr['single_one'],
                                    'string': 'SINGLE*',
                                    'sm-string': 'SI*',
                                    'bold': True,
                                    'actual': 0
                                },
                                'si**': {
                                    'value': chance_data_vr['single_two'],
                                    'string': 'SINGLE**',
                                    'sm-string': 'SI**',
                                    'bold': True,
                                    'actual': 0
                                },
                                'bp-hr': {
                                    'value': chance_data_vr['bp_homerun'],
                                    'string': '◆BP-HR',
                                    'bold': True,
                                    'actual': 0
                                },
                                'hr': {
                                    'value': chance_data_vr['homerun'],
                                    'string': 'HOMERUN',
                                    'sm-string': 'HR',
                                    'bold': True,
                                    'actual': 0
                                },
                                'tr': {
                                    'value': chance_data_vr['triple'],
                                    'string': 'TRIPLE',
                                    'sm-string': 'TR',
                                    'bold': True,
                                    'actual': 0
                                },
                                'do**': {
                                    'value': chance_data_vr['double_two'],
                                    'string': 'DOUBLE**',
                                    'sm-string': 'DO**',
                                    'bold': True,
                                    'actual': 0
                                },
                                'do***': {
                                    'value': chance_data_vr['double_three'],
                                    'string': 'DOUBLE***',
                                    'sm-string': 'DO***',
                                    'bold': True,
                                    'actual': 0
                                },
                                'do-cf': {
                                    'value': chance_data_vr['double_cf'],
                                    'string': f'DOUBLE (cf)',
                                    'sm-string': f'DO (cf)',
                                    'bold': True,
                                    'actual': 0
                                },
                                'hbp': {
                                    'value': chance_data_vr['hbp'],
                                    'string': 'HBP',
                                    'bold': True,
                                    'actual': 0
                                },
                                'bb': {
                                    'value': chance_data_vr['walk'],
                                    'string': 'WALK',
                                    'bold': True,
                                    'actual': 0
                                },
                                'so': {
                                    'value': chance_data_vr['strikeout'],
                                    'string': 'strikeout',
                                    # 'sm-string': 'so',
                                    'bold': False,
                                    'actual': 0,
                                },
                                'fo-slap': {
                                    'value': chance_data_vr['fo_slap'],
                                    'string': f'fly (rf) B',
                                    'sm-string': f'fly (rf) B',
                                    'bold': False,
                                    'actual': 0
                                },
                                'fo-cf': {
                                    'value': chance_data_vr['fo_center'],
                                    'string': f'fly (cf) B',
                                    'bold': False,
                                    'actual': 0
                                },
                                'gb-a': {
                                    'value': chance_data_vr['groundout_a'],
                                    'string': f'gb (ss) A',
                                    'bold': False,
                                    'actual': 0
                                },
                                'gb-c': {
                                    'value': chance_data_vr['groundout_b'],
                                    'string': f'gb (1b) B',
                                    'bold': False,
                                    'actual': 0
                                },
                                'gb-x-p': {
                                    'value': chance_data_vr['xcheck_p'],
                                    'string': 'GB (p) X',
                                    'bold': False,
                                    'actual': 0
                                },
                                'gb-x-c': {
                                    'value': chance_data_vr['xcheck_c'],
                                    'string': 'CATCH-X',
                                    'bold': False,
                                    'actual': 0
                                },
                                'gb-x-1b': {
                                    'value': chance_data_vr['xcheck_1b'],
                                    'string': 'GB (1b) X',
                                    'bold': False,
                                    'actual': 0
                                },
                                'gb-x-2b': {
                                    'value': chance_data_vr['xcheck_2b'],
                                    'string': 'GB (2b) X',
                                    'bold': False,
                                    'actual': 0
                                },
                                'gb-x-3b': {
                                    'value': chance_data_vr['xcheck_3b'],
                                    'string': 'GB (3b) X',
                                    'bold': False,
                                    'actual': 0
                                },
                                'gb-x-ss': {
                                    'value': chance_data_vr['xcheck_ss'],
                                    'string': 'GB (ss) X',
                                    'bold': False,
                                    'actual': 0
                                },
                                'gb-x-lf': {
                                    'value': chance_data_vr['xcheck_lf'],
                                    'string': 'FLY (lf) X',
                                    'bold': False,
                                    'actual': 0
                                },
                                'gb-x-cf': {
                                    'value': chance_data_vr['xcheck_cf'],
                                    'string': 'FLY (cf) X',
                                    'bold': False,
                                    'actual': 0
                                },
                                'gb-x-rf': {
                                    'value': chance_data_vr['xcheck_rf'],
                                    'string': 'FLY (rf) X',
                                    'bold': False,
                                    'actual': 0
                                },
                                'fatigue': 0
                            }
                        }
                        results = copy.deepcopy(BLANK_RESULTS)

                        def column_output():
                            card_output = {}

                            for hand in ['vL', 'vR']:
                                for col in ['1', '2', '3']:
                                    card_output[f'{hand.lower()}_{get_col(col)}_2d6'] = ''
                                    card_output[f'{hand.lower()}_{get_col(col)}_results'] = ''
                                    card_output[f'{hand.lower()}_{get_col(col)}_splits'] = ''

                            for hand in ['vL', 'vR']:
                                for col in ['1', '2', '3']:
                                    int_results = {}
                                    for x in results[hand][col]:
                                        try:
                                            int_results[int(x)] = results[hand][col][x]
                                        except ValueError as e:
                                            if testing:
                                                print(f'skipping {x} in column_output')

                                    if testing: print(f'{int_results}')

                                    sorted_results = {
                                        row_num: int_results[row_num] for row_num in sorted(int_results.keys())
                                    }
                                    for line in sorted_results:
                                        if testing: print(f'\nsorted_results: {sorted_results}\nline: {line}')
                                        if sorted_results[line]["result"]:
                                            card_output[f'{hand.lower()}_{get_col(col)}_2d6'] += \
                                                f'{results[hand][col][str(line)]["2d6"]}\n'
                                            card_output[f'{hand.lower()}_{get_col(col)}_results'] += \
                                                f'{results[hand][col][str(line)]["result"]}\n'
                                            card_output[f'{hand.lower()}_{get_col(col)}_splits'] += \
                                                f'{results[hand][col][str(line)]["splits"]}\n'

                            return card_output

                        def add_full_result(vs_hand, tba_data, is_good, chances, plus_fatigue=False):
                            all_cols = []
                            good_col = player.offense_col
                            if is_good:
                                if good_col == 1:
                                    second = random.choice([2, 3])
                                    all_cols = [1, second, 3 if second == 2 else 2]
                                elif good_col == 2:
                                    second = random.choice([1, 3])
                                    all_cols = [2, second, 3 if second == 1 else 1]
                                elif good_col == 3:
                                    second = random.choice([1, 2])
                                    all_cols = [3, second, 1 if second == 1 else 2]
                            else:
                                if good_col == 1:
                                    f_col = random.choice([2, 3])
                                    all_cols = [f_col, 3 if f_col == 2 else 2, 1]
                                elif good_col == 2:
                                    f_col = random.choice([1, 3])
                                    all_cols = [f_col, 3 if f_col == 1 else 1, 2]
                                elif good_col == 3:
                                    f_col = random.choice([1, 2])
                                    all_cols = [f_col, 1 if f_col == 1 else 2, 3]

                            if chances == 6:
                                for column in all_cols:
                                    if not results[vs_hand][f'{column}']['7']['result']:
                                        results[vs_hand][f'{column}']['7'] = result_data(tba_data, 7, fatigue=plus_fatigue)
                                        return chances
                                    if not results[vs_hand][f'{column}']['6']['result'] and not \
                                            results[vs_hand][f'{column}']['2']['result']:
                                        results[vs_hand][f'{column}']['6'] = result_data(tba_data, 6, fatigue=plus_fatigue)
                                        results[vs_hand][f'{column}']['2'] = result_data(tba_data, 2, fatigue=plus_fatigue)
                                        return chances
                                    if not results[vs_hand][f'{column}']['8']['result'] and not \
                                            results[vs_hand][f'{column}']['12']['result']:
                                        results[vs_hand][f'{column}']['8'] = result_data(tba_data, 8, fatigue=plus_fatigue)
                                        results[vs_hand][f'{column}']['12'] = result_data(tba_data, 12,
                                                                                          fatigue=plus_fatigue)
                                        return chances
                                    if not results[vs_hand][f'{column}']['6']['result'] and not \
                                            results[vs_hand][f'{column}']['12']['result']:
                                        results[vs_hand][f'{column}']['6'] = result_data(tba_data, 6, fatigue=plus_fatigue)
                                        results[vs_hand][f'{column}']['12'] = result_data(tba_data, 12,
                                                                                          fatigue=plus_fatigue)
                                        return chances
                                    if not results[vs_hand][f'{column}']['8']['result'] and not \
                                            results[vs_hand][f'{column}']['2']['result']:
                                        results[vs_hand][f'{column}']['8'] = result_data(tba_data, 8, fatigue=plus_fatigue)
                                        results[vs_hand][f'{column}']['2'] = result_data(tba_data, 2, fatigue=plus_fatigue)
                                        return chances

                                # No matches
                                return 0

                            elif chances == 5:
                                for column in all_cols:
                                    if not results[vs_hand][f'{column}']['6']['result']:
                                        results[vs_hand][f'{column}']['6'] = result_data(tba_data, 6, fatigue=plus_fatigue)
                                        return chances
                                    if not results[vs_hand][f'{column}']['8']['result']:
                                        results[vs_hand][f'{column}']['8'] = result_data(tba_data, 8, fatigue=plus_fatigue)
                                        return chances
                                    if not results[vs_hand][f'{column}']['3']['result'] and not \
                                            results[vs_hand][f'{column}']['4']['result']:
                                        results[vs_hand][f'{column}']['3'] = result_data(tba_data, 3, fatigue=plus_fatigue)
                                        results[vs_hand][f'{column}']['4'] = result_data(tba_data, 4, fatigue=plus_fatigue)
                                        return chances
                                    if not results[vs_hand][f'{column}']['3']['result'] and not \
                                            results[vs_hand][f'{column}']['10']['result']:
                                        results[vs_hand][f'{column}']['3'] = result_data(tba_data, 3, fatigue=plus_fatigue)
                                        results[vs_hand][f'{column}']['10'] = result_data(tba_data, 10,
                                                                                          fatigue=plus_fatigue)
                                        return chances
                                    if not results[vs_hand][f'{column}']['4']['result'] and not \
                                            results[vs_hand][f'{column}']['11']['result']:
                                        results[vs_hand][f'{column}']['4'] = result_data(tba_data, 4, fatigue=plus_fatigue)
                                        results[vs_hand][f'{column}']['11'] = result_data(tba_data, 11,
                                                                                          fatigue=plus_fatigue)
                                        return chances
                                    if not results[vs_hand][f'{column}']['10']['result'] and not \
                                            results[vs_hand][f'{column}']['11']['result']:
                                        results[vs_hand][f'{column}']['10'] = result_data(tba_data, 10,
                                                                                          fatigue=plus_fatigue)
                                        results[vs_hand][f'{column}']['11'] = result_data(tba_data, 11,
                                                                                          fatigue=plus_fatigue)
                                        return chances

                                # No matches
                                return 0

                            elif chances == 4:
                                for column in all_cols:
                                    if not results[vs_hand][f'{column}']['5']['result']:
                                        results[vs_hand][f'{column}']['5'] = result_data(tba_data, 5, fatigue=plus_fatigue)
                                        return chances
                                    if not results[vs_hand][f'{column}']['9']['result']:
                                        results[vs_hand][f'{column}']['9'] = result_data(tba_data, 9, fatigue=plus_fatigue)
                                        return chances
                                    if not results[vs_hand][f'{column}']['3']['result'] and not \
                                            results[vs_hand][f'{column}']['11']['result']:
                                        results[vs_hand][f'{column}']['3'] = result_data(tba_data, 3, fatigue=plus_fatigue)
                                        results[vs_hand][f'{column}']['11'] = result_data(tba_data, 11,
                                                                                          fatigue=plus_fatigue)
                                        return chances
                                    if not results[vs_hand][f'{column}']['2']['result'] and not \
                                            results[vs_hand][f'{column}']['4']['result']:
                                        results[vs_hand][f'{column}']['2'] = result_data(tba_data, 2, fatigue=plus_fatigue)
                                        results[vs_hand][f'{column}']['4'] = result_data(tba_data, 4, fatigue=plus_fatigue)
                                        return chances
                                    if not results[vs_hand][f'{column}']['10']['result'] and not \
                                            results[vs_hand][f'{column}']['12']['result']:
                                        results[vs_hand][f'{column}']['10'] = result_data(tba_data, 10,
                                                                                          fatigue=plus_fatigue)
                                        results[vs_hand][f'{column}']['12'] = result_data(tba_data, 12,
                                                                                          fatigue=plus_fatigue)
                                        return chances
                                    if not results[vs_hand][f'{column}']['2']['result'] and not \
                                            results[vs_hand][f'{column}']['10']['result']:
                                        results[vs_hand][f'{column}']['2'] = result_data(tba_data, 2, fatigue=plus_fatigue)
                                        results[vs_hand][f'{column}']['10'] = result_data(tba_data, 10,
                                                                                          fatigue=plus_fatigue)
                                        return chances
                                    if not results[vs_hand][f'{column}']['10']['result'] and not \
                                            results[vs_hand][f'{column}']['4']['result']:
                                        results[vs_hand][f'{column}']['10'] = result_data(tba_data, 10,
                                                                                          fatigue=plus_fatigue)
                                        results[vs_hand][f'{column}']['4'] = result_data(tba_data, 4, fatigue=plus_fatigue)
                                        return chances

                                return 0

                            elif chances == 3:
                                for column in all_cols:
                                    if not results[vs_hand][f'{column}']['4']['result']:
                                        results[vs_hand][f'{column}']['4'] = result_data(tba_data, 4, fatigue=plus_fatigue)
                                        return chances
                                    if not results[vs_hand][f'{column}']['10']['result']:
                                        results[vs_hand][f'{column}']['10'] = result_data(tba_data, 10,
                                                                                          fatigue=plus_fatigue)
                                        return chances
                                    if not results[vs_hand][f'{column}']['2']['result'] and not \
                                            results[vs_hand][f'{column}']['3']['result']:
                                        results[vs_hand][f'{column}']['2'] = result_data(tba_data, 2, fatigue=plus_fatigue)
                                        results[vs_hand][f'{column}']['3'] = result_data(tba_data, 3, fatigue=plus_fatigue)
                                        return chances
                                    if not results[vs_hand][f'{column}']['2']['result'] and not \
                                            results[vs_hand][f'{column}']['11']['result']:
                                        results[vs_hand][f'{column}']['2'] = result_data(tba_data, 2, fatigue=plus_fatigue)
                                        results[vs_hand][f'{column}']['11'] = result_data(tba_data, 11,
                                                                                          fatigue=plus_fatigue)
                                        return chances
                                    if not results[vs_hand][f'{column}']['12']['result'] and not \
                                            results[vs_hand][f'{column}']['3']['result']:
                                        results[vs_hand][f'{column}']['12'] = result_data(tba_data, 12,
                                                                                          fatigue=plus_fatigue)
                                        results[vs_hand][f'{column}']['3'] = result_data(tba_data, 3, fatigue=plus_fatigue)
                                        return chances
                                    if not results[vs_hand][f'{column}']['12']['result'] and not \
                                            results[vs_hand][f'{column}']['11']['result']:
                                        results[vs_hand][f'{column}']['12'] = result_data(tba_data, 12,
                                                                                          fatigue=plus_fatigue)
                                        results[vs_hand][f'{column}']['11'] = result_data(tba_data, 11,
                                                                                          fatigue=plus_fatigue)
                                        return chances

                                return 0

                            elif chances == 2:
                                for column in all_cols:
                                    if not results[vs_hand][f'{column}']['3']['result']:
                                        results[vs_hand][f'{column}']['3'] = result_data(tba_data, 3, fatigue=plus_fatigue)
                                        return chances
                                    if not results[vs_hand][f'{column}']['11']['result']:
                                        results[vs_hand][f'{column}']['11'] = result_data(tba_data, 11,
                                                                                          fatigue=plus_fatigue)
                                        return chances
                                    if not results[vs_hand][f'{column}']['2']['result'] and not \
                                            results[vs_hand][f'{column}']['12']['result']:
                                        results[vs_hand][f'{column}']['2'] = result_data(tba_data, 2, fatigue=plus_fatigue)
                                        results[vs_hand][f'{column}']['12'] = result_data(tba_data, 12,
                                                                                          fatigue=plus_fatigue)
                                        return chances

                                return 0

                            elif chances == 1:
                                for column in all_cols:
                                    if not results[vs_hand][f'{column}']['2']['result']:
                                        results[vs_hand][f'{column}']['2'] = result_data(tba_data, 2, fatigue=plus_fatigue)
                                        return chances
                                    if not results[vs_hand][f'{column}']['12']['result']:
                                        results[vs_hand][f'{column}']['12'] = result_data(tba_data, 12,
                                                                                          fatigue=plus_fatigue)
                                        return chances
                                return 0

                        def add_split_result(vs_hand, tba_data_top, tba_data_bottom, chances_top, is_good=None):
                            all_cols = []
                            good_col = player.offense_col

                            if is_good is None:
                                if good_col == 1:
                                    f_col = random.choice([2, 3])
                                    all_cols = [f_col, 1, 3 if f_col == 2 else 2]
                                elif good_col == 2:
                                    f_col = random.choice([1, 3])
                                    all_cols = [f_col, 2, 3 if f_col == 1 else 1]
                                elif good_col == 3:
                                    f_col = random.choice([1, 2])
                                    all_cols = [f_col, 3, 1 if f_col == 1 else 2]

                            elif is_good:
                                if good_col == 1:
                                    second = random.choice([2, 3])
                                    all_cols = [1, second, 3 if second == 2 else 2]
                                elif good_col == 2:
                                    second = random.choice([1, 3])
                                    all_cols = [2, second, 3 if second == 1 else 1]
                                elif good_col == 3:
                                    second = random.choice([1, 2])
                                    all_cols = [3, second, 1 if second == 1 else 2]

                            else:
                                if good_col == 1:
                                    f_col = random.choice([2, 3])
                                    all_cols = [f_col, 3 if f_col == 2 else 2, 1]
                                elif good_col == 2:
                                    f_col = random.choice([1, 3])
                                    all_cols = [f_col, 3 if f_col == 1 else 1, 2]
                                elif good_col == 3:
                                    f_col = random.choice([1, 2])
                                    all_cols = [f_col, 1 if f_col == 1 else 2, 3]

                            legal_2d6 = legal_splits(chances_top)
                            for column in all_cols:
                                if results[vs_hand][f'{column}']['splits'] < 3:
                                    for y in legal_2d6:
                                        if tba_data_bottom['value'] >= y['bad_chances'] and not \
                                                results[vs_hand][f'{column}'][f'{y["2d6"]}']['result']:
                                            results[vs_hand][f'{column}'][f'{y["2d6"]}'] = \
                                                result_data(tba_data_top, y["2d6"], tba_data_bottom, y["incs"])
                                            results[vs_hand][f'{column}']['splits'] += 1
                                            return y['bad_chances']

                            if testing: print(f'Legal 2d6: {legal_2d6}')
                            if testing: print(f'Could not find a legal spot for:\n{tba_data_top}\n{tba_data_bottom}')
                            return None

                        def assign_chances(
                                res_key: str, vs_hand: str, remainder_keys: list[str], allow_retry: bool, rollover_key: str,
                                is_good: bool, force_whole: bool = False):
                            retries = 0 if allow_retry else 1

                            if testing: print(f'starting {res_key}: {tba[vs_hand][res_key]["value"]}')
                            # If not even int, add_split_result with less than half of total chances
                            total_chances = mround(tba[vs_hand][res_key]['value'])
                            # chance_remainder = mround(total_chances - math.floor(total_chances))

                            # If total chance is a whole number, do easy assignments first
                            if int(total_chances) - total_chances == 0 or force_whole or tba[vs_hand][res_key]['value'] > 2:
                                if testing: print(f'{tba[vs_hand][res_key]["value"]} {res_key}s being placed')
                                if (res_key == 'so' or res_key == 'gb-a' or res_key == 'gb-c' or 'fo' in res_key) and \
                                        tba[vs_hand]['fatigue'] < 10:
                                    num_added = add_full_result(
                                        vs_hand,
                                        tba[vs_hand][res_key],
                                        is_good,
                                        min(math.floor(tba[vs_hand][res_key]['value']),
                                            min(6, 10 - tba[vs_hand]['fatigue'])),
                                        plus_fatigue=True
                                    )
                                    tba[vs_hand]['fatigue'] += num_added if num_added else 0

                                elif tba[vs_hand][res_key]['value'] > 9.5:
                                    num_added = add_full_result(vs_hand, tba[vs_hand][res_key], is_good, 6)

                                elif tba[vs_hand][res_key]['value'] > 7.5:
                                    num_added = add_full_result(vs_hand, tba[vs_hand][res_key], is_good, 5)

                                elif res_key == 'bp-si' and tba[vs_hand]['bp-si']['value'] > 4.5:
                                    num_added = add_full_result(vs_hand, tba[vs_hand][res_key], is_good,
                                                                random.randint(3, 5))

                                elif tba[vs_hand][res_key]['value'] > 5.5:
                                    num_added = add_full_result(vs_hand, tba[vs_hand][res_key], is_good, 4)

                                else:
                                    num_added = add_full_result(
                                        vs_hand,
                                        tba[vs_hand][res_key],
                                        is_good,
                                        int(tba[vs_hand][res_key]['value'])
                                    )
                                    if not num_added and int(tba[vs_hand][res_key]['value']) > 1:
                                        num_added = add_full_result(
                                            vs_hand,
                                            tba[vs_hand][res_key],
                                            is_good,
                                            int(tba[vs_hand][res_key]['value'] - 1)
                                        )
                                        if not num_added and int(tba[vs_hand][res_key]['value']) > 2:
                                            num_added = add_full_result(
                                                vs_hand,
                                                tba[vs_hand][res_key],
                                                is_good,
                                                int(tba[vs_hand][res_key]['value'] - 2)
                                            )
                                            if not num_added and int(tba[vs_hand][res_key]['value']) > 3:
                                                num_added = add_full_result(
                                                    vs_hand,
                                                    tba[vs_hand][res_key],
                                                    is_good,
                                                    int(tba[vs_hand][res_key]['value'] - 3)
                                                )
                                                if not num_added and int(tba[vs_hand][res_key]['value']) > 4:
                                                    num_added = add_full_result(
                                                        vs_hand,
                                                        tba[vs_hand][res_key],
                                                        is_good,
                                                        int(tba[vs_hand][res_key]['value'] - 4)
                                                    )

                                if num_added:
                                    tba[vs_hand][res_key]['value'] = mround(tba[vs_hand][res_key]['value'] - num_added)
                                    tba[vs_hand][res_key]['actual'] = mround(tba[vs_hand][res_key]['actual'] + num_added)
                                    return

                                elif retries == 0:
                                    if testing: print(f'retry # {retries} for {res_key} for {player.name} {vs_hand}')
                                    return

                                else:
                                    if tba[vs_hand][rollover_key]['value'] >= 1:
                                        t_value = 1
                                    else:
                                        t_value = .05
                                    if testing: print(f'Transferring {t_value} {res_key} to {rollover_key}')
                                    tba[vs_hand][rollover_key]['value'] = mround(
                                        tba[vs_hand][rollover_key]['value'] + t_value)
                                    tba[vs_hand][res_key]['value'] = mround(tba[vs_hand][res_key]['value'] - t_value)
                                    return

                            # Else start dicing up the chances
                            else:
                                # if retries == 0 and total_chances > 3:
                                #     chance_remainder = mround(
                                #         math.ceil(total_chances / 2) - (total_chances - math.floor(total_chances))
                                #     )
                                # else:
                                #     chance_remainder = mround(total_chances - math.floor(total_chances))

                                chance_remainder = mround(total_chances - math.floor(total_chances))
                                if testing: print(f'chance_remainder: {chance_remainder}')

                                # if mround(chance_remainder) != 0 and mround(chance_remainder) > .5:
                                # TO ROLL BACK, UNDO ABOVE COMMEND AND TAB ALL BELOW CODE IN ONCE
                                top_chances = None
                                bottom_key = None
                                bottom_result = None

                                """
                                If this result cannot take any splits (but has extra results pass the remainder to the rollover and 
                                come back to assign_chances with a whole number
                                """
                                if len(remainder_keys) == 0:
                                    # print(f'in the remainder_keys check for {res_key} / rounding down from '
                                    #       f'{tba[vs_hand][res_key]["value"]} to '
                                    #       f'{mround(math.floor(tba[vs_hand][res_key]["value"]))}')
                                    tba[vs_hand][res_key]['value'] = mround(math.floor(tba[vs_hand][res_key]['value']))
                                    # print(f'confirming end val: {tba[vs_hand][res_key]["value"]}')
                                    tba[vs_hand][rollover_key]['value'] = mround(
                                        tba[vs_hand][rollover_key]['value'] + chance_remainder
                                    )
                                    return

                                for rem_key in remainder_keys:
                                    if mround(tba[vs_hand][rem_key]['value']) >= mround(1 - chance_remainder):
                                        bottom_key = rem_key
                                        bottom_result = tba[vs_hand][rem_key]
                                        break

                                if not bottom_key:
                                    if tba[vs_hand][rollover_key]['value'] > 1:
                                        t_value = 1
                                    else:
                                        t_value = .05
                                    if testing: print(f'Transferring {t_value} {res_key} to {rollover_key}')

                                    tba[vs_hand][res_key]['value'] = mround(tba[vs_hand][res_key]['value'] - t_value)
                                    tba[vs_hand][rollover_key]['value'] = mround(
                                        tba[vs_hand][rollover_key]['value'] + t_value
                                    )
                                    return
                                    # raise ValueError(
                                    #     f'Could not find a second result for a {res_key} split for {player.name} {vHand}')

                                bottom_chances = None
                                if tba[vs_hand][res_key]['value'] > 4:
                                    top_chances = mround(3 + chance_remainder)
                                    if testing: print(f'checking top_chances: {top_chances}')
                                    bottom_chances = add_split_result(
                                        vs_hand, tba[vs_hand][res_key], bottom_result, top_chances, is_good
                                    )

                                elif tba[vs_hand][res_key]['value'] > 3:
                                    top_chances = mround(2 + chance_remainder)
                                    if testing: print(f'checking top_chances: {top_chances}')
                                    bottom_chances = add_split_result(
                                        vs_hand, tba[vs_hand][res_key], bottom_result, top_chances, is_good
                                    )

                                elif tba[vs_hand][res_key]['value'] > 2:
                                    top_chances = mround(1 + chance_remainder)
                                    if testing: print(f'checking top_chances: {top_chances}')
                                    bottom_chances = add_split_result(
                                        vs_hand, tba[vs_hand][res_key], bottom_result, top_chances, is_good
                                    )

                                if not bottom_chances:
                                    top_chances = mround(chance_remainder)
                                    if testing: print(f'checking top_chances: {top_chances}')
                                    bottom_chances = add_split_result(
                                        vs_hand, tba[vs_hand][res_key], bottom_result, top_chances, is_good
                                    )

                                if not bottom_chances and tba[vs_hand][res_key]['value'] > 3:
                                    top_chances = mround(.5 + chance_remainder)
                                    if testing: print(f'checking top_chances: {top_chances}')
                                    bottom_chances = add_split_result(
                                        vs_hand, tba[vs_hand][res_key], bottom_result, top_chances, is_good
                                    )

                                if not bottom_chances and tba[vs_hand][res_key]['value'] > 3:
                                    top_chances = mround(.7 + chance_remainder)
                                    if testing: print(f'checking top_chances: {top_chances}')
                                    bottom_chances = add_split_result(
                                        vs_hand, tba[vs_hand][res_key], bottom_result, top_chances, is_good
                                    )

                                if not bottom_chances and chance_remainder > 0.15:
                                    top_chances = mround(chance_remainder - 0.15)
                                    if testing: print(f'checking top_chances: {top_chances}')
                                    bottom_chances = add_split_result(
                                        vs_hand, tba[vs_hand][res_key], bottom_result, top_chances, is_good
                                    )

                                if not bottom_chances and chance_remainder > 0.05:
                                    top_chances = mround(chance_remainder - 0.05)
                                    if testing: print(f'checking top_chances: {top_chances}')
                                    bottom_chances = add_split_result(
                                        vs_hand, tba[vs_hand][res_key], bottom_result, top_chances, is_good
                                    )

                                if testing: print(f'{res_key} chances: {mround(top_chances)} / split with {bottom_result}')

                                if bottom_chances:
                                    tba[vs_hand][res_key]['value'] = mround(tba[vs_hand][res_key]['value'] - top_chances)
                                    tba[vs_hand][res_key]['actual'] = mround(tba[vs_hand][res_key]['actual'] + top_chances)
                                    tba[vs_hand][bottom_key]['value'] = mround(
                                        tba[vs_hand][bottom_key]['value'] - bottom_chances)
                                    tba[vs_hand][bottom_key]['actual'] = mround(
                                        tba[vs_hand][bottom_key]['actual'] + bottom_chances
                                    )
                                    if testing: print(
                                        f'placed {top_chances} {res_key}s and {bottom_chances} {bottom_result["string"]}s for '
                                        f'{player.name} {vs_hand}\n\n')
                                    return

                                elif retries == 0:
                                    retries += 1
                                    if testing: print(f'retry # {retries} for {res_key} for {player.name} {vs_hand}')
                                    return

                                else:
                                    if tba[vs_hand][rollover_key]['value'] > 1:
                                        t_value = 1
                                    else:
                                        t_value = .05
                                    if testing: print(f'Transferring {t_value} {res_key} to {rollover_key}')
                                    tba[vs_hand][res_key]['value'] = mround(tba[vs_hand][res_key]['value'] - t_value)
                                    tba[vs_hand][rollover_key]['value'] = mround(
                                        tba[vs_hand][rollover_key]['value'] + t_value
                                    )
                                    return

                        def gap_filler(vs_hand, res_key: str):
                            for col in ['1', '2', '3']:
                                total_filler = 0
                                for b_row in ['2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12']:
                                    # print(f'checking {col}-{b_row} {vs_hand} for a None: {results[vs_hand][col][b_row]["result"]}')
                                    if not results[vs_hand][col][b_row]['result']:
                                        chances = chances_from_row(b_row)
                                        total_filler += chances
                                        tba[vs_hand][res_key]['actual'] = mround(
                                            tba[vs_hand][res_key]['actual'] + chances
                                        )
                                        results[vs_hand][col][b_row] = result_data(tba[vs_hand][res_key], b_row)
                            if testing:
                                print(f'total filler: {total_filler}')

                        # Build vl results then vR
                        for vHand in ['vL', 'vR']:
                            # Refactored bp-hr
                            retries = False
                            while tba[vHand]['bp-hr']['value'] > 0:
                                assign_chances(
                                    res_key='bp-hr',
                                    vs_hand=vHand,
                                    remainder_keys=[],
                                    allow_retry=retries,
                                    rollover_key='do-cf',
                                    is_good=True
                                )
                                retries = False

                            # Fatigue results
                            retries = False
                            while tba[vHand]['so']['value'] >= 1 and tba[vHand]['fatigue'] < 10:
                                assign_chances(
                                    res_key='so',
                                    vs_hand=vHand,
                                    remainder_keys=[],
                                    allow_retry=retries,
                                    rollover_key='',
                                    is_good=False,
                                    force_whole=True
                                )
                            if tba[vHand]['fatigue'] < 10 and tba[vHand]['gb-a']['value'] >= 1:
                                assign_chances(
                                    res_key='gb-a',
                                    vs_hand=vHand,
                                    remainder_keys=[],
                                    allow_retry=retries,
                                    rollover_key='',
                                    is_good=False,
                                    force_whole=True
                                )
                            if tba[vHand]['fatigue'] < 10 and tba[vHand]['gb-c']['value'] >= 1:
                                assign_chances(
                                    res_key='gb-c',
                                    vs_hand=vHand,
                                    remainder_keys=[],
                                    allow_retry=retries,
                                    rollover_key='',
                                    is_good=False,
                                    force_whole=True
                                )
                            if tba[vHand]['fatigue'] < 10 and tba[vHand]['fo-slap']['value'] >= 1:
                                assign_chances(
                                    res_key='fo-slap',
                                    vs_hand=vHand,
                                    remainder_keys=[],
                                    allow_retry=retries,
                                    rollover_key=f'fo-cf',
                                    is_good=False
                                )
                            if tba[vHand]['fatigue'] <= 10 and tba[vHand]['fo-cf']['value'] >= 1:
                                assign_chances(
                                    res_key='fo-cf',
                                    vs_hand=vHand,
                                    remainder_keys=[],
                                    allow_retry=retries,
                                    rollover_key=f'gb-c',
                                    is_good=False
                                )

                            # Refactored gb-x-p
                            retries = False
                            while tba[vHand]['gb-x-p']['value'] > 0:
                                assign_chances(
                                    res_key='gb-x-p',
                                    vs_hand=vHand,
                                    remainder_keys=[],
                                    allow_retry=retries,
                                    rollover_key='',
                                    is_good=False
                                )
                                retries = False

                            # Refactored gb-x-c
                            retries = False
                            while tba[vHand]['gb-x-c']['value'] > 0:
                                assign_chances(
                                    res_key='gb-x-c',
                                    vs_hand=vHand,
                                    remainder_keys=[],
                                    allow_retry=retries,
                                    rollover_key='',
                                    is_good=False
                                )
                                retries = False

                            # Refactored gb-x-1b
                            retries = False
                            while tba[vHand]['gb-x-1b']['value'] > 0:
                                assign_chances(
                                    res_key='gb-x-1b',
                                    vs_hand=vHand,
                                    remainder_keys=[],
                                    allow_retry=retries,
                                    rollover_key='',
                                    is_good=False
                                )
                                retries = False

                            # Refactored gb-x-2b
                            retries = False
                            while tba[vHand]['gb-x-2b']['value'] > 0:
                                assign_chances(
                                    res_key='gb-x-2b',
                                    vs_hand=vHand,
                                    remainder_keys=[],
                                    allow_retry=retries,
                                    rollover_key='',
                                    is_good=False
                                )
                                retries = False

                            # Refactored gb-x-3b
                            retries = False
                            while tba[vHand]['gb-x-3b']['value'] > 0:
                                assign_chances(
                                    res_key='gb-x-3b',
                                    vs_hand=vHand,
                                    remainder_keys=[],
                                    allow_retry=retries,
                                    rollover_key='',
                                    is_good=False
                                )
                                retries = False

                            # Refactored gb-x-ss
                            retries = False
                            while tba[vHand]['gb-x-ss']['value'] > 0:
                                assign_chances(
                                    res_key='gb-x-ss',
                                    vs_hand=vHand,
                                    remainder_keys=[],
                                    allow_retry=retries,
                                    rollover_key='',
                                    is_good=False
                                )
                                retries = False

                            # Refactored gb-x-lf
                            retries = False
                            while tba[vHand]['gb-x-lf']['value'] > 0:
                                assign_chances(
                                    res_key='gb-x-lf',
                                    vs_hand=vHand,
                                    remainder_keys=[],
                                    allow_retry=retries,
                                    rollover_key='',
                                    is_good=False
                                )
                                retries = False

                            # Refactored gb-x-cf
                            retries = False
                            while tba[vHand]['gb-x-cf']['value'] > 0:
                                assign_chances(
                                    res_key='gb-x-cf',
                                    vs_hand=vHand,
                                    remainder_keys=[],
                                    allow_retry=retries,
                                    rollover_key='',
                                    is_good=False
                                )
                                retries = False

                            # Refactored gb-x-rf
                            retries = False
                            while tba[vHand]['gb-x-rf']['value'] > 0:
                                assign_chances(
                                    res_key='gb-x-rf',
                                    vs_hand=vHand,
                                    remainder_keys=[],
                                    allow_retry=retries,
                                    rollover_key='',
                                    is_good=False
                                )
                                retries = False

                            # Refactored bp-si
                            retries = True
                            while tba[vHand]['bp-si']['value'] > 0:
                                assign_chances(
                                    res_key='bp-si',
                                    vs_hand=vHand,
                                    remainder_keys=[],
                                    allow_retry=retries,
                                    rollover_key=f'si*',
                                    is_good=False
                                )
                                retries = False

                            # Refactored so
                            retries = False
                            while tba[vHand]['so']['value'] > 0:
                                assign_chances(
                                    res_key='so',
                                    vs_hand=vHand,
                                    remainder_keys=[],
                                    allow_retry=retries,
                                    rollover_key='gb-c',
                                    is_good=False
                                )
                                retries = False

                            # Refactored hbp
                            retries = False
                            while tba[vHand]['hbp']['value'] > 0:
                                assign_chances(
                                    res_key='hbp',
                                    vs_hand=vHand,
                                    remainder_keys=[],
                                    allow_retry=retries,
                                    rollover_key=f'bb',
                                    is_good=True
                                )
                                retries = False

                            # Refactored hr
                            retries = True
                            while tba[vHand]['hr']['value'] > 0:
                                assign_chances(
                                    res_key='hr',
                                    vs_hand=vHand,
                                    remainder_keys=['tr', 'do-cf', 'fo-slap', 'fo-cf'],
                                    allow_retry=retries,
                                    rollover_key=f'do-cf',
                                    is_good=True
                                )
                                retries = False

                            # Refactored si-cf
                            retries = False
                            while tba[vHand]['si-cf']['value'] > 0:
                                assign_chances(
                                    res_key='si-cf',
                                    vs_hand=vHand,
                                    remainder_keys=['gb-c', 'gb-a'],
                                    allow_retry=retries,
                                    rollover_key=f'si*',
                                    is_good=True
                                )
                                retries = False

                            # Refactored tr
                            retries = False
                            while tba[vHand]['tr']['value'] > 0:
                                assign_chances(
                                    res_key='tr',
                                    vs_hand=vHand,
                                    remainder_keys=['do-cf', 'si**', 'fo-cf', 'fo-slap'],
                                    allow_retry=retries,
                                    rollover_key=f'do-cf',
                                    is_good=True
                                )
                                retries = False

                            # Refactored do***
                            retries = True
                            while tba[vHand]['do***']['value'] > 0:
                                assign_chances(
                                    res_key='do***',
                                    vs_hand=vHand,
                                    remainder_keys=['do-cf', 'si**', 'fo-cf', 'fo-slap'],
                                    allow_retry=retries,
                                    rollover_key=f'do-cf',
                                    is_good=True
                                )
                                retries = False

                            # Refactored do**
                            retries = True
                            while tba[vHand]['do**']['value'] > 0:
                                assign_chances(
                                    res_key='do**',
                                    vs_hand=vHand,
                                    remainder_keys=['si**', 'fo-cf', 'fo-slap', 'gb-c'],
                                    allow_retry=retries,
                                    rollover_key=f'do-cf',
                                    is_good=True
                                )
                                retries = False

                            # Refactored do-cf
                            retries = True
                            while tba[vHand]['do-cf']['value'] > 0:
                                assign_chances(
                                    res_key='do-cf',
                                    vs_hand=vHand,
                                    remainder_keys=[f'fo-slap', 'fo-cf', 'gb-c'],
                                    allow_retry=retries,
                                    rollover_key=f'si**',
                                    is_good=True
                                )
                                retries = False

                            # Refactored si**
                            retries = True
                            while tba[vHand]['si**']['value'] > 0:
                                assign_chances(
                                    res_key='si**',
                                    vs_hand=vHand,
                                    remainder_keys=['gb-a', 'gb-c'],
                                    allow_retry=retries,
                                    rollover_key=f'si*',
                                    is_good=True
                                )
                                retries = False

                            # Refactored si*
                            retries = True
                            while tba[vHand]['si*']['value'] > 0:
                                assign_chances(
                                    res_key='si*',
                                    vs_hand=vHand,
                                    remainder_keys=['gb-c', 'gb-a'],
                                    allow_retry=retries,
                                    rollover_key=f'bb',
                                    is_good=False
                                )
                                retries = False

                            # Refactored bb
                            retries = False
                            while tba[vHand]['bb']['value'] > 0:
                                assign_chances(
                                    res_key='bb',
                                    vs_hand=vHand,
                                    remainder_keys=['so'],
                                    allow_retry=retries,
                                    rollover_key=f'gb-c',
                                    is_good=True
                                )
                                retries = False

                            # Refactored fo-slap
                            retries = False
                            while tba[vHand]['fo-slap']['value'] > 0:
                                assign_chances(
                                    res_key='fo-slap',
                                    vs_hand=vHand,
                                    remainder_keys=['fo-cf'],
                                    allow_retry=retries,
                                    rollover_key=f'fo-cf',
                                    is_good=False
                                )
                                retries = False

                            # Refactored fo-cf
                            retries = False
                            while tba[vHand]['fo-cf']['value'] > 0:
                                assign_chances(
                                    res_key='fo-cf',
                                    vs_hand=vHand,
                                    remainder_keys=[],
                                    allow_retry=retries,
                                    rollover_key=f'gb-c',
                                    is_good=False
                                )
                                retries = False

                            # Refactored gb-b
                            retries = False
                            while tba[vHand]['gb-c']['value'] > 0:
                                assign_chances(
                                    res_key='gb-c',
                                    vs_hand=vHand,
                                    remainder_keys=['gb-a'],
                                    allow_retry=retries,
                                    rollover_key=f'gb-a',
                                    is_good=False
                                )
                                retries = False

                            # Refactored gb-a
                            retries = False
                            while tba[vHand]['gb-a']['value'] > 0:
                                assign_chances(
                                    res_key='gb-a',
                                    vs_hand=vHand,
                                    remainder_keys=[],
                                    allow_retry=retries,
                                    rollover_key=f'so',
                                    is_good=False
                                )
                                retries = False

                            """
                            Whatever result is last should be run through the gap_filler()
                            """

                            if testing: print(f'filling in gaps with gb-a')
                            gap_filler(vHand, 'fo-cf')

                        if testing:
                            print(f'\n\n******\n\n{player.name} Results:\n{results}\n{tba}')
                        else:
                            print(f'Completed {player.name}')
                        col_output = column_output()
                        if testing: print(f'\n\ncol_output:\n{col_output}\n\n')

                        # # Prep csv pitcher lines
                        # logging.info(f'prepping pitcher lines')
                        # card_columns.append(
                        #     [player.name, player.sba_id, bat_hand,
                        #      col_output['vl_one_2d6'], col_output['vl_one_results'], col_output['vl_one_splits'],
                        #      col_output['vl_two_2d6'], col_output['vl_two_results'], col_output['vl_two_splits'],
                        #      col_output['vl_three_2d6'], col_output['vl_three_results'], col_output['vl_three_splits'],
                        #      col_output['vr_one_2d6'], col_output['vr_one_results'], col_output['vr_one_splits'],
                        #      col_output['vr_two_2d6'], col_output['vr_two_results'], col_output['vr_two_splits'],
                        #      col_output['vr_three_2d6'], col_output['vr_three_results'], col_output['vr_three_splits']]
                        # )

                        for hand in ['vL', 'vR']:
                            logging.info(f'inserting pitcher ratings')
                            p_ratings = {
                                'id': f'{player.sba_id}-{hand}-{cardset.id}',
                                'player': player,
                                'cardset': cardset,
                                'vs_hand': hand,
                                'is_prep': False,
                                'homerun': mround(tba[hand]['hr']['actual']),
                                'bp_homerun': mround(tba[hand]['bp-hr']['actual']),
                                'triple': mround(tba[hand]['tr']['actual']),
                                'double_three': mround(tba[hand]['do***']['actual']),
                                'double_two': mround(tba[hand]['do**']['actual']),
                                'double_cf': mround(tba[hand]['do-cf']['actual']),
                                'single_two': mround(tba[hand]['si**']['actual']),
                                'single_one': mround(tba[hand]['si*']['actual']),
                                'single_center': mround(tba[hand]['si-cf']['actual']),
                                'bp_single': mround(tba[hand]['bp-si']['actual']),
                                'hbp': mround(tba[hand]['hbp']['actual']),
                                'walk': mround(tba[hand]['bb']['actual']),
                                'strikeout': mround(tba[hand]['so']['actual']),
                                'fo_slap': mround(tba[hand]['fo-slap']['actual']),
                                'fo_center': mround(tba[hand]['fo-cf']['actual']),
                                'groundout_a': mround(tba[hand]['gb-a']['actual']),
                                'groundout_b': mround(tba[hand]['gb-c']['actual']),
                                'xcheck_p': mround(tba[hand]['gb-x-p']['actual']),
                                'xcheck_c': mround(tba[hand]['gb-x-c']['actual']),
                                'xcheck_1b': mround(tba[hand]['gb-x-1b']['actual']),
                                'xcheck_2b': mround(tba[hand]['gb-x-2b']['actual']),
                                'xcheck_3b': mround(tba[hand]['gb-x-3b']['actual']),
                                'xcheck_ss': mround(tba[hand]['gb-x-ss']['actual']),
                                'xcheck_lf': mround(tba[hand]['gb-x-lf']['actual']),
                                'xcheck_cf': mround(tba[hand]['gb-x-cf']['actual']),
                                'xcheck_rf': mround(tba[hand]['gb-x-rf']['actual'])
                            }

                            count_hits = (
                                p_ratings['homerun'] + p_ratings['bp_homerun'] / 2 + p_ratings['triple'] +
                                p_ratings['double_three'] + p_ratings['double_two'] + p_ratings['double_cf'] +
                                p_ratings['single_two'] + p_ratings['single_one'] +
                                p_ratings['single_center'] + p_ratings['bp_single']
                            )

                            p_ratings['avg'] = count_hits / 108
                            p_ratings['obp'] = (
                                    count_hits + p_ratings['hbp'] + p_ratings['walk'] +
                                    (p_ratings['xcheck_p'] + p_ratings['xcheck_c'] + p_ratings['xcheck_1b'] +
                                     p_ratings['xcheck_2b'] + p_ratings['xcheck_3b'] + p_ratings['xcheck_ss'] +
                                     p_ratings['xcheck_lf'] + p_ratings['xcheck_cf'] + p_ratings['xcheck_rf']) * .3
                            ) / 108
                            p_ratings['slg'] = (
                                ((p_ratings['homerun'] + p_ratings['bp_homerun']) * 4) + (p_ratings['triple'] * 3) +
                                ((p_ratings['double_three'] + p_ratings['double_two'] + p_ratings['double_cf']) * 2) +
                                p_ratings['single_two'] + p_ratings['single_one'] + p_ratings['single_center'] +
                                p_ratings['bp_single'] / 2
                            ) / 108

                            PitcherRatings.insert(p_ratings).on_conflict_replace().execute()

                            logging.info(f'inserting pitcher columns')
                            this_columns = {
                                'id': f'{player.sba_id}-{hand}-{cardset.id}',
                                'player': player,
                                'hand': bat_hand,
                                'p_ratings_id': f'{player.sba_id}-{hand}-{cardset.id}',
                                'one_dice': col_output[f'{hand.lower()}_one_2d6'],
                                'one_results': col_output[f'{hand.lower()}_one_results'],
                                'one_splits': col_output[f'{hand.lower()}_one_splits'],
                                'two_dice': col_output[f'{hand.lower()}_two_2d6'],
                                'two_results': col_output[f'{hand.lower()}_two_results'],
                                'two_splits': col_output[f'{hand.lower()}_two_splits'],
                                'three_dice': col_output[f'{hand.lower()}_three_2d6'],
                                'three_results': col_output[f'{hand.lower()}_three_results'],
                                'three_splits': col_output[f'{hand.lower()}_three_splits']
                            }
                            CardColumns.insert(this_columns).on_conflict_replace().execute()

                        # # Prep csv ratings guide
                        # logging.info(f'prepping pitcher ratings guide')
                        # rg_line = [player.name, bat_hand]
                        # for hand in ['vL', 'vR']:
                        #     for x in rg_headers:
                        #         if x not in ['name', 'hand']:
                        #             rg_line.append(mround(tba[hand][x]['actual']))
                        # ratings_guide.append(rg_line)
                        logging.info(f'completed {player.name}')

                        count_pitchers += 1

                    # No player match
                    else:
                        logging.error(f'Could not match fangraph player id {row[0]}')
                        print(f'Could not match fangraph player id {row[0]}')
                except Exception as e:
                    logging.error(f'Failed to process pitcher {row[0]} ({row[2]}): {type(e)}: {e}')
                    print(f'Failed to process pitcher {row[0]} ({row[2]})')

        print(f'Processed {count_pitchers} pitcher stat lines into chances...')

        """
        Export card output to csv for Component Studio
        """
        # # Removed since output has own script now
        # try:
        #     output_path.mkdir(parents=True)
        # except FileExistsError as e:
        #     print(f'Directory {output_path} already exists')
        # write_to_csv(output_path, f'pitcher-ratings-guide-{now.strftime("%Y-%m-%d-%f")}', ratings_guide)
        # write_to_csv(output_path, f'pitcher-card-columns-{now.strftime("%Y-%m-%d-%f")}', card_columns)

        """
        END OF PITCHERS
        """

    lets_go = input(f'Should I run batters (y/n)? ')
    if lets_go in YES:
        # https://www.baseball-reference.com/leagues/majors/2022-baserunning-batting.shtml
        with open(f'{input_path}baserunning-data.csv', 'r') as file:
            reader = csv.reader(file)

            for row in reader:
                player = Player.get_or_none(Player.br_id == row[36])
                if player:
                    dupe = BatterData.delete().where(
                        (BatterData.player == player) & (BatterData.cardset == cardset)
                    ).execute()

                    stealing = b.stealing(
                        int(row[8]), int(row[12]), int(row[13]), int(row[14]), int(row[15]), season_pct
                    )
                    this_data = BatterData(
                        player=player,
                        cardset=cardset,
                        stealing=b.stealing_line(stealing),
                        st_low=stealing[0],
                        st_high=stealing[1],
                        st_auto=stealing[2],
                        st_jump=stealing[3],
                        running=b.running(row[26]),
                        hit_and_run='C',
                        bunting='C'
                    )
                    this_data.save()

                else:
                    logging.error(f'Could not match bbref id {row[36]}')
                    print(f'Could not match bbref id {row[36]}')

        existing_columns = CardColumns.delete().where(
            CardColumns.id.endswith(f'-{cardset.id}') & CardColumns.b_ratings.is_null(False)
        ).execute()
        existing_batters = BatterRatings.delete().where(BatterRatings.cardset == cardset).execute()

        # rg_headers = ['name', 'hand', 'hr', 'bp-hr', 'tr', 'do***', 'do**', 'do-pull', 'si**', 'si*', 'si-cf', 'bp-si',
        #               'hbp', 'bb', 'so', 'lo', 'po', 'fo-a', 'fo-bq', 'fo-lf-b', 'fo-rf-b', 'gb-a', 'gb-b', 'gb-c']
        # ratings_guide = [[
        #     'name', 'hand', 'hr-vL', 'bp-hr-vL', 'tr-vL', 'do***-vL', 'do**-vL', 'do-pull-vL', 'si**-vL', 'si*-vL',
        #     'si-cf-vL', 'bp-si-vL', 'hbp-vL', 'bb-vL', 'so-vL', 'lo-vL', 'po-vL', 'fo-a-vL', 'fo-bq-vL', 'fo-lf-b-vL',
        #     'fo-rf-b-vL', 'gb-a-vL', 'gb-b-vL', 'gb-c-vL', 'hr-vR', 'bp-hr-vR', 'tr-vR', 'do***-vR', 'do**-vR',
        #     'do-pull-vR', 'si**-vR', 'si*-vR', 'si-cf-vR', 'bp-si-vR', 'hbp-vR', 'bb-vR', 'so-vR', 'lo-vR', 'po-vR',
        #     'fo-a-vR', 'fo-bq-vR', 'fo-lf-b-vR', 'fo-rf-b-vR', 'gb-a-vR', 'gb-b-vR', 'gb-c-vR'
        # ]]
        # all_results = [['name', 'sba_id', 'hand', 'vl_one_2d6', 'vl_one_results', 'vl_one_splits',
        #                 'vl_two_2d6', 'vl_two_results', 'vl_two_splits',
        #                 'vl_three_2d6', 'vl_three_results', 'vl_three_splits',
        #                 'vr_one_2d6', 'vr_one_results', 'vr_one_splits',
        #                 'vr_two_2d6', 'vr_two_results', 'vr_two_splits',
        #                 'vr_three_2d6', 'vr_three_results', 'vr_three_splits']]

        with open(f'{input_path}batter-stats.csv', 'r') as file:
            reader = csv.reader(file)

            for row in reader:
                player = Player.get_or_none(Player.fg_id == int(row[0]))
                if player and (('Promo' in cardset.set_title) or ('Major League' in cardset.set_title) or
                               (int(row[5]) >= 28 and int(row[39]) >= 58)):
                    chance_data_vl = {
                        'id': f'{player.sba_id}-vL-{cardset.id}-bat',
                        'player_id': player.sba_id,
                        'cardset_id': cardset.id,
                        'vs_hand': 'vL',
                        'is_prep': True,
                        'homerun': 0,
                        'bp_homerun': 0,
                        'triple': 0,
                        'double_three': 0,
                        'double_two': 0,
                        'double_pull': 0,
                        'single_two': 0,
                        'single_one': 0,
                        'single_center': 0,
                        'bp_single': 0,
                        'hbp': 0,
                        'walk': 0,
                        'strikeout': 0,
                        'lineout': 0,
                        'popout': 0,
                        'flyout_a': 0,
                        'flyout_bq': 0,
                        'flyout_lf_b': 0,
                        'flyout_rf_b': 0,
                        'groundout_a': 0,
                        'groundout_b': 0,
                        'groundout_c': 0,
                    }
                    chance_data_vr = {
                        'id': f'{player.sba_id}-vR-{cardset.id}-bat',
                        'player_id': player.sba_id,
                        'cardset_id': cardset.id,
                        'vs_hand': 'vR',
                        'is_prep': True,
                        'homerun': 0,
                        'bp_homerun': 0,
                        'triple': 0,
                        'double_three': 0,
                        'double_two': 0,
                        'double_pull': 0,
                        'single_two': 0,
                        'single_one': 0,
                        'single_center': 0,
                        'bp_single': 0,
                        'hbp': 0,
                        'walk': 0,
                        'strikeout': 0,
                        'lineout': 0,
                        'popout': 0,
                        'flyout_a': 0,
                        'flyout_bq': 0,
                        'flyout_lf_b': 0,
                        'flyout_rf_b': 0,
                        'groundout_a': 0,
                        'groundout_b': 0,
                        'groundout_c': 0,
                    }
                    bat_hand = player.hand

                    # Turn sheets workflow into code here

                    offense_mod = 1.2
                    all_hits_vl = mround(108 * offense_mod * float(row[23]))
                    all_hits_vr = mround(108 * offense_mod * float(row[57]))

                    hard_rate_vl = float(row[38])
                    hard_rate_vr = float(row[72])
                    med_rate_vl = float(row[37])
                    med_rate_vr = float(row[71])
                    soft_rate_vl = float(row[36])
                    soft_rate_vr = float(row[70])

                    if int(row[7]) == 0:
                        all_singles_vl = 0.0
                    else:
                        all_singles_vl = mround(all_hits_vl * (float(row[8]) / float(row[7])))
                    if int(row[41]) == 0:
                        all_singles_vr = 0.0
                    else:
                        all_singles_vr = mround(all_hits_vr * (float(row[42]) / float(row[41])))

                    chance_data_vl['bp_single'] = b.bp_singles(all_singles_vl)
                    chance_data_vr['bp_single'] = b.bp_singles(all_singles_vr)

                    chance_data_vl['single_two'] = b.wh_singles(
                        mround(all_singles_vl - chance_data_vl['bp_single']), hard_rate_vl
                    )
                    chance_data_vr['single_two'] = b.wh_singles(
                        mround(all_singles_vr - chance_data_vr['bp_single']), hard_rate_vr
                    )

                    chance_data_vl['single_one'] = b.one_singles(
                        mround(all_singles_vl - chance_data_vl['bp_single'] - chance_data_vl['single_two']),
                        ifh_rate=float(row[31]),
                        force_rem=True if chance_data_vl['single_two'] == 0 else False
                    )
                    chance_data_vr['single_one'] = b.one_singles(
                        mround(all_singles_vr - chance_data_vr['bp_single'] - chance_data_vr['single_two']),
                        ifh_rate=float(row[65]),
                        force_rem=True if chance_data_vr['single_two'] == 0 else False
                    )

                    chance_data_vl['single_center'] = mround(
                        all_singles_vl - chance_data_vl['bp_single'] - chance_data_vl['single_two'] -
                        chance_data_vl['single_one']
                    )
                    chance_data_vr['single_center'] = mround(
                        all_singles_vr - chance_data_vr['bp_single'] - chance_data_vr['single_two'] -
                        chance_data_vr['single_one']
                    )

                    total_singles_vl = (
                            chance_data_vl['bp_single'] + chance_data_vl['single_two'] + chance_data_vl['single_one'] +
                            chance_data_vl['single_center']
                    )
                    total_singles_vr = (
                            chance_data_vr['bp_single'] + chance_data_vr['single_two'] + chance_data_vr['single_one'] +
                            chance_data_vr['single_center']
                    )
                    rem_hits_vl = all_hits_vl - total_singles_vl
                    rem_hits_vr = all_hits_vr - total_singles_vr

                    all_hr_vl = b.all_homeruns(rem_hits_vl, all_hits_vl, float(row[11]), float(row[7]), float(row[8]))
                    all_hr_vr = b.all_homeruns(
                        rem_hits_vr, all_hits_vr, float(row[45]), float(row[41]), float(row[42])
                    )

                    chance_data_vl['homerun'] = b.nd_homeruns(all_hr_vl, float(row[30]))
                    chance_data_vr['homerun'] = b.nd_homeruns(all_hr_vr, float(row[64]))
                    chance_data_vl['bp_homerun'] = mround(all_hr_vl - chance_data_vl['homerun'])
                    chance_data_vr['bp_homerun'] = mround(all_hr_vr - chance_data_vr['homerun'])

                    total_hr_vl = mround(chance_data_vl['homerun'] + chance_data_vl['bp_homerun'])
                    total_hr_vr = mround(chance_data_vr['homerun'] + chance_data_vr['bp_homerun'])

                    all_xbh_vl = mround(all_hits_vl - total_singles_vl - total_hr_vl)
                    all_xbh_vr = mround(all_hits_vr - total_singles_vr - total_hr_vr)

                    chance_data_vl['triple'] = b.triples(
                        all_xbh_vl, float(row[10]), float(row[9])
                    )
                    chance_data_vr['triple'] = b.triples(
                        all_xbh_vr, float(row[44]), float(row[43])
                    )

                    all_doubles_vl = mround(all_xbh_vl - chance_data_vl['triple'])
                    all_doubles_vr = mround(all_xbh_vr - chance_data_vr['triple'])

                    chance_data_vl['double_two'] = b.two_doubles(all_doubles_vl, soft_rate_vl)
                    chance_data_vr['double_two'] = b.two_doubles(all_doubles_vr, soft_rate_vr)
                    chance_data_vl['double_pull'] = mround(all_doubles_vl - chance_data_vl['double_two'])
                    chance_data_vr['double_pull'] = mround(all_doubles_vr - chance_data_vr['double_two'])

                    total_doubles_vl = mround(chance_data_vl['double_two'] + chance_data_vl['double_pull'])
                    total_doubles_vr = mround(chance_data_vr['double_two'] + chance_data_vr['double_pull'])

                    other_ob_vl = mround(108 * offense_mod * ((float(row[14]) + float(row[17])) / float(row[5])))
                    other_ob_vr = mround(108 * offense_mod * ((float(row[48]) + float(row[51])) / float(row[39])))

                    chance_data_vl['hbp'] = b.hit_by_pitch(other_ob_vl, float(row[17]), float(row[14]))
                    chance_data_vr['hbp'] = b.hit_by_pitch(other_ob_vr, float(row[51]), float(row[48]))
                    chance_data_vl['walk'] = mround(other_ob_vl - chance_data_vl['hbp'])
                    chance_data_vr['walk'] = mround(other_ob_vr - chance_data_vr['hbp'])

                    all_outs_vl = mround(108 - all_hits_vl - other_ob_vl)
                    all_outs_vr = mround(108 - all_hits_vr - other_ob_vr)

                    chance_data_vl['strikeout'] = b.strikeouts(all_outs_vl, float(row[16]) / float(row[5]))
                    chance_data_vr['strikeout'] = b.strikeouts(all_outs_vr, float(row[50]) / float(row[39]))

                    rem_outs_vl = mround(all_outs_vl - chance_data_vl['strikeout'])
                    rem_outs_vr = mround(all_outs_vr - chance_data_vr['strikeout'])

                    lineouts_vl = max(mround(rem_outs_vl * float(row[26])), 1)
                    lineouts_vr = max(mround(rem_outs_vr * float(row[60])), 1)
                    chance_data_vl['popout'] = b.popouts(lineouts_vl - 1, float(row[29]))
                    chance_data_vr['popout'] = b.popouts(lineouts_vr - 1, float(row[63]))
                    chance_data_vl['lineout'] = mround(lineouts_vl - chance_data_vl['popout'])
                    chance_data_vr['lineout'] = mround(lineouts_vr - chance_data_vr['popout'])

                    rem_outs_vl = mround(rem_outs_vl - chance_data_vl['lineout'] - chance_data_vl['popout'])
                    rem_outs_vr = mround(rem_outs_vr - chance_data_vr['lineout'] - chance_data_vr['popout'])
                    flyouts_vl = mround(rem_outs_vl * float(row[28]))
                    flyouts_vr = mround(rem_outs_vr * float(row[62]))

                    chance_data_vl['flyout_a'] = b.flyout_a(flyouts_vl, hard_rate_vl)
                    chance_data_vr['flyout_a'] = b.flyout_a(flyouts_vr, hard_rate_vr)
                    rem_flyouts_vl = mround(flyouts_vl - chance_data_vl['flyout_a'])
                    rem_flyouts_vr = mround(flyouts_vr - chance_data_vr['flyout_a'])
                    chance_data_vl['flyout_bq'] = b.flyout_bq(rem_flyouts_vl, soft_rate_vl)
                    chance_data_vr['flyout_bq'] = b.flyout_bq(rem_flyouts_vr, soft_rate_vr)
                    rem_flyouts_vl = mround(flyouts_vl - chance_data_vl['flyout_bq'])
                    rem_flyouts_vr = mround(flyouts_vr - chance_data_vr['flyout_bq'])
                    chance_data_vl['flyout_lf_b'] = b.flyout_b(
                        rem_flyouts_vl,
                        float(row[33]) if bat_hand.lower() == 'r' else float(row[35]),
                        float(row[34])
                    )
                    chance_data_vr['flyout_lf_b'] = b.flyout_b(
                        rem_flyouts_vr,
                        float(row[67]) if bat_hand.lower() == 'r' else float(row[69]),
                        float(row[68])
                    )
                    chance_data_vl['flyout_rf_b'] = mround(rem_flyouts_vl - chance_data_vl['flyout_lf_b'])
                    chance_data_vr['flyout_rf_b'] = mround(rem_flyouts_vr - chance_data_vr['flyout_lf_b'])

                    rem_outs_vl = mround(rem_outs_vl - flyouts_vl)
                    rem_outs_vr = mround(rem_outs_vr - flyouts_vr)
                    groundouts_vl = mround(rem_outs_vl)
                    groundouts_vr = mround(rem_outs_vr)

                    chance_data_vl['groundout_a'] = b.groundball_a(groundouts_vl, float(row[20]), float(row[6]))
                    chance_data_vr['groundout_a'] = b.groundball_a(groundouts_vr, float(row[54]), float(row[40]))
                    chance_data_vl['groundout_c'] = b.groundball_c(
                        groundouts_vl - chance_data_vl['groundout_a'], med_rate_vl
                    )
                    chance_data_vr['groundout_c'] = b.groundball_c(
                        groundouts_vr - chance_data_vr['groundout_a'], med_rate_vr
                    )
                    chance_data_vl['groundout_b'] = mround(
                        groundouts_vl - chance_data_vl['groundout_a'] - chance_data_vl['groundout_c']
                    )
                    chance_data_vr['groundout_b'] = mround(
                        groundouts_vr - chance_data_vr['groundout_a'] - chance_data_vr['groundout_c']
                    )

                    if testing:
                        print(f'vL: {chance_data_vl}\nvR: {chance_data_vr}')
                        print(f'total chances vL: {b.total_chances(chance_data_vl)} / '
                          f'vR: {b.total_chances(chance_data_vr)}')

                    BatterRatings.insert(chance_data_vl).on_conflict_replace().execute()
                    BatterRatings.insert(chance_data_vr).on_conflict_replace().execute()

                    b_data = BatterData.select().where(
                        (BatterData.player == player) & (BatterData.cardset == cardset)
                    ).limit(1)
                    if b_data.count() == 1:
                        babip = (all_hits_vl + all_hits_vr - all_hr_vl - all_hr_vr) / \
                                (216 - chance_data_vl['strikeout'] - chance_data_vr['strikeout'] +
                                 chance_data_vl['flyout_lf_b'] + chance_data_vr['flyout_lf_b'] - all_hr_vl - all_hr_vr)

                        if babip >= .35:
                            hnr = 'A'
                        elif babip >= .3:
                            hnr = 'B'
                        elif babip >= .225:
                            hnr = 'C'
                        else:
                            hnr = 'D'

                        b_data[0].hit_and_run = hnr
                        b_data[0].save()
                    else:
                        print(f'No BatterData for {player.name}')

                    """
                    Process batter chances into card output
                    """

                    bat_hand = player.hand
                    tba = {
                        'vL': {
                            'bp-si': {
                                'value': chance_data_vl['bp_single'],
                                'string': '▼BP-SI',
                                'bold': True,
                                'actual': 0
                            },
                            'si-cf': {
                                'value': chance_data_vl['single_center'],
                                'string': 'SINGLE (cf)',
                                'sm-string': 'SI (cf)',
                                'bold': True,
                                'actual': 0
                            },
                            'si*': {
                                'value': chance_data_vl['single_one'],
                                'string': 'SINGLE*',
                                'sm-string': 'SI*',
                                'bold': True,
                                'actual': 0
                            },
                            'si**': {
                                'value': chance_data_vl['single_two'],
                                'string': 'SINGLE**',
                                'sm-string': 'SI**',
                                'bold': True,
                                'actual': 0
                            },
                            'bp-hr': {
                                'value': chance_data_vl['bp_homerun'],
                                'string': '◆BP-HR',
                                'bold': True,
                                'actual': 0
                            },
                            'hr': {
                                'value': chance_data_vl['homerun'],
                                'string': 'HOMERUN',
                                'sm-string': 'HR',
                                'bold': True,
                                'actual': 0
                            },
                            'tr': {
                                'value': chance_data_vl['triple'],
                                'string': 'TRIPLE',
                                'sm-string': 'TR',
                                'bold': True,
                                'actual': 0
                            },
                            'do**': {
                                'value': chance_data_vl['double_two'],
                                'string': 'DOUBLE**',
                                'sm-string': 'DO**',
                                'bold': True,
                                'actual': 0
                            },
                            'do***': {
                                'value': chance_data_vl['double_three'],
                                'string': 'DOUBLE***',
                                'sm-string': 'DO***',
                                'bold': True,
                                'actual': 0
                            },
                            'do-pull': {
                                'value': chance_data_vl['double_pull'],
                                'string': f'DOUBLE ({"rf" if bat_hand == "L" else "lf"})',
                                'sm-string': f'DO ({"rf" if bat_hand == "L" else "lf"})',
                                'bold': True,
                                'actual': 0
                            },
                            'hbp': {
                                'value': chance_data_vl['hbp'],
                                'string': 'HBP',
                                'bold': True,
                                'actual': 0
                            },
                            'bb': {
                                'value': chance_data_vl['walk'],
                                'string': 'WALK',
                                'bold': True,
                                'actual': 0
                            },
                            'so': {
                                'value': chance_data_vl['strikeout'],
                                'string': 'strikeout',
                                'bold': False,
                                'actual': 0
                            },
                            'lo': {
                                'value': chance_data_vl['lineout'],
                                'string': f'lineout ({"ss" if bat_hand == "L" else "2b"})',
                                'sm-string': f'lo ({"ss" if bat_hand == "L" else "2b"})',
                                'bold': False,
                                'actual': 0
                            },
                            'po': {
                                'value': chance_data_vl['popout'],
                                'string': f'popout ({"2b" if bat_hand == "L" else "ss"})',
                                'bold': False,
                                'actual': 0
                            },
                            'fo-a': {
                                'value': chance_data_vl['flyout_a'],
                                'string': f'fly (cf) A',
                                'bold': False,
                                'actual': 0
                            },
                            'fo-bq': {
                                'value': chance_data_vl['flyout_bq'],
                                'string': f'fly (cf) B?',
                                'bold': False,
                                'actual': 0
                            },
                            'fo-lf-b': {
                                'value': chance_data_vl['flyout_lf_b'],
                                'string': f'fly (lf) B',
                                'bold': False,
                                'actual': 0
                            },
                            'fo-rf-b': {
                                'value': chance_data_vl['flyout_rf_b'],
                                'string': f'fly (rf) B',
                                'bold': False,
                                'actual': 0
                            },
                            'gb-a': {
                                'value': chance_data_vl['groundout_a'],
                                'string': f'gb ({"2b" if bat_hand == "L" else "ss"}) A',
                                'bold': False,
                                'actual': 0
                            },
                            'gb-b': {
                                'value': chance_data_vl['groundout_b'],
                                'string': f'gb ({"ss" if bat_hand == "L" else "2b"}) B',
                                'bold': False,
                                'actual': 0
                            },
                            'gb-c': {
                                'value': chance_data_vl['groundout_c'],
                                'string': f'gb ({"3b" if bat_hand == "L" else "1b"}) B',
                                'bold': False,
                                'actual': 0
                            }
                        },
                        'vR': {
                            'bp-si': {
                                'value': chance_data_vr['bp_single'],
                                'string': '▼BP-SI',
                                'bold': True,
                                'actual': 0
                            },
                            'si-cf': {
                                'value': chance_data_vr['single_center'],
                                'string': 'SINGLE (cf)',
                                'sm-string': 'SI (cf)',
                                'bold': True,
                                'actual': 0
                            },
                            'si*': {
                                'value': chance_data_vr['single_one'],
                                'string': 'SINGLE*',
                                'sm-string': 'SI*',
                                'bold': True,
                                'actual': 0
                            },
                            'si**': {
                                'value': chance_data_vr['single_two'],
                                'string': 'SINGLE**',
                                'sm-string': 'SI**',
                                'bold': True,
                                'actual': 0
                            },
                            'bp-hr': {
                                'value': chance_data_vr['bp_homerun'],
                                'string': '◆BP-HR',
                                'bold': True,
                                'actual': 0
                            },
                            'hr': {
                                'value': chance_data_vr['homerun'],
                                'string': 'HOMERUN',
                                'sm-string': 'HR',
                                'bold': True,
                                'actual': 0
                            },
                            'tr': {
                                'value': chance_data_vr['triple'],
                                'string': 'TRIPLE',
                                'sm-string': 'TR',
                                'bold': True,
                                'actual': 0
                            },
                            'do**': {
                                'value': chance_data_vr['double_two'],
                                'string': 'DOUBLE**',
                                'sm-string': 'DO**',
                                'bold': True,
                                'actual': 0
                            },
                            'do***': {
                                'value': chance_data_vr['double_three'],
                                'string': 'DOUBLE***',
                                'sm-string': 'DO***',
                                'bold': True,
                                'actual': 0
                            },
                            'do-pull': {
                                'value': chance_data_vr['double_pull'],
                                'string': f'DOUBLE ({"rf" if bat_hand == "L" else "lf"})',
                                'sm-string': f'DO ({"rf" if bat_hand == "L" else "lf"})',
                                'bold': True,
                                'actual': 0
                            },
                            'hbp': {
                                'value': chance_data_vr['hbp'],
                                'string': 'HBP',
                                'bold': True,
                                'actual': 0
                            },
                            'bb': {
                                'value': chance_data_vr['walk'],
                                'string': 'WALK',
                                'bold': True,
                                'actual': 0
                            },
                            'so': {
                                'value': chance_data_vr['strikeout'],
                                'string': 'strikeout',
                                'bold': False,
                                'actual': 0
                            },
                            'lo': {
                                'value': chance_data_vr['lineout'],
                                'string': f'lineout ({"ss" if bat_hand == "L" else "2b"})',
                                'sm-string': f'lo ({"ss" if bat_hand == "L" else "2b"})',
                                'bold': False,
                                'actual': 0
                            },
                            'po': {
                                'value': chance_data_vr['popout'],
                                'string': f'popout ({"2b" if bat_hand == "L" else "ss"})',
                                'bold': False,
                                'actual': 0
                            },
                            'fo-a': {
                                'value': chance_data_vr['flyout_a'],
                                'string': f'fly (cf) A',
                                'bold': False,
                                'actual': 0
                            },
                            'fo-bq': {
                                'value': chance_data_vr['flyout_bq'],
                                'string': f'fly (cf) B?',
                                'bold': False,
                                'actual': 0
                            },
                            'fo-lf-b': {
                                'value': chance_data_vr['flyout_lf_b'],
                                'string': f'fly (lf) B',
                                'bold': False,
                                'actual': 0
                            },
                            'fo-rf-b': {
                                'value': chance_data_vr['flyout_rf_b'],
                                'string': f'fly (rf) B',
                                'bold': False,
                                'actual': 0
                            },
                            'gb-a': {
                                'value': chance_data_vr['groundout_a'],
                                'string': f'gb ({"2b" if bat_hand == "L" else "ss"}) A',
                                'bold': False,
                                'actual': 0
                            },
                            'gb-b': {
                                'value': chance_data_vr['groundout_b'],
                                'string': f'gb ({"ss" if bat_hand == "L" else "2b"}) B',
                                'bold': False,
                                'actual': 0
                            },
                            'gb-c': {
                                'value': chance_data_vr['groundout_c'],
                                'string': f'gb ({"3b" if bat_hand == "L" else "1b"}) B',
                                'bold': False,
                                'actual': 0
                            }
                        }
                    }
                    results = copy.deepcopy(BLANK_RESULTS)

                    def column_output():
                        card_output = {}

                        for hand in ['vL', 'vR']:
                            for col in ['1', '2', '3']:
                                card_output[f'{hand.lower()}_{get_col(col)}_2d6'] = ''
                                card_output[f'{hand.lower()}_{get_col(col)}_results'] = ''
                                card_output[f'{hand.lower()}_{get_col(col)}_splits'] = ''

                        for hand in ['vL', 'vR']:
                            for col in ['1', '2', '3']:
                                int_results = {}
                                for x in results[hand][col]:
                                    try:
                                        int_results[int(x)] = results[hand][col][x]
                                    except ValueError as e:
                                        if testing:
                                            print(f'skipping {x} in column_output')

                                if testing: print(f'{int_results}')

                                sorted_results = {
                                    row_num: int_results[row_num] for row_num in sorted(int_results.keys())
                                }
                                for line in sorted_results:
                                    if testing: print(f'\nsorted_results: {sorted_results}\nline: {line}')
                                    if sorted_results[line]["result"]:
                                        card_output[f'{hand.lower()}_{get_col(col)}_2d6'] += \
                                            f'{results[hand][col][str(line)]["2d6"]}\n'
                                        card_output[f'{hand.lower()}_{get_col(col)}_results'] += \
                                            f'{results[hand][col][str(line)]["result"]}\n'
                                        card_output[f'{hand.lower()}_{get_col(col)}_splits'] += \
                                            f'{results[hand][col][str(line)]["splits"]}\n'

                        return card_output

                    def add_full_result(vs_hand, tba_data, is_good, chances):
                        all_cols = []
                        good_col = player.offense_col
                        if is_good:
                            if good_col == 1:
                                second = random.choice([2, 3])
                                all_cols = [1, second, 3 if second == 2 else 2]
                            elif good_col == 2:
                                second = random.choice([1, 3])
                                all_cols = [2, second, 3 if second == 1 else 1]
                            elif good_col == 3:
                                second = random.choice([1, 2])
                                all_cols = [3, second, 1 if second == 1 else 2]
                        else:
                            if good_col == 1:
                                f_col = random.choice([2, 3])
                                all_cols = [f_col, 3 if f_col == 2 else 2, 1]
                            elif good_col == 2:
                                f_col = random.choice([1, 3])
                                all_cols = [f_col, 3 if f_col == 1 else 1, 2]
                            elif good_col == 3:
                                f_col = random.choice([1, 2])
                                all_cols = [f_col, 1 if f_col == 1 else 2, 3]

                        if chances == 6:
                            for column in all_cols:
                                if not results[vs_hand][f'{column}']['7']['result']:
                                    results[vs_hand][f'{column}']['7'] = result_data(tba_data, 7)
                                    return chances
                                if not results[vs_hand][f'{column}']['6']['result'] and not \
                                        results[vs_hand][f'{column}']['2']['result']:
                                    results[vs_hand][f'{column}']['6'] = result_data(tba_data, 6)
                                    results[vs_hand][f'{column}']['2'] = result_data(tba_data, 2)
                                    return chances
                                if not results[vs_hand][f'{column}']['8']['result'] and not \
                                        results[vs_hand][f'{column}']['12']['result']:
                                    results[vs_hand][f'{column}']['8'] = result_data(tba_data, 8)
                                    results[vs_hand][f'{column}']['12'] = result_data(tba_data, 12)
                                    return chances
                                if not results[vs_hand][f'{column}']['6']['result'] and not \
                                        results[vs_hand][f'{column}']['12']['result']:
                                    results[vs_hand][f'{column}']['6'] = result_data(tba_data, 6)
                                    results[vs_hand][f'{column}']['12'] = result_data(tba_data, 12)
                                    return chances
                                if not results[vs_hand][f'{column}']['8']['result'] and not \
                                        results[vs_hand][f'{column}']['2']['result']:
                                    results[vs_hand][f'{column}']['8'] = result_data(tba_data, 8)
                                    results[vs_hand][f'{column}']['2'] = result_data(tba_data, 2)
                                    return chances

                            # No matches
                            return 0

                        elif chances == 5:
                            for column in all_cols:
                                if not results[vs_hand][f'{column}']['6']['result']:
                                    results[vs_hand][f'{column}']['6'] = result_data(tba_data, 6)
                                    return chances
                                if not results[vs_hand][f'{column}']['8']['result']:
                                    results[vs_hand][f'{column}']['8'] = result_data(tba_data, 8)
                                    return chances
                                if not results[vs_hand][f'{column}']['3']['result'] and not \
                                        results[vs_hand][f'{column}']['4']['result']:
                                    results[vs_hand][f'{column}']['3'] = result_data(tba_data, 3)
                                    results[vs_hand][f'{column}']['4'] = result_data(tba_data, 4)
                                    return chances
                                if not results[vs_hand][f'{column}']['3']['result'] and not \
                                        results[vs_hand][f'{column}']['10']['result']:
                                    results[vs_hand][f'{column}']['3'] = result_data(tba_data, 3)
                                    results[vs_hand][f'{column}']['10'] = result_data(tba_data, 10)
                                    return chances
                                if not results[vs_hand][f'{column}']['4']['result'] and not \
                                        results[vs_hand][f'{column}']['11']['result']:
                                    results[vs_hand][f'{column}']['4'] = result_data(tba_data, 4)
                                    results[vs_hand][f'{column}']['11'] = result_data(tba_data, 11)
                                    return chances
                                if not results[vs_hand][f'{column}']['10']['result'] and not \
                                        results[vs_hand][f'{column}']['11']['result']:
                                    results[vs_hand][f'{column}']['10'] = result_data(tba_data, 10)
                                    results[vs_hand][f'{column}']['11'] = result_data(tba_data, 11)
                                    return chances

                            # No matches
                            return 0

                        elif chances == 4:
                            for column in all_cols:
                                if not results[vs_hand][f'{column}']['5']['result']:
                                    results[vs_hand][f'{column}']['5'] = result_data(tba_data, 5)
                                    return chances
                                if not results[vs_hand][f'{column}']['9']['result']:
                                    results[vs_hand][f'{column}']['9'] = result_data(tba_data, 9)
                                    return chances
                                if not results[vs_hand][f'{column}']['3']['result'] and not \
                                        results[vs_hand][f'{column}']['11']['result']:
                                    results[vs_hand][f'{column}']['3'] = result_data(tba_data, 3)
                                    results[vs_hand][f'{column}']['11'] = result_data(tba_data, 11)
                                    return chances
                                if not results[vs_hand][f'{column}']['2']['result'] and not \
                                        results[vs_hand][f'{column}']['4']['result']:
                                    results[vs_hand][f'{column}']['2'] = result_data(tba_data, 2)
                                    results[vs_hand][f'{column}']['4'] = result_data(tba_data, 4)
                                    return chances
                                if not results[vs_hand][f'{column}']['10']['result'] and not \
                                        results[vs_hand][f'{column}']['12']['result']:
                                    results[vs_hand][f'{column}']['10'] = result_data(tba_data, 10)
                                    results[vs_hand][f'{column}']['12'] = result_data(tba_data, 12)
                                    return chances
                                if not results[vs_hand][f'{column}']['2']['result'] and not \
                                        results[vs_hand][f'{column}']['10']['result']:
                                    results[vs_hand][f'{column}']['2'] = result_data(tba_data, 2)
                                    results[vs_hand][f'{column}']['10'] = result_data(tba_data, 10)
                                    return chances
                                if not results[vs_hand][f'{column}']['10']['result'] and not \
                                        results[vs_hand][f'{column}']['4']['result']:
                                    results[vs_hand][f'{column}']['10'] = result_data(tba_data, 10)
                                    results[vs_hand][f'{column}']['4'] = result_data(tba_data, 4)
                                    return chances

                            return 0

                        elif chances == 3:
                            for column in all_cols:
                                if not results[vs_hand][f'{column}']['4']['result']:
                                    results[vs_hand][f'{column}']['4'] = result_data(tba_data, 4)
                                    return chances
                                if not results[vs_hand][f'{column}']['10']['result']:
                                    results[vs_hand][f'{column}']['10'] = result_data(tba_data, 10)
                                    return chances
                                if not results[vs_hand][f'{column}']['2']['result'] and not \
                                        results[vs_hand][f'{column}']['3']['result']:
                                    results[vs_hand][f'{column}']['2'] = result_data(tba_data, 2)
                                    results[vs_hand][f'{column}']['3'] = result_data(tba_data, 3)
                                    return chances
                                if not results[vs_hand][f'{column}']['2']['result'] and not \
                                        results[vs_hand][f'{column}']['11']['result']:
                                    results[vs_hand][f'{column}']['2'] = result_data(tba_data, 2)
                                    results[vs_hand][f'{column}']['11'] = result_data(tba_data, 11)
                                    return chances
                                if not results[vs_hand][f'{column}']['12']['result'] and not \
                                        results[vs_hand][f'{column}']['3']['result']:
                                    results[vs_hand][f'{column}']['12'] = result_data(tba_data, 12)
                                    results[vs_hand][f'{column}']['3'] = result_data(tba_data, 3)
                                    return chances
                                if not results[vs_hand][f'{column}']['12']['result'] and not \
                                        results[vs_hand][f'{column}']['11']['result']:
                                    results[vs_hand][f'{column}']['12'] = result_data(tba_data, 12)
                                    results[vs_hand][f'{column}']['11'] = result_data(tba_data, 11)
                                    return chances

                            return 0

                        elif chances == 2:
                            for column in all_cols:
                                if not results[vs_hand][f'{column}']['3']['result']:
                                    results[vs_hand][f'{column}']['3'] = result_data(tba_data, 3)
                                    return chances
                                if not results[vs_hand][f'{column}']['11']['result']:
                                    results[vs_hand][f'{column}']['11'] = result_data(tba_data, 11)
                                    return chances
                                if not results[vs_hand][f'{column}']['2']['result'] and not \
                                        results[vs_hand][f'{column}']['12']['result']:
                                    results[vs_hand][f'{column}']['2'] = result_data(tba_data, 2)
                                    results[vs_hand][f'{column}']['12'] = result_data(tba_data, 12)
                                    return chances

                            return 0

                        elif chances == 1:
                            for column in all_cols:
                                if not results[vs_hand][f'{column}']['2']['result']:
                                    results[vs_hand][f'{column}']['2'] = result_data(tba_data, 2)
                                    return chances
                                if not results[vs_hand][f'{column}']['12']['result']:
                                    results[vs_hand][f'{column}']['12'] = result_data(tba_data, 12)
                                    return chances
                            return 0

                    def add_split_result(vs_hand, tba_data_top, tba_data_bottom, chances_top, is_good=None):
                        all_cols = []
                        good_col = player.offense_col

                        if is_good is None:
                            if good_col == 1:
                                f_col = random.choice([2, 3])
                                all_cols = [f_col, 1, 3 if f_col == 2 else 2]
                            elif good_col == 2:
                                f_col = random.choice([1, 3])
                                all_cols = [f_col, 2, 3 if f_col == 1 else 1]
                            elif good_col == 3:
                                f_col = random.choice([1, 2])
                                all_cols = [f_col, 3, 1 if f_col == 1 else 2]

                        elif is_good:
                            if good_col == 1:
                                second = random.choice([2, 3])
                                all_cols = [1, second, 3 if second == 2 else 2]
                            elif good_col == 2:
                                second = random.choice([1, 3])
                                all_cols = [2, second, 3 if second == 1 else 1]
                            elif good_col == 3:
                                second = random.choice([1, 2])
                                all_cols = [3, second, 1 if second == 1 else 2]

                        else:
                            if good_col == 1:
                                f_col = random.choice([2, 3])
                                all_cols = [f_col, 3 if f_col == 2 else 2, 1]
                            elif good_col == 2:
                                f_col = random.choice([1, 3])
                                all_cols = [f_col, 3 if f_col == 1 else 1, 2]
                            elif good_col == 3:
                                f_col = random.choice([1, 2])
                                all_cols = [f_col, 1 if f_col == 1 else 2, 3]

                        legal_2d6 = legal_splits(chances_top)
                        for column in all_cols:
                            if results[vs_hand][f'{column}']['splits'] < 3:
                                for y in legal_2d6:
                                    if tba_data_bottom['value'] >= y['bad_chances'] and not \
                                            results[vs_hand][f'{column}'][f'{y["2d6"]}']['result']:
                                        results[vs_hand][f'{column}'][f'{y["2d6"]}'] = \
                                            result_data(tba_data_top, y["2d6"], tba_data_bottom, y["incs"])
                                        results[vs_hand][f'{column}']['splits'] += 1
                                        return y['bad_chances']

                        if testing: print(f'Legal 2d6: {legal_2d6}')
                        if testing: print(f'Could not find a legal spot for:\n{tba_data_top}\n{tba_data_bottom}')
                        return None

                    def assign_chances(
                            res_key: str, vs_hand: str, remainder_keys: list[str], allow_retry: bool, rollover_key: str,
                            is_good: bool, force_whole: bool = False):
                        retries = 0 if allow_retry else 1

                        if testing: print(f'starting {res_key}: {tba[vs_hand][res_key]["value"]}')
                        # If not even int, add_split_result with less than half of total chances
                        total_chances = mround(tba[vs_hand][res_key]['value'])
                        # chance_remainder = mround(total_chances - math.floor(total_chances))

                        # If total chance is a whole number, do easy assignments first
                        if int(total_chances) - total_chances == 0 or force_whole or tba[vs_hand][res_key]['value'] > 2:
                            if testing: print(f'{tba[vs_hand][res_key]["value"]} {res_key}s being placed')
                            if tba[vs_hand][res_key]['value'] > 9.5:
                                num_added = add_full_result(vs_hand, tba[vs_hand][res_key], is_good, 6)

                            elif tba[vs_hand][res_key]['value'] > 7.5:
                                num_added = add_full_result(vs_hand, tba[vs_hand][res_key], is_good, 5)

                            elif tba[vs_hand][res_key]['value'] > 5.5:
                                num_added = add_full_result(vs_hand, tba[vs_hand][res_key], is_good, 4)

                            else:
                                num_added = add_full_result(
                                    vs_hand,
                                    tba[vs_hand][res_key],
                                    is_good,
                                    int(tba[vs_hand][res_key]['value'])
                                )

                            if num_added:
                                tba[vs_hand][res_key]['value'] = mround(tba[vs_hand][res_key]['value'] - num_added)
                                tba[vs_hand][res_key]['actual'] = mround(tba[vs_hand][res_key]['actual'] + num_added)
                                return

                            elif retries == 0:
                                if testing: print(f'retry # {retries} for {res_key} for {player.name} {vs_hand}')
                                return

                            else:
                                if tba[vs_hand][rollover_key]['value'] >= 1:
                                    t_value = 1
                                else:
                                    t_value = .05
                                if testing: print(f'Transferring {t_value} {res_key} to {rollover_key}')
                                tba[vs_hand][rollover_key]['value'] = mround(tba[vs_hand][rollover_key]['value'] + t_value)
                                tba[vs_hand][res_key]['value'] = mround(tba[vs_hand][res_key]['value'] - t_value)
                                return

                        # Else start dicing up the chances
                        else:
                            # if retries == 0 and total_chances > 3:
                            #     chance_remainder = mround(
                            #         math.ceil(total_chances / 2) - (total_chances - math.floor(total_chances))
                            #     )
                            # else:
                            #     chance_remainder = mround(total_chances - math.floor(total_chances))

                            chance_remainder = mround(total_chances - math.floor(total_chances))
                            if testing: print(f'chance_remainder: {chance_remainder}')

                            # if mround(chance_remainder) != 0 and mround(chance_remainder) > .5:
                            # TO ROLL BACK, UNDO ABOVE COMMEND AND TAB ALL BELOW CODE IN ONCE
                            top_chances = None
                            bottom_key = None
                            bottom_result = None

                            """
                            If this result cannot take any splits (but has extra results pass the remainder to the rollover and 
                            come back to assign_chances with a whole number
                            """
                            if len(remainder_keys) == 0:
                                tba[vs_hand][res_key]['value'] = mround(math.floor(tba[vs_hand][res_key]['value']))
                                tba[vs_hand][rollover_key]['value'] = mround(
                                    tba[vs_hand][rollover_key]['value'] + chance_remainder
                                )
                                return

                            for rem_key in remainder_keys:
                                if mround(tba[vs_hand][rem_key]['value']) >= mround(1 - chance_remainder):
                                    bottom_key = rem_key
                                    bottom_result = tba[vs_hand][rem_key]
                                    break

                            if not bottom_key:
                                if tba[vs_hand][rollover_key]['value'] > 1:
                                    t_value = 1
                                else:
                                    t_value = .05
                                if testing: print(f'Transferring {t_value} {res_key} to {rollover_key}')

                                tba[vs_hand][res_key]['value'] = mround(tba[vs_hand][res_key]['value'] - t_value)
                                tba[vs_hand][rollover_key]['value'] = mround(
                                    tba[vs_hand][rollover_key]['value'] + t_value
                                )
                                return
                                # raise ValueError(
                                #     f'Could not find a second result for a {res_key} split for {player.name} {vHand}')

                            bottom_chances = None
                            if tba[vs_hand][res_key]['value'] > 4:
                                top_chances = mround(3 + chance_remainder)
                                if testing: print(f'checking top_chances: {top_chances}')
                                bottom_chances = add_split_result(
                                    vs_hand, tba[vs_hand][res_key], bottom_result, top_chances, is_good
                                )

                            elif tba[vs_hand][res_key]['value'] > 3:
                                top_chances = mround(2 + chance_remainder)
                                if testing: print(f'checking top_chances: {top_chances}')
                                bottom_chances = add_split_result(
                                    vs_hand, tba[vs_hand][res_key], bottom_result, top_chances, is_good
                                )

                            elif tba[vs_hand][res_key]['value'] > 2:
                                top_chances = mround(1 + chance_remainder)
                                if testing: print(f'checking top_chances: {top_chances}')
                                bottom_chances = add_split_result(
                                    vs_hand, tba[vs_hand][res_key], bottom_result, top_chances, is_good
                                )

                            if not bottom_chances:
                                top_chances = mround(chance_remainder)
                                if testing: print(f'checking top_chances: {top_chances}')
                                bottom_chances = add_split_result(
                                    vs_hand, tba[vs_hand][res_key], bottom_result, top_chances, is_good
                                )

                            if not bottom_chances and tba[vs_hand][res_key]['value'] > 3:
                                top_chances = mround(.5 + chance_remainder)
                                if testing: print(f'checking top_chances: {top_chances}')
                                bottom_chances = add_split_result(
                                    vs_hand, tba[vs_hand][res_key], bottom_result, top_chances, is_good
                                )

                            if not bottom_chances and tba[vs_hand][res_key]['value'] > 3:
                                top_chances = mround(.7 + chance_remainder)
                                if testing: print(f'checking top_chances: {top_chances}')
                                bottom_chances = add_split_result(
                                    vs_hand, tba[vs_hand][res_key], bottom_result, top_chances, is_good
                                )

                            if not bottom_chances and chance_remainder > 0.15:
                                top_chances = mround(chance_remainder - 0.15)
                                if testing: print(f'checking top_chances: {top_chances}')
                                bottom_chances = add_split_result(
                                    vs_hand, tba[vs_hand][res_key], bottom_result, top_chances, is_good
                                )

                            if not bottom_chances and chance_remainder > 0.05:
                                top_chances = mround(chance_remainder - 0.05)
                                if testing: print(f'checking top_chances: {top_chances}')
                                bottom_chances = add_split_result(
                                    vs_hand, tba[vs_hand][res_key], bottom_result, top_chances, is_good
                                )

                            if testing: print(f'{res_key} chances: {mround(top_chances)} / split with {bottom_result}')

                            if bottom_chances:
                                tba[vs_hand][res_key]['value'] = mround(tba[vs_hand][res_key]['value'] - top_chances)
                                tba[vs_hand][res_key]['actual'] = mround(tba[vs_hand][res_key]['actual'] + top_chances)
                                tba[vs_hand][bottom_key]['value'] = mround(
                                    tba[vs_hand][bottom_key]['value'] - bottom_chances)
                                tba[vs_hand][bottom_key]['actual'] = mround(
                                    tba[vs_hand][bottom_key]['actual'] + bottom_chances
                                )
                                if testing: print(
                                    f'placed {top_chances} {res_key}s and {bottom_chances} {bottom_result["string"]}s for '
                                    f'{player.name} {vs_hand}\n\n')
                                return

                            elif retries == 0:
                                retries += 1
                                if testing: print(f'retry # {retries} for {res_key} for {player.name} {vs_hand}')
                                return

                            else:
                                if tba[vs_hand][rollover_key]['value'] > 1:
                                    t_value = 1
                                else:
                                    t_value = .05
                                if testing: print(f'Transferring {t_value} {res_key} to {rollover_key}')
                                tba[vs_hand][res_key]['value'] = mround(tba[vs_hand][res_key]['value'] - t_value)
                                tba[vs_hand][rollover_key]['value'] = mround(
                                    tba[vs_hand][rollover_key]['value'] + t_value
                                )
                                return

                    def gap_filler(vs_hand, res_key: str):
                        for col in ['1', '2', '3']:
                            for b_row in ['2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12']:
                                # print(f'checking {col}-{b_row} {vs_hand} for a None: {results[vs_hand][col][b_row]["result"]}')
                                if not results[vs_hand][col][b_row]['result']:
                                    chances = chances_from_row(b_row)
                                    tba[vs_hand][res_key]['actual'] = mround(
                                        tba[vs_hand][res_key]['actual'] + chances
                                    )
                                    results[vs_hand][col][b_row] = result_data(tba[vs_hand][res_key], b_row)

                    # Build vl results then vR
                    for vHand in ['vL', 'vR']:
                        # Refactored bp-hr
                        retries = False
                        while tba[vHand]['bp-hr']['value'] > 0:
                            assign_chances(
                                res_key='bp-hr',
                                vs_hand=vHand,
                                remainder_keys=[],
                                allow_retry=retries,
                                rollover_key='do-pull',
                                is_good=True
                            )
                            retries = False

                        # Refactored fo-a
                        retries = False
                        while tba[vHand]['fo-a']['value'] > 0:
                            assign_chances(
                                res_key='fo-a',
                                vs_hand=vHand,
                                remainder_keys=[],
                                allow_retry=retries,
                                rollover_key=f'{"fo-lf-b" if bat_hand == "R" else "fo-rf-b"}',
                                is_good=False
                            )
                            retries = False

                        # Refactored si-cf
                        retries = False
                        while tba[vHand]['si-cf']['value'] > 0:
                            assign_chances(
                                res_key='si-cf',
                                vs_hand=vHand,
                                remainder_keys=[],
                                allow_retry=retries,
                                rollover_key=f'si*',
                                is_good=True
                            )
                            retries = False

                        # Refactored bp-si
                        retries = True
                        while tba[vHand]['bp-si']['value'] > 0:
                            assign_chances(
                                res_key='bp-si',
                                vs_hand=vHand,
                                remainder_keys=[],
                                allow_retry=retries,
                                rollover_key=f'si*',
                                is_good=False
                            )
                            retries = False

                        # Refactored hbp
                        retries = False
                        while tba[vHand]['hbp']['value'] > 0:
                            assign_chances(
                                res_key='hbp',
                                vs_hand=vHand,
                                remainder_keys=[],
                                allow_retry=retries,
                                rollover_key=f'bb',
                                is_good=True
                            )
                            retries = False

                        # Refactored hr
                        retries = True
                        while tba[vHand]['hr']['value'] > 0:
                            assign_chances(
                                res_key='hr',
                                vs_hand=vHand,
                                remainder_keys=['tr', 'do-pull', f'fo-{get_of(bat_hand, vHand)}-b',
                                                f'fo-{get_of(bat_hand, vHand, pull_side=False)}-b'],
                                allow_retry=retries,
                                rollover_key=f'do-pull',
                                is_good=True
                            )
                            retries = False

                        # Refactored tr
                        retries = False
                        while tba[vHand]['tr']['value'] > 0:
                            assign_chances(
                                res_key='tr',
                                vs_hand=vHand,
                                remainder_keys=['do-pull', 'si**', f'fo-{get_of(bat_hand, vHand)}-b',
                                                f'fo-{get_of(bat_hand, vHand, pull_side=False)}-b'],
                                allow_retry=retries,
                                rollover_key=f'do-pull',
                                is_good=True
                            )
                            retries = False

                        # Refactored do***
                        retries = True
                        while tba[vHand]['do***']['value'] > 0:
                            assign_chances(
                                res_key='do***',
                                vs_hand=vHand,
                                remainder_keys=['si**', f'fo-{get_of(bat_hand, vHand, pull_side=False)}-b',
                                                f'fo-{get_of(bat_hand, vHand)}-b', 'lo', 'gb-c'],
                                allow_retry=retries,
                                rollover_key=f'do-pull',
                                is_good=True
                            )
                            retries = False

                        # Refactored do**
                        retries = True
                        while tba[vHand]['do**']['value'] > 0:
                            assign_chances(
                                res_key='do**',
                                vs_hand=vHand,
                                remainder_keys=['si**', f'fo-{get_of(bat_hand, vHand, pull_side=False)}-b',
                                                f'fo-{get_of(bat_hand, vHand)}-b', 'lo', 'gb-c'],
                                allow_retry=retries,
                                rollover_key=f'do-pull',
                                is_good=True
                            )
                            retries = False

                        # Refactored do**
                        retries = True
                        while tba[vHand]['do-pull']['value'] > 0:
                            assign_chances(
                                res_key='do-pull',
                                vs_hand=vHand,
                                remainder_keys=[f'fo-{get_of(bat_hand, vHand)}-b', 'lo', 'gb-c'],
                                allow_retry=retries,
                                rollover_key=f'si**',
                                is_good=True
                            )
                            retries = False

                        # Refactored si**
                        retries = True
                        while tba[vHand]['si**']['value'] > 0:
                            assign_chances(
                                res_key='si**',
                                vs_hand=vHand,
                                remainder_keys=['lo', 'gb-a', 'gb-b', 'gb-c', 'po'],
                                allow_retry=retries,
                                rollover_key=f'si*',
                                is_good=True
                            )
                            retries = False

                        # Refactored si*
                        retries = True
                        while tba[vHand]['si*']['value'] > 0:
                            assign_chances(
                                res_key='si*',
                                vs_hand=vHand,
                                remainder_keys=['gb-c', 'gb-b', 'gb-a', 'lo', 'po'],
                                allow_retry=retries,
                                rollover_key=f'gb-c',
                                is_good=False
                            )
                            retries = False

                        # Refactored bb
                        retries = False
                        while tba[vHand]['bb']['value'] > 0:
                            assign_chances(
                                res_key='bb',
                                vs_hand=vHand,
                                remainder_keys=['so'],
                                allow_retry=retries,
                                rollover_key=f'gb-c',
                                is_good=True
                            )
                            retries = False

                        # Refactored so
                        retries = False
                        while tba[vHand]['so']['value'] > 0:
                            assign_chances(
                                res_key='so',
                                vs_hand=vHand,
                                remainder_keys=[],
                                allow_retry=retries,
                                rollover_key='po',
                                is_good=False
                            )
                            retries = False

                        # TODO: Add support for the lomax

                        # Refactored lo
                        # retries = False
                        # assign_chances(
                        #     res_key='lo',
                        #     vHand=vHand,
                        #     remainder_keys=['gb-a'],
                        #     allow_retry=retries,
                        #     rollover_key=f'po',
                        #     is_good=False
                        # )

                        while tba[vHand]['lo']['value'] > 0:
                            assign_chances(
                                res_key='lo',
                                vs_hand=vHand,
                                remainder_keys=[],
                                allow_retry=retries,
                                rollover_key=f'po',
                                is_good=False
                            )
                            retries = False

                        # Refactored po
                        retries = False
                        while tba[vHand]['po']['value'] > 0:
                            assign_chances(
                                res_key='po',
                                vs_hand=vHand,
                                remainder_keys=[],
                                allow_retry=retries,
                                rollover_key=f'so',
                                is_good=False
                            )
                            retries = False

                        # Refactored fo-lf-b
                        retries = False
                        while tba[vHand]['fo-lf-b']['value'] > 0:
                            assign_chances(
                                res_key='fo-lf-b',
                                vs_hand=vHand,
                                remainder_keys=[],
                                allow_retry=retries,
                                rollover_key=f'fo-rf-b',
                                is_good=False
                            )
                            retries = False

                        # Refactored fo-rf-b
                        retries = False
                        while tba[vHand]['fo-rf-b']['value'] > 0:
                            assign_chances(
                                res_key='fo-rf-b',
                                vs_hand=vHand,
                                remainder_keys=[],
                                allow_retry=retries,
                                rollover_key=f'fo-bq',
                                is_good=False
                            )
                            retries = False

                        # Refactored fo-bq
                        retries = False
                        while tba[vHand]['fo-bq']['value'] > 0:
                            assign_chances(
                                res_key='fo-bq',
                                vs_hand=vHand,
                                remainder_keys=[],
                                allow_retry=retries,
                                rollover_key=f'gb-c',
                                is_good=False
                            )
                            retries = False

                        # Refactored gb-c
                        retries = False
                        while tba[vHand]['gb-c']['value'] > 0:
                            assign_chances(
                                res_key='gb-c',
                                vs_hand=vHand,
                                remainder_keys=[],
                                allow_retry=retries,
                                rollover_key=f'gb-b',
                                is_good=False
                            )
                            retries = False

                        # Refactored gb-b
                        retries = False
                        while tba[vHand]['gb-b']['value'] > 0:
                            assign_chances(
                                res_key='gb-b',
                                vs_hand=vHand,
                                remainder_keys=['gb-a'],
                                allow_retry=retries,
                                rollover_key=f'gb-a',
                                is_good=False
                            )
                            retries = False

                        # # Refactored gb-a
                        # retries = False
                        # while tba[vHand]['gb-a']['value'] > 0:
                        #     assign_chances(
                        #         res_key='gb-a',
                        #         vs_hand=vHand,
                        #         remainder_keys=[],
                        #         allow_retry=retries,
                        #         rollover_key=f'so',
                        #         is_good=False
                        #     )
                        #     retries = False

                        """
                        Whatever result is last should be run through the gap_filler()
                        """

                        if testing: print(f'filling in gaps with gb-a')
                        gap_filler(vHand, 'gb-a')

                    if testing:
                        print(f'\n\n******\n\n{player.name} Results:\n{results}\n{tba}')
                    # else:
                    #     print(f'Completed {player.name}')
                    col_output = column_output()
                    if testing: print(f'\n\ncol_output:\n{col_output}\n\n')

                    # # Prep csv batter lines
                    # all_results.append(
                    #     [player.name, player.sba_id, bat_hand,
                    #      col_output['vl_one_2d6'], col_output['vl_one_results'], col_output['vl_one_splits'],
                    #      col_output['vl_two_2d6'], col_output['vl_two_results'], col_output['vl_two_splits'],
                    #      col_output['vl_three_2d6'], col_output['vl_three_results'], col_output['vl_three_splits'],
                    #      col_output['vr_one_2d6'], col_output['vr_one_results'], col_output['vr_one_splits'],
                    #      col_output['vr_two_2d6'], col_output['vr_two_results'], col_output['vr_two_splits'],
                    #      col_output['vr_three_2d6'], col_output['vr_three_results'], col_output['vr_three_splits']]
                    # )

                    for hand in ['vL', 'vR']:
                        b_ratings = {
                            'id': f'{player.sba_id}-{hand}-{cardset.id}',
                            'player': player,
                            'cardset': cardset,
                            'vs_hand': hand,
                            'is_prep': False,
                            'homerun': mround(tba[hand]['hr']['actual']),
                            'bp_homerun': mround(tba[hand]['bp-hr']['actual']),
                            'triple': mround(tba[hand]['tr']['actual']),
                            'double_three': mround(tba[hand]['do***']['actual']),
                            'double_two': mround(tba[hand]['do**']['actual']),
                            'double_pull': mround(tba[hand]['do-pull']['actual']),
                            'single_two': mround(tba[hand]['si**']['actual']),
                            'single_one': mround(tba[hand]['si*']['actual']),
                            'single_center': mround(tba[hand]['si-cf']['actual']),
                            'bp_single': mround(tba[hand]['bp-si']['actual']),
                            'hbp': mround(tba[hand]['hbp']['actual']),
                            'walk': mround(tba[hand]['bb']['actual']),
                            'strikeout': mround(tba[hand]['so']['actual']),
                            'lineout': mround(tba[hand]['lo']['actual']),
                            'popout': mround(tba[hand]['po']['actual']),
                            'flyout_a': mround(tba[hand]['fo-a']['actual']),
                            'flyout_bq': mround(tba[hand]['fo-bq']['actual']),
                            'flyout_lf_b': mround(tba[hand]['fo-lf-b']['actual']),
                            'flyout_rf_b': mround(tba[hand]['fo-rf-b']['actual']),
                            'groundout_a': mround(tba[hand]['gb-a']['actual']),
                            'groundout_b': mround(tba[hand]['gb-b']['actual']),
                            'groundout_c': mround(tba[hand]['gb-c']['actual'])
                        }

                        count_hits = (
                            b_ratings['homerun'] + b_ratings['bp_homerun'] / 2 + b_ratings['triple'] +
                            b_ratings['double_three'] + b_ratings['double_two'] +
                            b_ratings['double_pull'] + b_ratings['single_two'] + b_ratings['single_one'] +
                            b_ratings['single_center'] + b_ratings['bp_single'] / 2
                        )

                        b_ratings['avg'] = count_hits / 108
                        b_ratings['obp'] = (
                                count_hits + b_ratings['hbp'] + b_ratings['walk']
                        ) / 108
                        b_ratings['slg'] = (
                            (b_ratings['homerun'] * 4) + (b_ratings['triple'] * 3) +
                            ((b_ratings['bp_homerun'] + b_ratings['double_three'] + b_ratings['double_two'] +
                             b_ratings['double_pull']) * 2) +
                            b_ratings['single_two'] + b_ratings['single_one'] + b_ratings['single_center'] +
                            b_ratings['bp_single'] / 2
                        ) / 108

                        BatterRatings.insert(b_ratings).on_conflict_replace().execute()

                        this_columns = {
                            'id': f'{player.sba_id}-{hand}-{cardset.id}',
                            'player': player,
                            'hand': player.hand,
                            'b_ratings_id': f'{player.sba_id}-{hand}-{cardset.id}',
                            'one_dice': col_output[f'{hand.lower()}_one_2d6'],
                            'one_results': col_output[f'{hand.lower()}_one_results'],
                            'one_splits': col_output[f'{hand.lower()}_one_splits'],
                            'two_dice': col_output[f'{hand.lower()}_two_2d6'],
                            'two_results': col_output[f'{hand.lower()}_two_results'],
                            'two_splits': col_output[f'{hand.lower()}_two_splits'],
                            'three_dice': col_output[f'{hand.lower()}_three_2d6'],
                            'three_results': col_output[f'{hand.lower()}_three_results'],
                            'three_splits': col_output[f'{hand.lower()}_three_splits']
                        }
                        CardColumns.insert(this_columns).on_conflict_replace().execute()

                    # # Prep csv ratings guide
                    # rg_line = [player.name, bat_hand]
                    # for hand in ['vL', 'vR']:
                    #     for x in rg_headers:
                    #         if x not in ['name', 'hand']:
                    #             rg_line.append(mround(tba[hand][x]['actual']))
                    # ratings_guide.append(rg_line)

                # No player match
                else:
                    logging.error(f'Could not match player id {row[0]}')
                    print(f'Could not match player id {row[0]}')

        # # https://www.baseball-reference.com/leagues/majors/2021-standard-batting.shtml
        # with open('baserunning-data.csv', 'r') as file:
        #     reader = csv.reader(file)
        #
        #     for row in reader:
        #         player = Player.get_or_none(Player.br_id == row[36])
        #         if player:

        """
        Export card output to csv for Component Studio
        """
        # # Removed since output has own script now
        # write_to_csv(output_path, f'batter-ratings-guide-{now.strftime("%Y-%m-%d-%f")}', ratings_guide)
        # write_to_csv(output_path, f'batter-card-columns-{now.strftime("%Y-%m-%d-%f")}', all_results)

    lets_go = input(f'Should I run fielders (y/n)? ')
    if lets_go in YES:
        # https://www.baseball-reference.com/leagues/majors/2022-specialpos_p-fielding.shtml
        with open(f'{input_path}defense-p.csv', 'r') as file:
            reader = csv.reader(file)

            for row in reader:
                player = Player.get_or_none(Player.br_id == row[29])
                if player and row[15] != '' and row[12] != '':
                    # Build Position object and save
                    this_pos = Position(
                        player=player,
                        cardset=cardset,
                        position='P',
                        innings=int(float(row[8])),
                        range=d.range_pitcher(int(row[15]), season_pct),
                        error=d.error_pitcher(int(row[12]), int(row[9]), season_pct=season_pct),
                    )
                    dupe = Position.delete().where(
                        (Position.player == player) & (Position.cardset == cardset)
                    ).execute()
                    this_pos.save()

                    spow, rpow = d.pow_ratings(d.innings_float(row[8]), int(row[6]), int(row[5]))
                    this_pit = PitcherData(
                        player=player,
                        cardset=cardset,
                        hold=d.hold_pitcher(row[27], int(row[28]), season_pct),
                        starter_rating=spow,
                        relief_rating=rpow
                    )
                    dupe = PitcherData.delete().where(
                        (PitcherData.player == player) & (PitcherData.cardset == cardset)
                    ).execute()
                    this_pit.save()

                    if int(row[6]) >= int(row[5]) * .1:
                        sp_pos = Position(
                            player=player,
                            cardset=cardset,
                            position='SP',
                            innings=int(float(row[8])) * (int(row[6]) / int(row[5])),
                            range=69,
                            error=420
                        )
                        sp_pos.save()
                    if int(row[6]) <= int(row[5]) * .8:
                        rp_pos = Position(
                            player=player,
                            cardset=cardset,
                            position='RP',
                            innings=int(float(row[8])) * (1 - (int(row[6]) / int(row[5]))),
                            range=69,
                            error=420
                        )
                        rp_pos.save()

                # No player match
                else:
                    logging.error(f'Could not match bbref id {row[29]}')
                    print(f'Could not match bbref id {row[29]}')

        # https://www.baseball-reference.com/leagues/majors/2022-standard-pitching.shtml
        with open(f'{input_path}pitcher-data.csv', 'r') as file:
            reader = csv.reader(file)

            for row in reader:
                player = Player.get_or_none(Player.br_id == row[35])
                if player:
                    all_data = PitcherData.select().where(
                        (PitcherData.player == player) & (PitcherData.cardset == cardset)
                    ).limit(1)
                    try:
                        this_data = all_data[0]
                    except Exception as e:
                        logging.error(f'Could not find existing PitcherData for {player.name}')

                    if this_data:
                        closer_rating = p.closer_rating(int(row[11]), int(row[14]), int(row[9]))
                        this_data.balk = p.balks(int(row[24]), int(float(row[15])), season_pct)
                        this_data.wild_pitch = p.wild_pitches(int(row[25]), int(float(row[15])), season_pct)
                        this_data.closer_rating = closer_rating
                        this_data.batting = f'1W{player.hand}-C'
                        this_data.save()

                        if closer_rating != 'N':
                            cp_pos = Position(
                                player=player,
                                cardset=cardset,
                                position='CP',
                                innings=1,
                                range=69,
                                error=420
                            )
                            cp_pos.save()

                else:
                    logging.error(f'Could not match bbref id {row[35]}')
                    print(f'Could not match bbref id {row[35]}')

        with open(f'{input_path}defense-c.csv', 'r') as file:
            reader = csv.reader(file)
            curr_pos = 'C'

            for row in reader:
                player = Player.get_or_none(Player.br_id == row[34])
                if player:
                    # Build Position object and save
                    this_pos = Position(
                        player=player,
                        cardset=cardset,
                        position=curr_pos,
                        innings=int(float(row[8])),
                        range=d.range_catcher(int(row[17]), season_pct),
                        error=d.error_catcher(int(row[12]), int(row[9]), season_pct),
                        arm=d.arm_catcher(row[33], int(row[25]), season_pct),
                        pb=d.pb_catcher(int(row[29]), int(float(row[8])), season_pct),
                        overthrow=d.ot_catcher(int(row[12]), int(row[9]), season_pct)
                    )
                    dupe = Position.delete().where(
                        (Position.player == player) & (Position.cardset == cardset) & (Position.position == curr_pos)
                    ).execute()
                    this_pos.save()

                # No player match
                else:
                    logging.error(f'Could not match bbref id {row[34]}')
                    print(f'Could not match bbref id {row[34]}')

        with open(f'{input_path}defense-1b.csv', 'r') as file:
            reader = csv.reader(file)
            curr_pos = '1B'

            for row in reader:
                player = Player.get_or_none(Player.br_id == row[29])
                if player and row[24] != '' and row[18] != '':
                    # Build Position object and save
                    this_pos = Position(
                        player=player,
                        cardset=cardset,
                        position=curr_pos,
                        innings=int(float(row[8])),
                        range=d.range_first_base(int(row[24]), int(row[18]), season_pct),
                        error=d.error_first_base(int(row[12]), int(row[9]), season_pct),
                    )
                    dupe = Position.delete().where(
                        (Position.player == player) & (Position.cardset == cardset) & (Position.position == curr_pos)
                    ).execute()
                    this_pos.save()

                # No player match
                else:
                    logging.error(f'Could not match bbref id {row[29]}')
                    print(f'Could not match bbref id {row[29]}')

        with open(f'{input_path}defense-2b.csv', 'r') as file:
            reader = csv.reader(file)
            curr_pos = '2B'

            for row in reader:
                player = Player.get_or_none(Player.br_id == row[29])
                if player and row[25] != '' and row[18] != '':
                    # Build Position object and save
                    this_pos = Position(
                        player=player,
                        cardset=cardset,
                        position=curr_pos,
                        innings=int(float(row[8])),
                        range=d.range_second_base(int(row[25]), int(row[18]), season_pct),
                        error=d.error_second_base(int(row[12]), int(row[9]), season_pct),
                    )
                    dupe = Position.delete().where(
                        (Position.player == player) & (Position.cardset == cardset) & (Position.position == curr_pos)
                    ).execute()
                    this_pos.save()

                # No player match
                else:
                    p_err = f'{player.name if player else "player not found"}'
                    logging.error(f'Could not match bbref id {row[29]}')
                    print(f'Could not match bbref id {row[29]} / player: {p_err} / row[27]: {row[25]} / '
                          f'row[20]: {row[18]}')

        with open(f'{input_path}defense-3b.csv', 'r') as file:
            reader = csv.reader(file)
            curr_pos = '3B'

            for row in reader:
                player = Player.get_or_none(Player.br_id == row[29])
                if player and row[24] != '' and row[18] != '':
                    # Build Position object and save
                    this_pos = Position(
                        player=player,
                        cardset=cardset,
                        position=curr_pos,
                        innings=int(float(row[8])),
                        range=d.range_third_base(int(row[24]), int(row[18]), season_pct),
                        error=d.error_third_base(int(row[12]), int(row[9]), season_pct),
                    )
                    dupe = Position.delete().where(
                        (Position.player == player) & (Position.cardset == cardset) & (Position.position == curr_pos)
                    ).execute()
                    this_pos.save()

                # No player match
                else:
                    logging.error(f'Could not match bbref id {row[29]}')
                    print(f'Could not match bbref id {row[29]}')

        with open(f'{input_path}defense-ss.csv', 'r') as file:
            reader = csv.reader(file)
            curr_pos = 'SS'

            for row in reader:
                player = Player.get_or_none(Player.br_id == row[29])
                if player and row[25] != '' and row[18] != '':
                    # Build Position object and save
                    this_pos = Position(
                        player=player,
                        cardset=cardset,
                        position=curr_pos,
                        innings=int(float(row[8])),
                        range=d.range_shortstop(int(row[25]), int(row[18]), season_pct),
                        error=d.error_shortstop(int(row[12]), int(row[9]), season_pct),
                    )
                    dupe = Position.delete().where(
                        (Position.player == player) & (Position.cardset == cardset) & (Position.position == curr_pos)
                    ).execute()
                    this_pos.save()

                # No player match
                else:
                    logging.error(f'Could not match bbref id {row[29]}')
                    print(f'Could not match bbref id {row[29]}')

        with open(f'{input_path}defense-lf.csv', 'r') as file:
            reader = csv.reader(file)
            curr_pos = 'LF'

            for row in reader:
                player = Player.get_or_none(Player.br_id == row[26])
                if player and row[22] != '':
                    # Build Position object and save
                    this_pos = Position(
                        player=player,
                        cardset=cardset,
                        position=curr_pos,
                        innings=int(float(row[8])),
                        range=d.range_left_field(int(row[19]), season_pct),
                        error='69',
                        arm=row[22]
                    )
                    dupe = Position.delete().where(
                        (Position.player == player) & (Position.cardset == cardset) & (Position.position == curr_pos)
                    ).execute()
                    this_pos.save()

                # No player match
                else:
                    logging.error(f'Could not match bbref id {row[26]}')
                    print(f'Could not match bbref id {row[26]}')

        with open(f'{input_path}defense-cf.csv', 'r') as file:
            reader = csv.reader(file)
            curr_pos = 'CF'

            for row in reader:
                player = Player.get_or_none(Player.br_id == row[26])
                if player and row[22] != '':
                    # Build Position object and save
                    this_pos = Position(
                        player=player,
                        cardset=cardset,
                        position=curr_pos,
                        innings=int(float(row[8])),
                        range=d.range_center_field(int(row[19]), season_pct),
                        error='69',
                        arm=row[22]
                    )
                    dupe = Position.delete().where(
                        (Position.player == player) & (Position.cardset == cardset) & (Position.position == curr_pos)
                    ).execute()
                    this_pos.save()

                # No player match
                else:
                    logging.error(f'Could not match bbref id {row[26]}')
                    print(f'Could not match bbref id {row[26]}')

        with open(f'{input_path}defense-rf.csv', 'r') as file:
            reader = csv.reader(file)
            curr_pos = 'RF'

            for row in reader:
                player = Player.get_or_none(Player.br_id == row[26])
                if player and row[22] != '':
                    # Build Position object and save
                    this_pos = Position(
                        player=player,
                        cardset=cardset,
                        position=curr_pos,
                        innings=int(float(row[8])),
                        range=d.range_right_field(int(row[19]), season_pct),
                        error='69',
                        arm=row[22]
                    )
                    dupe = Position.delete().where(
                        (Position.player == player) & (Position.cardset == cardset) & (Position.position == curr_pos)
                    ).execute()
                    this_pos.save()

                # No player match
                else:
                    logging.error(f'Could not match bbref id {row[26]}')
                    print(f'Could not match bbref id {row[26]}')

        with open(f'{input_path}defense-of.csv', 'r') as file:
            reader = csv.reader(file)

            for row in reader:
                player = Player.get_or_none(Player.br_id == row[26])
                all_of = Position.select().where(
                    (Position.player == player) & (Position.cardset == cardset) & (Position.position.contains("F"))
                )
                all_arms = [int(x.arm) for x in all_of]
                if player and row[25] != '' and row[18] != '':
                    # Build Position object and save
                    this_pos = Position(
                        player=player,
                        cardset=cardset,
                        position='OF',
                        innings=int(float(row[8])),
                        range=69,
                        error=d.error_outfield(int(row[12]), int(row[9]), season_pct),
                        arm=d.arm_outfield(all_arms)
                    )
                    dupe = Position.delete().where(
                        (Position.player == player) & (Position.cardset == cardset) & (Position.position == 'OF')
                    ).execute()
                    this_pos.save()

                # No player match
                else:
                    logging.error(f'Could not match bbref id {row[26]}')
                    print(f'Could not match bbref id {row[26]}')

if __name__ == '__main__':
    asyncio.run(main(sys.argv[1:]))
