from random_word import RandomWords
import random

#pip3 install random-words
r = RandomWords()

all_heroes = ['Ana', 'Ashe', 'Baptiste', 'Bastion', 'Brigitte', 'DIVA', 'Doomfist', 'Echo', 'Genji', 'Hanzo', 'Junkrat', 'Lucio',
 'McCree', 'Mei', 'Mercy', 'Moira', 'Orisa' , 'Pharah', 'Reaper' ,'Reinhardt', 'Roadhog', 'Sigma', 'Soldier', 'Sombra', 'Symmetra', 'Torbjorn', 'Tracer', 'Widowmaker',
 'Winston', 'Hammond', 'Zarya', 'Zenyatta']

all_tanks = [5, 16, 19, 20, 21, 28, 29, 30]

all_supports = [0, 2, 4, 11, 14, 15, 31]

all_damage = [1, 3, 6, 7, 8, 9, 10, 12, 13, 17, 18, 22, 23, 24, 25, 26, 27]

# order is tanks 0, damage 1, support 2

brawl_comp = [[19, 30], [12, 18, 22], [15, 11, 4]]

dive_comp = [[5, 28, 29], [6, 7, 8, 17, 23, 26], [0, 11, 14, 31]]

bunker_comp = [[16, 20, 21, 19], [1, 3, 9, 10, 22, 24, 25, 27], [2, 14, 15]]

class Hero:

    def __init__(self, id_number, role_type, play_style, map_user, map_controller, support_out, NV_power, V_power, Vpower_CAP, NVpower_CAP, fun, abilities, ultimate):
        self.id_number = id_number
        self.name = all_heroes[id_number]
        self.role_type = role_type #0 is tank, 1 is dps and 2 is support
        self.play_style = play_style #0 is dive, 1 is brawl, 2 is bunker
        self.map_user = map_user #1-100 based on if they need positioning or healthpacks
        self.map_controller = map_controller #1-100 based on how well they control positioning
        self.support_out = support_out #1-100 based on amount of support (healing + utility)
        self.NV_power = NV_power #Non-visible power, based on position control and tanking ability | 1-100
        self.V_power = V_power #Visible power, based on damage output
        self.Vpower_CAP = Vpower_CAP
        self.NVpower_CAP = NVpower_CAP
        self.Support_X_Vpower = Vpower_CAP / V_power
        self.Support_X_NVpower = NVpower_CAP / NV_power
        self.fun = fun
        self.abilities = abilities
        self.ultimate = ultimate[1]
        self.ultimateType = ultimate[0] # either 0 for used on teammates, or 1 for enemies, or 2 for CC

class Player:

    def __init__(self, rank_start, rank_end, role_variable, player_id):
        self.name = "BigGamer" + str(random.randint(10,500))
        self.rank = random.randint(rank_start, rank_end)
        self.player_id = player_id
        player_average = rank_start + rank_end / 2
        # making sure 2-2-2 is enforced
        self.role_variable = role_variable
        self.mainID = None
        if role_variable == 0:
            self.mainID = random.choice(all_tanks)
        if role_variable == 1:
            self.mainID = random.choice(all_supports)
        if role_variable == 2:
            self.mainID = random.choice(all_damage)
        self.swap_willingness = random.randint(1,100)
        self.char_being_played = self.mainID
        self.last_played = self.mainID
        self.current_value = 1
        self.deaths = 0
        self.eliminations = 0
        self.heroes_played = {self.mainID: {self.mainID: 1, 'value': 1}}
        self.fun_had = 100
        self.personality_type = str(random.choices(
            [1,2,3,4,5],
            weights = [0.1, 0.2, 0.3, ( player_average / 7000), (player_average / 7000)],
            k = 1
        )[0]) # 1-5. with 1 being the most hostile, and 5 being the best teammate you can get
        self.frustration = (5 - int(self.personality_type)) * random.randint(1,8)

    def swapHero(self, new_hero):
        self.last_played = self.char_being_played
        self.char_being_played = new_hero
        if new_hero in self.heroes_played:
            self.heroes_played[new_hero][new_hero] += 1
            self.heroes_played[new_hero]['value'] = self.heroes_played[new_hero]['value'] + self.current_value
        else:
            self.heroes_played[new_hero] = {new_hero : 1, 'value' : self.current_value}
        self.current_value = 0
        print(self.name + " has swapped to " + all_heroes[self.char_being_played])

    def addValue(self):
        if self.char_being_played in self.heroes_played:
            self.heroes_played[self.char_being_played]['value'] += self.current_value
            self.current_value = 0
        else:
            self.heroes_played[self.char_being_played] = {current_hero : 1, 'value' : self.current_value}
            self.current_value = 0

# id    role type   play style   map user    map controller    support out     Non vis power   vis power   vis cap   nonvis cap   fun  abilities  ultimate
# [1 ]  {  2   }   [    3     ]  [  4   ]   [     5       ]    [    6    ]     {    7      }   [    8  ]   [ 9   ]   [   10   ]  [11]  [  12   ]  [ 13   ]

Ana = Hero(0, 2, 2, 80, 15, 85, 5, 5, 10, 15, 65, ['Sleep Dart', 'Biotic Grenade', 'Biotic Rifle'], [0,['Nanoboost', 'Biotic Rifle', 'Biotic Grenade']])
Ashe = Hero(1, 1, 2, 60, 20, 0, 15, 90, 130, 15, 80, ['Dynamite', 'Coach Gun'], [1,['Bob']])
Baptiste = Hero(2, 2, 2, 5, 10, 95, 5, 80, 85, 15, 60, ['Biotic Launcher'], [0,['Amplification Matrix']])
Bastion = Hero(3, 1, 2, 70, 75, 5, 25, 60, 90, 35, 60, ['Sentry Mode', 'Recon Mode'], [1,['Tank Mode']])
Brigitte = Hero(4, 2, 1, 20, 75, 80, 25, 35, 40, 35, 10, ['Flail', 'Shield Bash', 'Whip'], [0,['Inspire', 'Rally', 'Repair Throw']])
DIVA = Hero(5, 0, 0, 5, 80, 0, 40, 30, 35, 50, 40, ['Rockets', 'Fusion Cannons', 'Self-Destruct'], [0,['Defense Matrix']])
Doomfist = Hero(6, 1, 0, 90, 20, 0, 25, 65, 75, 30, 55, ['Slam', 'Upper Cut', 'Punch'], [1,['Meteor Strike']])
Echo = Hero(7, 1, 0, 30, 70, 0, 15, 95, 180, 25, 90, ['Tri-Shot', 'Sticky Bombs', 'Focusing Beam'], [1,['Duplicated Hero']])
Genji = Hero(8, 1, 0, 50, 10, 0, 10, 70, 90, 15, 90, ['Shuriken', 'Deflect'], [1,['Dragonblade']])
Hanzo = Hero(9, 1, 2, 30, 40, 0, 15, 90, 140, 25, 85, ['Storm Bow', 'Storm Arrow'], [1,['Dragonstrike']])
Junkrat = Hero(10, 1, 2, 30, 25, 0, 15, 50, 70, 20, 80, ['Frag Launcher', 'Mine', 'Trap'], [1,['Riptire']])
Lucio = Hero(11, 2, 0, 40, 5, 40, 5, 10, 10, 25, 80, ['Sonic Amplifier', 'Boop'], [0,['Crossfade', 'Sound Barrier']])
McCree = Hero(12, 1, 1, 70, 70, 0, 25, 80, 110, 30, 80, ['Revolver', 'Fan the Hammer'], [2,['Flash']])
Mei = Hero(13, 1, 1, 30, 60, 0, 25, 80, 90, 35, 65, ['Ice-cicle', 'Freeze'], [2,['Blizzard', 'Freeze']])
Mercy = Hero(14, 2, 0, 5, 10, 90, 5, 5, 10, 30, 80, ['Blaster'], [0,['Healing Beam', 'Resurrection']])
Moira = Hero(15, 2, 1, 5, 40, 75, 5, 20, 25, 15, 40, ['Biotic Grasp', 'Biotic Orb', 'Coalescence'], [0,['Coalescence', 'Biotic Orb', 'Biotic Grasp']])
Orisa = Hero(16, 0, 2, 40, 65, 0, 55, 30, 35, 75, 5, ['Fusion Driver', 'Pull'], [0,['Supercharger', 'Barrier']])
Pharah = Hero(17, 1, 0, 20, 10, 0, 10, 40, 90, 40, 70, ['Rocket Launcher'], [1,['Barrage']])
Reaper = Hero(18, 1, 1, 50, 10, 0, 20, 60, 65, 25, 75, ['Shotguns'], [1,['Death Blossom']])
Reinhardt = Hero(19, 0, 1, 20, 35, 0, 55, 30, 50, 65, 30, ['Hammer', 'Firestrike', 'Charge'], [2,['Earthshatter']])
Roadhog = Hero(20, 0, 2, 20, 70, 0, 45, 65, 80, 65, 80, ['Scrap Gun', 'Hook'], [1,['Whole Hog']])
Sigma = Hero(21, 0, 2, 10, 40, 0, 65, 60, 80, 85, 70, ['Hyperspheres', 'Rock', 'Gravitic Flux'], [2,['Rock']])
Soldier = Hero(22, 1, 1, 35, 20, 10, 20, 65, 80, 25, 75, ['Pulse Rifle', 'Helix Missile', 'Tactical Visor'], [0,['Biotic Field']])
Sombra = Hero(23, 1, 0, 30, 90, 15, 25, 60, 70, 20, 60, ['Machine Pistol'], [2,['EMP', 'Hack']])
Symmetra = Hero(24, 1, 2, 20, 50, 0, 5, 55, 70, 20, 40, ['Photon Beam', 'Sentry Turret'], [0,['Photon Barrier']])
Torbjorn = Hero(25, 1, 2, 10, 40, 0, 15, 65, 75, 25, 75, ['Rivet Gun', 'Hammer', 'Turret'], [1,['Molten Core']])
Tracer = Hero(26, 1, 0, 80, 35, 0, 35, 95, 110, 35, 85, ['Pulse Pistols'], [1,['Pulse Bomb']])
Widowmaker = Hero(27, 1, 2, 80, 40, 0, 5, 40, 80, 15, 75, ['Sniper'], [1,['Venom Mine']])
Winston = Hero(28, 0, 0, 50, 35, 0, 55, 20, 35, 65, 40, ['Tesla Cannon', 'Jump Pack'], [1,['Primal Rage']])
Hammond = Hero(29, 0, 0, 80, 90, 0, 90, 65, 70, 95, 75, ['Quad Cannons', 'Roll', 'Piledriver'], [1,['Mines']])
Zarya = Hero(30, 0, 1, 10, 20, 0, 45, 65, 75, 55, 70, ['Particle Cannon'], [2,['Graviton Surge']])
Zenyatta = Hero(31, 2, 0, 90, 5, 55, 5, 85, 100, 15, 70, ['Orbs of Destruction'], [0,['Orb of Harmony', 'Transcendence']])

# order is tanks 0, damage 1, support 2
meta_comp = [[31,29], [26, 7, 1, 9], [14, 4, 2]]

# These are all lists of things for players to say in and after the games
player_names = ['TickleTrain', 'MercyMain', 'BedWetter11', 'MoiraHeadshotGod', 'BigGamer', 'HarambeFanatic44', 'JeffLuvr', 'GMEBuyer', 'Teltu', 'BradyIsCool', 'Alex', 'BaseballLover64',
'TomBradyFan', 'GodGamer', 'CoolKid141', 'OboePlayer91', 'Alteffour', 'Gnome', 'GenjiOneTrick', 'Hannibal', 'GhanaFuneral', 'RageWolf55', 'FallenWarfare', 'TwistedTea', 'Throwing', 'Jessica', 'Feester', 'RyuKen', 'BigPete', 'HighGround']

choosing_hero_sentences_angriest = ['bro, i f****** hate this hero', 'this s*** is garbage', 'I hate this dogs*** meta', 'F*** THIS F****** GAME', 'im about to f****** throw']
choosing_hero_sentences_upset = ["i guess ill play this guy", 'am i really stuck on this hero', 'i shouldnt have queued']
not_playing_synergy = ['i dont really like this comp, im just gonna go ', 'not a fan of this comp, im gonna play ', 'dont feel like playing that comp, imma play ']
not_playing_synergy_angry = ['bro f*** that dumba** comp, im playin ', 'nah that comp is dumb as f***, im goin ', 'F*** THAT S*** IM GOING ']
choosing_hero_random = ['whats up guys?', 'wuz goo', 'whats crackin', 'yo', 'Yo', 'Hey']

unhappy_with_supports = ['can out supports swap?', 'yo, supports. you there?', 'hey supports, can one of you swap?']
angry_with_supports = ['our supports are dogs***', 'WHY THE F*** CANT THE SUPPORTS HEAL ME????', 'our supports are absolutely braindead', 'zzz supports WTF ARE YOU DOING???', 'support diff']

unhappy_with_tanks = ['can our tanks swap?', 'yo, tanks. you there?', 'tanks, can one of you swap?']
angry_with_tanks = ['our tanks are dogs***', 'TANKS PRESS W KEY', 'our tanks are F****** braindead', 'gg. tanks are dogs***']

unhappy_with_damage = ['can our dps swap?', 'yo, dps. you there?', 'dps, can one of you swap?']
angry_with_damage = ['our dps are dogs***', 'DPS TURN ON YOUR MONITORS', 'our dps are F****** braindead', 'pretty sure our dps are throwing']

end_of_game_angry = ['was i the only one playing?', 'our team actually hard threw', 'F*** THIS GAME', 'serious question. was out team throwing?', 'pretty sure the rest of my team didnt have their monitors on', 'wish i had 5 avoid slots']
end_of_game = ['I feel very, very small... please hold me...', "I'm trying to be a nicer person. It's hard, but I'm trying, guys.", "I'm wrestling with some insecurity issues in my life but thank you for playing with me.", 'gg' 'GGs', 'good try', 'gg go next']

# Create a range for the ranks of the players
rank_start = int(input("Enter rank range start: "))
rank_end = int(input("Enter rank range end: "))
games = int(input('Enter amount of matches to play: '))

# Both team lists
red_team = []
blue_team = []

# Generate the players, and make it 2-2-2
for team_used in [red_team, blue_team]:
    for player_used in range(6):
        role_type = None
        if player_used == 0 or player_used == 1:
            role_type = 0
        elif player_used == 2 or player_used == 3:
            role_type = 1
        else:
            role_type = 2
        team_used.append(Player(rank_start, rank_end, role_type, (str([red_team, blue_team].index(team_used)) + str(player_used))))

for x in red_team:
    print(x.name + "'s main is " + all_heroes[x.mainID] + ", they're on red team, and their personality type is: " + x.personality_type)

for x in blue_team:
    print(x.name + "'s main is " + all_heroes[x.mainID] + ", they're on blue team, and their personality type is: " + x.personality_type)

# ---------------------- First game ---------------------------------

# First hero pick

#setting global team vars to keep track of
red_team_support = 0
red_team_damage = 0
red_team_tanking = 0
red_team_damage_amplified = 0
red_team_tanking_amplified = 0
red_team_team_swap_num = 0

blue_team_support = 0
blue_team_damage = 0
blue_team_tanking = 0
blue_team_damage_amplified = 0
blue_team_tanking_amplified = 0
blue_team_team_swap_num = 0

num_iter = -1

for current_team in [red_team, blue_team]:
    num_iter += 1
    sr_average = (rank_start + rank_end) / 2
    swap_said = False
    comp_synergy = {}
    meta_synergy = []
    used_char_list = []
    synergy_use_list = None

    person_to_suggest = None
    # these numbers are for flat support, visible power and non visible

    if num_iter == 0:
        team_support = red_team_support
        team_damage = red_team_damage
        team_tanking = red_team_tanking
        team_damage_amplified = red_team_damage_amplified
        team_tanking_amplified = red_team_tanking_amplified
        team_swap_num = red_team_team_swap_num
    else:
        team_support = blue_team_support
        team_damage = blue_team_damage
        team_tanking = blue_team_tanking
        team_damage_amplified = blue_team_damage_amplified
        team_tanking_amplified = blue_team_tanking_amplified
        team_swap_num = blue_team_team_swap_num

    # Creating lists to see how close the teams are to synergy or meta comp
    for i in current_team:
        player_style = eval(all_heroes[i.mainID]).play_style
        if player_style in comp_synergy:
            comp_synergy[player_style] += 1
        else:
            comp_synergy[player_style] = 1

        if player_style in meta_comp:
            meta_synergy += player_style

    comp_synergy_key = max(comp_synergy, key=comp_synergy.get)

    # Check if their team is closer to meta comp, or a certain synergy

    if len(meta_synergy) > comp_synergy[comp_synergy_key]:
        team_swap_num = 3
        synergy_use_list = meta_comp.copy()
        #this means meta comp
    else:
        team_swap_num = comp_synergy_key
        if comp_synergy_key == 0:
            synergy_use_list = [dive_comp[0].copy(), dive_comp[1].copy(), dive_comp[2].copy()]
        elif comp_synergy_key == 1:
            synergy_use_list = [brawl_comp[0].copy(), brawl_comp[1].copy(), brawl_comp[2].copy()]
        else:
            synergy_use_list = [bunker_comp[0].copy(), bunker_comp[1].copy(), bunker_comp[2].copy()]
        #this will swap to the number. ex 0 means dive 1 is brawl and 2 is bunker

    chars_picked = []
    for x in current_team:

        # if elect to swap to a comp with synergy
        #if the synergy comp is dive
        type_string = None
        if team_swap_num == 0:
            type_string = 'dive_comp'
        elif team_swap_num == 1:
            type_string = 'brawl_comp'
        elif team_swap_num == 2:
            type_string = 'bunker_comp'
        else:
            type_string = 'meta_comp'

        if swap_said == False:
            print(x.name + ": Lets go " + type_string[0 : (len(type_string) - 5)] + ' ' + type_string[(len(type_string) - 4) : (len(type_string))])
            person_to_suggest = x.name
            swap_said = True
        # 0 in role is tank
        # synergy order is tank 0, damage 1, support 2
        swap_var = None
        hero_type_temp = None
        if x.role_variable == 0:
            hero_type_temp = eval(type_string + '[0]')
        elif x.role_variable == 1:
            hero_type_temp = eval(type_string + '[1]')
        else:
            hero_type_temp = eval(type_string + '[2]')
        compar_chars = []
        synergy_delete = None
        for f in hero_type_temp:
            if f in synergy_use_list[x.role_variable]:
                compar_chars.append(f)

        random_sr_int = random.randint(200, 350)

        pick_list = []
        options_pick_list = []

        for l in range(len(synergy_use_list[x.role_variable])):

            loop_tank = eval(all_heroes[synergy_use_list[x.role_variable][l]])

            # order is tank 0, damage 1, support 2
            #create chances the hero will get picked based on the team's support, damage, rank and how fun the hero is
            if x.role_variable == 0: #tank
                chance_primary_pick = (loop_tank.NVpower_CAP * (max(1, (team_support/50)))) + loop_tank.NV_power #Primary is tanking / map control ability
                chance_secondary_pick = (loop_tank.Vpower_CAP * (max(1, ((team_damage + team_tanking)/190)))) + loop_tank.V_power #secondary is damage
                chance_fun_pick = loop_tank.fun * ((5350 - sr_average) / 1000) #fun
            elif x.role_variable == 1: #damage
                chance_primary_pick = (loop_tank.V_power * max(1, (team_damage/50))) + loop_tank.NV_power #Primary is damage and cc
                chance_secondary_pick = (loop_tank.V_power * max(1, ((team_support + loop_tank.Vpower_CAP)/90))) #secondary is damage with support
                chance_fun_pick = loop_tank.fun * ((5650 - sr_average) / 1000) #fun
            else:
                chance_primary_pick = (loop_tank.V_power * max(1, (team_tanking_amplified/50)) + loop_tank.NV_power) #Primary healing out
                chance_secondary_pick = (loop_tank.V_power * max(1, ((team_damage_amplified + loop_tank.Vpower_CAP)/70))) #secondary is utility
                chance_fun_pick = loop_tank.fun * ((5450 - sr_average) / 1000) #fun

            pick_list.append(chance_fun_pick + chance_primary_pick + chance_secondary_pick)
            options_pick_list.append(loop_tank.id_number)

                #add some past picks here

        high_sr_var = random.choices(
            options_pick_list,
            weights = pick_list,
            k=1
        )[0]

        add_random_char = random.choices(
            [1,2,3],
            weights=[9000 + (sr_average * 3), max(1000, ((4600 - sr_average) * (6 - int(x.personality_type)))), (4600 - sr_average) * (6 - int(x.personality_type))],
            k=1

        )[0]
        first_check = False
        if add_random_char == 2:
            def random_char_func():
                global high_sr_var

                first_check = True
                if x.role_variable == 0:
                    high_sr_var = eval(all_heroes[random.choice(all_tanks)]).id_number
                elif x.role_variable == 1:
                    high_sr_var = eval(all_heroes[random.choice(all_damage)]).id_number
                else:
                    high_sr_var = eval(all_heroes[random.choice(all_supports)]).id_number
                if high_sr_var in used_char_list:
                    random_char_func()
                elif high_sr_var not in synergy_use_list[x.role_variable]:
                    swapping_quote = random.choices(
                        [1,2],
                        weights = [350, ((6 - int(x.personality_type)) * x.frustration)],
                        k=1

                    )[0]
                    if swapping_quote == 1:
                        print(x.name + ': ' + random.choice(not_playing_synergy) + all_heroes[high_sr_var])
                    else:
                        print(x.name + ': ' + random.choice(not_playing_synergy_angry) + all_heroes[high_sr_var])

            if first_check == False:
                random_char_func()
        high_sr_var = eval(all_heroes[high_sr_var])
        used_char_list.append(high_sr_var.id_number)
        team_support += high_sr_var.support_out
        team_damage += high_sr_var.V_power
        team_tanking += high_sr_var.NV_power
        team_damage_amplified += high_sr_var.Vpower_CAP
        team_tanking_amplified += (high_sr_var.NVpower_CAP + high_sr_var.map_controller)
        if num_iter == 0:
            red_team_support = team_support
            red_team_damage = team_damage
            red_team_tanking = team_tanking
            red_team_damage_amplified = team_damage_amplified
            red_team_tanking_amplified = team_tanking_amplified
            red_team_team_swap_num = team_swap_num
        else:
            blue_team_support = team_support
            blue_team_damage = team_damage
            blue_team_tanking = team_tanking
            blue_team_damage_amplified = team_damage_amplified
            blue_team_tanking_amplified = team_tanking_amplified
            blue_team_team_swap_num = team_swap_num
        x.swapHero(high_sr_var.id_number)
        if high_sr_var.id_number in synergy_use_list[x.role_variable]:
            synergy_use_list[x.role_variable].remove(high_sr_var.id_number)

           # eval(compar_chars[f])

#----------------------------------------------------------------------------------------
#------------------ Function for swapping after fights-----------------------------------
#----------------------------------------------------------------------------------------

def losing_team_swap(team, team_id):
    if team_id == 'red':
        global red_team_support
        global red_team_damage
        global red_team_tanking
        global red_team_damage_amplified
        global red_team_tanking_amplified
        global red_team_team_swap_num
    elif team_id == 'blue':
        global blue_team_support
        global blue_team_damage
        global blue_team_tanking
        global blue_team_damage_amplified
        global blue_team_tanking_amplified
        global blue_team_team_swap_num

    for current_team in range(1):
        sr_average = (rank_start + rank_end) / 2
        swap_said = False
        comp_synergy = {}
        meta_synergy = []
        used_char_list = []
        synergy_use_list = None

        person_to_suggest = None
        # these numbers are for flat support, visible power and non visible

        if team_id == 'red':
            team_support = red_team_support
            team_damage = red_team_damage
            team_tanking = red_team_tanking
            team_damage_amplified = red_team_damage_amplified
            team_tanking_amplified = red_team_tanking_amplified
            team_swap_num = red_team_team_swap_num
        elif team_id == 'blue':
            team_support = blue_team_support
            team_damage = blue_team_damage
            team_tanking = blue_team_tanking
            team_damage_amplified = blue_team_damage_amplified
            team_tanking_amplified = blue_team_tanking_amplified
            team_swap_num = blue_team_team_swap_num

        meta_chance = 0
        bunker_chance = 0
        brawl_chance = 0
        dive_chance = 0
        for i in range(len(team)):
            #if tank
            if team[i].role_variable == 0:
                #check for meta comp
                for l in range(len(meta_comp[0])):
                    #check if initial dict key matches
                    if meta_comp[0][l] in team[i].heroes_played:
                        #then subtract valu
                        meta_chance += (team[i].heroes_played[meta_comp[0][l]]['value'] - team[i].heroes_played[meta_comp[0][l]][meta_comp[0][l]])
                #check for buner
                for l in range(len(bunker_comp[0])):
                    if bunker_comp[0][l] in team[i].heroes_played:
                        bunker_chance += (team[i].heroes_played[bunker_comp[0][l]]['value'] - team[i].heroes_played[bunker_comp[0][l]][bunker_comp[0][l]])
                for l in range(len(brawl_comp[0])):
                    if brawl_comp[0][l] in team[i].heroes_played:
                        brawl_chance += (team[i].heroes_played[brawl_comp[0][l]]['value'] - team[i].heroes_played[brawl_comp[0][l]][brawl_comp[0][l]])
                for l in range(len(dive_comp[0])):
                    if dive_comp[0][l] in team[i].heroes_played:
                        dive_chance += (team[i].heroes_played[dive_comp[0][l]]['value'] - team[i].heroes_played[dive_comp[0][l]][dive_comp[0][l]])
            #if support
            if team[i].role_variable == 1:
                #check for meta comp
                for l in range(len(meta_comp[2])):
                    #check if initial dict key matches
                    if meta_comp[2][l] in team[i].heroes_played:
                        #then subtract valu
                        meta_chance += (team[i].heroes_played[meta_comp[2][l]]['value'] - team[i].heroes_played[meta_comp[2][l]][meta_comp[2][l]])
                #check for buner
                for l in range(len(bunker_comp[2])):
                    if bunker_comp[2][l] in team[i].heroes_played:
                        bunker_chance += (team[i].heroes_played[bunker_comp[2][l]]['value'] - team[i].heroes_played[bunker_comp[2][l]][bunker_comp[2][l]])
                for l in range(len(brawl_comp[2])):
                    if brawl_comp[2][l] in team[i].heroes_played:
                        brawl_chance += (team[i].heroes_played[brawl_comp[2][l]]['value'] - team[i].heroes_played[brawl_comp[2][l]][brawl_comp[2][l]])
                for l in range(len(dive_comp[2])):
                    if dive_comp[2][l] in team[i].heroes_played:
                        dive_chance += (team[i].heroes_played[dive_comp[2][l]]['value'] - team[i].heroes_played[dive_comp[2][l]][dive_comp[2][l]])
            if team[i].role_variable == 2:
                #check for meta comp
                for l in range(len(meta_comp[1])):
                    #check if initial dict key matches
                    if meta_comp[1][l] in team[i].heroes_played:
                        #then subtract valu
                        meta_chance += (team[i].heroes_played[meta_comp[1][l]]['value'] - team[i].heroes_played[meta_comp[1][l]][meta_comp[1][l]])
                #check for buner
                for l in range(len(bunker_comp[1])):
                    if bunker_comp[1][l] in team[i].heroes_played:
                        bunker_chance += (team[i].heroes_played[bunker_comp[1][l]]['value'] - team[i].heroes_played[bunker_comp[1][l]][bunker_comp[1][l]])
                for l in range(len(brawl_comp[1])):
                    if brawl_comp[1][l] in team[i].heroes_played:
                        brawl_chance += (team[i].heroes_played[brawl_comp[1][l]]['value'] - team[i].heroes_played[brawl_comp[1][l]][brawl_comp[1][l]])
                for l in range(len(dive_comp[1])):
                    if dive_comp[1][l] in team[i].heroes_played:
                        dive_chance += (team[i].heroes_played[dive_comp[1][l]]['value'] - team[i].heroes_played[dive_comp[1][l]][dive_comp[1][l]])

        print('meta chance: ' + str(meta_chance) + ' dive chance: ' + str(dive_chance) + ' brawl chance: ' + str(brawl_chance) + ' bunker chance: ' + str(bunker_chance))

        # Creating lists to see how close the teams are to synergy or meta comp
        for i in team:
            player_style = eval(all_heroes[i.mainID]).play_style
            if player_style in comp_synergy:
                comp_synergy[player_style] += 1
            else:
                comp_synergy[player_style] = 1

            if player_style in meta_comp:
                meta_synergy += player_style

        comp_synergy_key = max(comp_synergy, key=comp_synergy.get)

        # Check if their team is closer to meta comp, or a certain synergy

        #adding some randomness and main priority for comp  synergy swaps
        added_weighting = random.choices(
            [1,2,3,4,5],
            weights= [10, meta_chance, dive_chance, brawl_chance, bunker_chance],
            k=1

        )[0]

        meta_count = len(meta_synergy)
        if added_weighting == 2:
            meta_count += meta_chance
            team_swap_num = 3
            synergy_use_list = meta_comp.copy()
        elif added_weighting == 3 or added_weighting == 4 or added_weighting == 5:
            # 3 is dive, 4 is brawl, and 5 is bunker
            if added_weighting == 3:
                synergy_use_list = [dive_comp[0].copy(), dive_comp[1].copy(), dive_comp[2].copy()]
                team_swap_num = 0
            elif added_weighting == 4:
                synergy_use_list = [brawl_comp[0].copy(), brawl_comp[1].copy(), brawl_comp[2].copy()]
                team_swap_num = 1
            else:
                synergy_use_list = [bunker_comp[0].copy(), bunker_comp[1].copy(), bunker_comp[2].copy()]
                team_swap_num = 2

        elif added_weighting == 1:

            if meta_count > comp_synergy[comp_synergy_key]:
                team_swap_num = 3
                synergy_use_list = meta_comp.copy()
                #this means meta comp
            else:
                team_swap_num = comp_synergy_key
                if comp_synergy_key == 0:
                    synergy_use_list = [dive_comp[0].copy(), dive_comp[1].copy(), dive_comp[2].copy()]
                elif comp_synergy_key == 1:
                    synergy_use_list = [brawl_comp[0].copy(), brawl_comp[1].copy(), brawl_comp[2].copy()]
                else:
                    synergy_use_list = [bunker_comp[0].copy(), bunker_comp[1].copy(), bunker_comp[2].copy()]
                #this will swap to the number. ex 0 means dive 1 is brawl and 2 is bunker

        chars_picked = []
        for x in team:

            # if elect to swap to a comp with synergy
            #if the synergy comp is dive
            type_string = None
            if team_swap_num == 0:
                type_string = 'dive_comp'
            elif team_swap_num == 1:
                type_string = 'brawl_comp'
            elif team_swap_num == 2:
                type_string = 'bunker_comp'
            else:
                type_string = 'meta_comp'

            if swap_said == False:
                print(x.name + ": Lets swap to " + type_string[0 : (len(type_string) - 5)] + ' ' + type_string[(len(type_string) - 4) : (len(type_string))])
                person_to_suggest = x.name
                swap_said = True
            # 0 in role is tank
            # synergy order is tank 0, damage 1, support 2
            swap_var = None
            hero_type_temp = None
            if x.role_variable == 0:
                hero_type_temp = eval(type_string + '[0]')
            elif x.role_variable == 1:
                hero_type_temp = eval(type_string + '[1]')
            else:
                hero_type_temp = eval(type_string + '[2]')
            compar_chars = []
            synergy_delete = None
            for f in hero_type_temp:
                if f in synergy_use_list[x.role_variable]:
                    compar_chars.append(f)

            random_sr_int = random.randint(200, 350)

            pick_list = []
            options_pick_list = []

            for l in range(len(synergy_use_list[x.role_variable])):

                loop_tank = eval(all_heroes[synergy_use_list[x.role_variable][l]])

                # order is tank 0, damage 1, support 2
                #create chances the hero will get picked based on the team's support, damage, rank and how fun the hero is
                if x.role_variable == 0: #tank
                    chance_primary_pick = (loop_tank.NVpower_CAP * (max(1, (team_support/50)))) + loop_tank.NV_power #Primary is tanking / map control ability
                    chance_secondary_pick = (loop_tank.Vpower_CAP * (max(1, ((team_damage + team_tanking)/190)))) + loop_tank.V_power #secondary is damage
                    chance_fun_pick = loop_tank.fun * ((5350 - sr_average) / 1000) #fun
                elif x.role_variable == 1: #damage
                    chance_primary_pick = (loop_tank.V_power * max(1, (team_damage/50))) + loop_tank.NV_power #Primary is damage and cc
                    chance_secondary_pick = (loop_tank.V_power * max(1, ((team_support + loop_tank.Vpower_CAP)/90))) #secondary is damage with support
                    chance_fun_pick = loop_tank.fun * ((5650 - sr_average) / 1000) #fun
                else:
                    chance_primary_pick = (loop_tank.V_power * max(1, (team_tanking_amplified/50)) + loop_tank.NV_power) #Primary healing out
                    chance_secondary_pick = (loop_tank.V_power * max(1, ((team_damage_amplified + loop_tank.Vpower_CAP)/70))) #secondary is utility
                    chance_fun_pick = loop_tank.fun * ((5450 - sr_average) / 1000) #fun

                pick_list.append(chance_fun_pick + chance_primary_pick + chance_secondary_pick)
                options_pick_list.append(loop_tank.id_number)

                    #add some past picks here

            high_sr_var = random.choices(
                options_pick_list,
                weights = pick_list,
                k=1
            )[0]

            add_random_char = random.choices(
                [1,2,3],
                weights=[9000 + (sr_average * 3), max(1000, ((4600 - sr_average) * (6 - int(x.personality_type)))), (4600 - sr_average) * (6 - int(x.personality_type))],
                k=1

            )[0]
            first_check = False
            if add_random_char == 2:
                def random_char_func():
                    global high_sr_var

                    first_check = True
                    if x.role_variable == 0:
                        high_sr_var = eval(all_heroes[random.choice(all_tanks)]).id_number
                    elif x.role_variable == 1:
                        high_sr_var = eval(all_heroes[random.choice(all_damage)]).id_number
                    else:
                        high_sr_var = eval(all_heroes[random.choice(all_supports)]).id_number
                    if high_sr_var in used_char_list:
                        random_char_func()
                    elif high_sr_var not in synergy_use_list[x.role_variable]:
                        swapping_quote = random.choices(
                            [1,2],
                            weights = [350, ((6 - int(x.personality_type)) * x.frustration)],
                            k=1

                        )[0]
                        if swapping_quote == 1:
                            print(x.name + ': ' + random.choice(not_playing_synergy) + all_heroes[high_sr_var])
                        else:
                            print(x.name + ': ' + random.choice(not_playing_synergy_angry) + all_heroes[high_sr_var])

                if first_check == False:
                    random_char_func()
            high_sr_var = eval(all_heroes[high_sr_var])
            used_char_list.append(high_sr_var.id_number)
            team_support += high_sr_var.support_out
            team_damage += high_sr_var.V_power
            team_tanking += high_sr_var.NV_power
            team_damage_amplified += high_sr_var.Vpower_CAP
            team_tanking_amplified += (high_sr_var.NVpower_CAP + high_sr_var.map_controller)
            if team_id == 'red':
                red_team_support = team_support
                red_team_damage = team_damage
                red_team_tanking = team_tanking
                red_team_damage_amplified = team_damage_amplified
                red_team_tanking_amplified = team_tanking_amplified
                red_team_team_swap_num = team_swap_num
            elif team_id == 'blue':
                blue_team_support = team_support
                blue_team_damage = team_damage
                blue_team_tanking = team_tanking
                blue_team_damage_amplified = team_damage_amplified
                blue_team_tanking_amplified = team_tanking_amplified
                blue_team_team_swap_num = team_swap_num
            x.swapHero(high_sr_var.id_number)
            if high_sr_var.id_number in synergy_use_list[x.role_variable]:
                synergy_use_list[x.role_variable].remove(high_sr_var.id_number)
#---------------------------- End function for later swapping--------------------------------

#---------------------------- fighting ------------------------------------------------------

print('red team support is: ' + str(red_team_support))
print('blue team support is: ' + str(blue_team_support))

#During round
#this will swap to the number. ex 0 means dive 1 is brawl and 2 is bunker, 3 is meta

red_games_won = 0
blue_games_won = 0
games_tied = 0

for x in range(games):
    red_match_total = 0
    blue_match_total = 0
    for q in range(8):

        def fun_calculation(team):
            overall_return = 0
            if team == 'red':
                for i in red_team:
                    overall_return += i.fun_had * (1 + int(i.personality_type))
            elif team == 'blue':
                for i in blue_team:
                    overall_return += i.fun_had * (1 + int(i.personality_type))
            print(overall_return)
            return overall_return

        overall_red = (red_team_damage * (200 - red_team_support)) + (red_team_damage_amplified * red_team_support) + (red_team_tanking * max(10, (80 - red_team_support))) + (red_team_tanking_amplified * red_team_support) + fun_calculation('red')
        overall_blue = (blue_team_damage * (200 - blue_team_support)) + (blue_team_damage_amplified * blue_team_support) + (blue_team_tanking * max(10, (80 - blue_team_support))) + (blue_team_tanking_amplified * blue_team_support) + fun_calculation('blue')

        advantage = random.choices(
            [1,2],
            weights= [overall_red, overall_blue],
            k=1

        )
        # advantage 1 is red, and 2 is blue

        red_stats = []
        blue_stats = []

        for i in red_team:
            red_char_playing = eval(all_heroes[i.char_being_played])
            red_stats.append([i, (red_char_playing.V_power * (200 - red_team_support)) + (red_char_playing.Vpower_CAP * red_team_support) + (red_char_playing.NV_power * max(1, (80 - red_team_support))) + (red_char_playing.NVpower_CAP * red_team_support) + ((red_char_playing.fun - i.frustration) * 3)])
        for i in blue_team:
            blue_char_playing = eval(all_heroes[i.char_being_played])
            blue_stats.append([i, (blue_char_playing.V_power * (200 - blue_team_support)) + (blue_char_playing.Vpower_CAP * blue_team_support) + (blue_char_playing.NV_power * max(1, (80 - blue_team_support))) + (blue_char_playing.NVpower_CAP * blue_team_support) + ((blue_char_playing.fun - i.frustration) * 3)])

        red_dead = 0
        blue_dead = 0
        living_red_team = red_team.copy()
        living_blue_team = blue_team.copy()
        dead_people = []
        dead_people_ids = []
        temp_red_stats = red_stats.copy()
        temp_blue_stats = blue_stats.copy()
        for w in range(6):

            range_options = random.choice([0,1,2,3,4,5])
            winner_single = random.choices(
                [1,2],
                weights= [red_stats[w][1], blue_stats[w][1]],
                k=1
            )[0]
            loser_id = 0
            # if red wins the fight
            if winner_single == 1:
                loser_var = blue_stats[w][0]
                loser_var.frustration += 2
                loser_var.fun_had += -2
                blue_list = []
                blue_id_list = []
                for o in temp_blue_stats:
                    if o[0] not in dead_people:
                        blue_list.append(o[1])
                        blue_id_list.append(o[0])

                person_killed = random.choices(
                    blue_id_list,
                    weights = blue_list,
                    k=1
                )[0]

                #if the person killed was a tank
                mean_comment = random.choices(
                    [1,2],
                    weights= [700, person_killed.frustration * (5 - int(person_killed.personality_type))],
                    k=1

                )

                #when they die
                for u in temp_blue_stats:
                    if u[0] == person_killed:
                        temp_blue_stats.remove(u)

                dead_people.append(person_killed)
                blue_dead += 1
                random_killer = random.choice(red_team)
                random_killer.addValue()
                random_killer.eliminations += 1
                print(person_killed.name + ' was killed by ' + random_killer.name + "'s " + str(random.choice(eval(all_heroes[random_killer.char_being_played]).abilities)))
                living_blue_team.remove(person_killed)

                if mean_comment == 2:
                    # if person killed was a tank
                    if person_killed.role_variable == 0:
                        if random.choice([1,2]) == 1:
                            random_comment = random.choice(angry_with_supports)
                            for q in blue_team:
                                if blue_team[q].role_variable == 1:
                                    blue_team[q].frustration += 10
                                    blue_team[q].fun_had += -10
                        else:
                            random_comment = random.choice(angry_with_damage)
                            for q in blue_team:
                                if blue_team[q].role_variable == 2:
                                    blue_team[q].frustration += 10
                                    blue_team[q].fun_had += -10
                    # if person killed was a support
                    if person_killed.role_variable == 1:
                        if random.choice([1,2]) == 1:
                            random_comment = random.choice(angry_with_tanks)
                            for q in blue_team:
                                if blue_team[q].role_variable == 0:
                                    blue_team[q].frustration += 10
                                    blue_team[q].fun_had += -10
                        else:
                            random_comment = random.choice(angry_with_damage)
                            for q in blue_team:
                                if blue_team[q].role_variable == 2:
                                    blue_team[q].frustration += 10
                                    blue_team[q].fun_had += -10
                    # if person killed was a dps
                    if person_killed.role_variable == 2:
                        if random.choice([1,2]) == 1:
                            random_comment = random.choice(angry_with_supports)
                            for q in blue_team:
                                if blue_team[q].role_variable == 1:
                                    blue_team[q].frustration += 10
                                    blue_team[q].fun_had += -10
                        else:
                            random_comment = random.choice(angry_with_tanks)
                            for q in blue_team:
                                if blue_team[q].role_variable == 0:
                                    blue_team[q].frustration += 10
                                    blue_team[q].fun_had += -10
                    print(person_killed.name + ': ' + random_comment)
                else:
                    regular_comment = random.choices(
                        [1,2],
                        weights= [20000, (int(person_killed.personality_type) * sr_average)],
                        k=1
                    )
                    if regular_comment == 2:
                        if person_killed.role_variable == 0:

                            if random.choice([1,2]) == 1:
                                random_comment = random.choice(unhappy_with_supports)
                            else:
                                random_comment = random.choice(unhappy_with_damage)

                        elif person_killed.role_variable == 1:

                            if random.choice([1,2]) == 1:
                                random_comment = random.choice(unhappy_with_tanks)
                            else:
                                random_comment = random.choice(unhappy_with_damage)

                        elif person_killed.role_variable == 2:

                            if random.choice([1,2]) == 1:
                                random_comment = random.choice(unhappy_with_tanks)
                            else:
                                random_comment = random.choice(unhappy_with_supports)

                        print(person_killed.name + ': ' + random_comment)

                person_killed.deaths += 1
                person_killed.frustration += 5
                person_killed.fun_had += -5

            elif winner_single == 2:
                loser_var = red_stats[w][0]
                loser_var.frustration += 2
                loser_var.fun_had += -2
                red_list = []
                red_id_list = []
                for o in temp_red_stats:
                    if o[0] not in dead_people:
                        red_list.append(o[1])
                        red_id_list.append(o[0])

                person_killed = random.choices(
                    red_id_list,
                    weights = red_list,
                    k=1
                )[0]

                #if the person killed was a tank
                mean_comment = random.choices(
                    [1,2],
                    weights= [700, person_killed.frustration * (5 - int(person_killed.personality_type))],
                    k=1

                )

                #when they die
                hero_player_killed = eval(all_heroes[person_killed.char_being_played])
                for u in temp_red_stats:
                    if u[0] == person_killed:
                        temp_red_stats.remove(u)
                dead_people.append(person_killed)
                red_dead += 1
                random_killer = random.choice(blue_team)
                random_killer.current_value += 1
                random_killer.addValue()
                living_red_team = red_team.copy()
                random_killer.eliminations += 1
                print(person_killed.name + ' was killed by ' + random_killer.name + "'s " + str(random.choice(eval(all_heroes[random_killer.char_being_played]).abilities)))

                if mean_comment == 2:
                    # if person killed was a tank
                    if person_killed.role_variable == 0:
                        if random.choice([1,2]) == 1:
                            random_comment = random.choice(angry_with_supports)
                            for q in red_team:
                                if red_team[q].role_variable == 1:
                                    red_team[q].frustration += 10
                                    red_team[q].fun_had += -10
                        else:
                            random_comment = random.choice(angry_with_damage)
                            for q in red_team:
                                if red_team[q].role_variable == 2:
                                    red_team[q].frustration += 10
                                    red_team[q].fun_had += -10
                    # if person killed was a support
                    if person_killed.role_variable == 1:
                        if random.choice([1,2]) == 1:
                            random_comment = random.choice(angry_with_tanks)
                            for q in red_team:
                                if red_team[q].role_variable == 0:
                                    red_team[q].frustration += 10
                                    red_team[q].fun_had += -10
                        else:
                            random_comment = random.choice(angry_with_damage)
                            for q in red_team:
                                if red_team[q].role_variable == 2:
                                    red_team[q].frustration += 10
                                    red_team[q].fun_had += -10
                    # if person killed was a dps
                    if person_killed.role_variable == 2:
                        if random.choice([1,2]) == 1:
                            random_comment = random.choice(angry_with_supports)
                            for q in red_team:
                                if red_team[q].role_variable == 1:
                                    red_team[q].frustration += 10
                                    red_team[q].fun_had += -10
                        else:
                            random_comment = random.choice(angry_with_tanks)
                            for q in red_team:
                                if red_team[q].role_variable == 0:
                                    red_team[q].frustration += 10
                                    red_team[q].fun_had += -10
                    print(person_killed.name + ': ' + random_comment)
                else:
                    regular_comment = random.choices(
                        [1,2],
                        weights= [20000, (int(person_killed.personality_type) * sr_average)],
                        k=1
                    )
                    if regular_comment == 2:
                        if person_killed.role_variable == 0:

                            if random.choice([1,2]) == 1:
                                random_comment = random.choice(unhappy_with_supports)
                            else:
                                random_comment = random.choice(unhappy_with_damage)

                        elif person_killed.role_variable == 1:

                            if random.choice([1,2]) == 1:
                                random_comment = random.choice(unhappy_with_tanks)
                            else:
                                random_comment = random.choice(unhappy_with_damage)

                        elif person_killed.role_variable == 2:

                            if random.choice([1,2]) == 1:
                                random_comment = random.choice(unhappy_with_tanks)
                            else:
                                random_comment = random.choice(unhappy_with_supports)
                        print(person_killed.name + ': ' + random_comment)

                person_killed.deaths += 1
                person_killed.frustration += 5
                person_killed.fun_had += -5

                # 0 tank, 1 support, 2dps

        if red_dead > blue_dead:
            for i in living_red_team:
                random_killer = random.choice(blue_team)
                print(i.name + ' was killed by ' + random_killer.name + "'s " + str(random.choice(eval(all_heroes[random_killer.char_being_played]).abilities)))
                random_killer.current_value += 1
                random_killer.addValue()
                random_killer.eliminations += 1
                random_killer.frustration -= 5
                random_killer.fun_had += 5
                blue_match_total += 1
            losing_team_swap(red_team, 'red')
        elif red_dead < blue_dead:
            for i in living_blue_team:
                random_killer = random.choice(red_team)
                print(i.name + ' was killed by ' + random_killer.name + "'s " + str(random.choice(eval(all_heroes[random_killer.char_being_played]).abilities)))
                random_killer.current_value += 1
                random_killer.addValue()
                random_killer.eliminations += 1
                random_killer.frustration -= 5
                random_killer.fun_had += 5
                red_match_total += 1
            losing_team_swap(blue_team, 'blue')

    if red_match_total > blue_match_total:
        red_games_won += 1
        for l in range(len(red_team)):
            red_team[l].current_value += 1
            red_team[l].addValue()
            red_team[l].fun_had += 10
            red_team[l].frustration -= 5
            end_choice = random.choices(
                [1,2],
                weights= [2,4],
                k=1

            )[0]
            if end_choice == 1:
                what_to_say = random.choices(
                    [1,2],
                    weights = [900000, (red_team[l].frustration * (6 - int(red_team[l].personality_type)) * (4800 - sr_average))]

                )[0]
                if what_to_say == 1:
                    print('(Red Team)' + red_team[l].name + ': ' + random.choice(end_of_game))
                elif what_to_say == 2:
                    print('(Red Team)' + red_team[l].name + ': ' + random.choice(end_of_game_angry))
        for l in range(len(blue_team)):
            blue_team[l].fun_had -= 35
            blue_team[l].frustration += 15
            end_choice = random.choices(
                [1,2],
                weights= [2,4],
                k=1

            )[0]
            if end_choice == 1:
                what_to_say = random.choices(
                    [1,2],
                    weights = [900000, (blue_team[l].frustration * (6 - int(blue_team[l].personality_type)) * (4800 - sr_average))]

                )[0]
                if what_to_say == 1:
                    print('(Blue Team)' + blue_team[l].name + ': ' + random.choice(end_of_game))
                elif what_to_say == 2:
                    print('(Blue Team)' + blue_team[l].name + ': ' + random.choice(end_of_game_angry))

    elif blue_match_total > red_match_total:
        blue_games_won += 1
        for l in range(len(red_team)):
            red_team[l].fun_had -= 35
            red_team[l].frustration -= 5
            end_choice = random.choices(
                [1,2],
                weights= [2,4],
                k=1

            )[0]
            if end_choice == 1:
                what_to_say = random.choices(
                    [1,2],
                    weights = [900000, (red_team[l].frustration * (6 - int(red_team[l].personality_type)) * (4800 - sr_average))]

                )[0]
                if what_to_say == 1:
                    print('(Red Team)' + red_team[l].name + ': ' + random.choice(end_of_game))
                elif what_to_say == 2:
                    print('(Red Team)' + red_team[l].name + ': ' + random.choice(end_of_game_angry))
        for l in range(len(blue_team)):
            blue_team[l].current_value += 1
            blue_team[l].addValue()
            blue_team[l].fun_had += 10
            blue_team[l].frustration += 15
            end_choice = random.choices(
                [1,2],
                weights= [2,4],
                k=1

            )[0]
            if end_choice == 1:
                what_to_say = random.choices(
                    [1,2],
                    weights = [900000, (blue_team[l].frustration * (6 - int(blue_team[l].personality_type)) * (4800 - sr_average))]

                )[0]
                if what_to_say == 1:
                    print('(Blue Team)' + blue_team[l].name + ': ' + random.choice(end_of_game))
                elif what_to_say == 2:
                    print('(Blue Team)' + blue_team[l].name + ': ' + random.choice(end_of_game_angry))
    else:
        games_tied += 1
        for l in range(len(red_team)):
            red_team[l].fun_had -= 10
            red_team[l].frustration += 5
            end_choice = random.choices(
                [1,2],
                weights= [2,4],
                k=1

            )[0]
            if end_choice == 1:
                what_to_say = random.choices(
                    [1,2],
                    weights = [900000, (red_team[l].frustration * (6 - int(red_team[l].personality_type)) * (4800 - sr_average))]

                )[0]
                if what_to_say == 1:
                    print('(Red Team)' + red_team[l].name + ': ' + random.choice(end_of_game))
                elif what_to_say == 2:
                    print('(Red Team)' + red_team[l].name + ': ' + random.choice(end_of_game_angry))
        for l in range(len(blue_team)):
            blue_team[l].fun_had -= 10
            blue_team[l].frustration += 5
            end_choice = random.choices(
                [1,2],
                weights= [2,4],
                k=1

            )[0]
            if end_choice == 1:
                what_to_say = random.choices(
                    [1,2],
                    weights = [900000, (blue_team[l].frustration * (6 - int(blue_team[l].personality_type)) * (4800 - sr_average))]

                )[0]
                if what_to_say == 1:
                    print('(Blue Team)' + blue_team[l].name + ': ' + random.choice(end_of_game))
                elif what_to_say == 2:
                    print('(Blue Team)' + blue_team[l].name + ': ' + random.choice(end_of_game_angry))

print('red matches won = ' + str(red_games_won))
print('blue matches won = ' + str(blue_games_won))
print('matches tied = ' + str(games_tied))

# End of round
#------------------------------------
# For each player, update the heroes played with the current one
#for current_team in [red_team, blue_team]:
    #for x in current_team:
        # Check to see if they swapped that round
       # if x.last_played != x.char_being_played:
        #    if x.char_being_played in x.heroes_played:
        #        x.heroes_played[x.char_being_played] += 1
       #     else:
       #         x.heroes_played[x.char_being_played] = 1
     #   x.last_played = x.char_being_played

# ----------------------- End of Game -----------------------------------


#!/usr/bin/env python

import argparse
import csv

def parse_args():
    parser = argparse.ArgumentParser(description='Process ting usages.')

    parser.add_argument('usage', nargs='+', help='path[s] to CSV file containing usage[s]')

    return parser.parse_args()

def addValues(csvReader, nameIndex, valueIndex):
    devices = {}
    for entry in csvReader:
        if entry[nameIndex] not in devices:
            devices[ entry[nameIndex] ] = 0
        devices[ entry[nameIndex] ] += int(entry[valueIndex])
    for device in devices:
        print('    {}: {}'.format(device, devices[device]))

def countValues(csvReader, nameIndex):
    devices = {}
    for entry in csvReader:
        if entry[nameIndex] not in devices:
            devices[ entry[nameIndex] ] = 0
        devices[ entry[nameIndex] ] += 1
    for device in devices:
        print('    {}: {}'.format(device, devices[device]))

def indexMatches(list, index, match):
    return len(list) > index and list[index] == match

def main():
    args = parse_args()
    for usage in args.usage:
        with open(usage, 'r') as csvfile:
            csvReader = csv.reader(csvfile)
            headers = csvReader.__next__()
            if indexMatches(headers, 5, 'Kilobytes'):
                print('Kilobytes')
                addValues(csvReader, 3, 5)
            elif indexMatches(headers, 12, 'Duration (min)'):
                print('Minutes')
                addValues(csvReader, 5, 12)
            elif indexMatches(headers, 7, 'Sent/Received'):
                print('Messages')
                countValues(csvReader, 4)

if __name__ == "__main__":
    main()


"""Utilities for handling images / thumbnails"""

def scaled_image_size(width, height, max_width, max_height) -> tuple[float, float]:
    """Get a new image size given original w/h and given max w/h

    Note:
        https://stackoverflow.com/a/6501997/4249857
    """
    # Set default w/h if given is == 0
    if not width:
        width = 1024
    if not height:
        height = 728

    ratio_x = max_width / width
    ratio_y = max_height / height
    ratio = min(ratio_x, ratio_y)

    return width * ratio, height * ratio


"""
SPECTOOLS contains useful functions for handling spectroscopic data

Author                 Version      Date
-----------------------------------------------
S. M. Crawford (SAAO)    1.0        8 Nov 2009

"""
import copy
import numpy as np
from scipy import signal
from scipy import interpolate as scint
from scipy.ndimage.filters import gaussian_filter1d
from scipy.optimize import minimize

from astropy.io import fits
from astropy import units as u
from astropy import modeling as mod
from astropy import stats

from specutils import Spectrum1D
from specutils.manipulation import gaussian_smooth

import pylab as pl

from .iterfit import iterfit
from . import SpecError

default_kernal = [0, -1, -2, -3, -2, -1, 0, 1, 2, 3, 2, 1, 0]

def mcentroid(xarr, yarr, kern=default_kernal, xc=None, xdiff=None):
    """Find the centroid of a line following a similar algorithm as
       the centroid algorithm in IRAF.   xarr and yarr should be an area
       around the desired feature to be centroided.  The default kernal
       is used if the user does not specific one.

       The algorithm solves for the solution to the equation

       ..math:: \int (I-I_0) f(x-x_0) dx = 0

    Parameters
    ----------
    xarr: numpy.ndarry
        array of x values

    yarr: numpy.ndarry
        array of y values

    kern: numpy.ndarray
         kernal to convolve the array with.  It has a default shape
         of [0, -1, -2, -3, -2, -1, 0, 1, 2, 3, 2, 1, 0]

    xc: int
        Initial guess

    xdiff: int
        Pixels around xc to use for convolution

    Returns
    -------
    cx: float
       Centroided x-value for feature

    """

    if xdiff is None:
       xdiff = len(kern)

    if xdiff < len(kern):
       xdiff = len(kern)

    if xc is not None and xdiff:
        mask = (abs(xarr - xc) < xdiff)
    else:
        mask = np.ones(len(xarr), dtype=bool)

    # convle the input array with the default kernal
    warr = np.convolve(yarr[mask], kern, mode='same')

    # interpolate the results
    # imask is used to make sure we are only gettin the
    # center pixels
    imask = (abs(xarr[mask]-xarr[mask].mean()) < 3)
    cx = np.interp(0, warr[imask], xarr[mask][imask])
    return cx

def interpolate(x, x_arr, y_arr, type='interp', order=3, left=None,
                right=None):
    """Perform interpolation on value x using arrays x_arr
       and y_arr.  The type of interpolate is defined by interp

       type:
       interp--use numpy.interp
       spline--use scipy.splrep and splev

       return
    """
    if type == 'interp':
        y = np.interp(x, x_arr, y_arr, left=left, right=right)
    if type == 'spline':
        if left is None:
            y_arr[0] = left
        if right is None:
            y_arr[-1] = right

        tk = scint.splrep(x_arr, y_arr, k=order)
        y = scint.splev(x, tk, der=0)

    return y

def clipstats(yarr, thresh, iter):
    """Return sigma-clipped mean of yarr"""
    mean = yarr.mean()
    std = yarr.std()
    for i in range(iter):
        mask = (abs(yarr - mean) < thresh * std)
        if mask.sum() <= 1:
            return yarr.mean(), yarr.std()
        mean = yarr[mask].mean()
        std = yarr[mask].std()

    return mean, std

def find_points(xarr, farr, kernal_size=3, sections=0):
    """Find all the peaks and the peak flux in a spectrum

    Parameters
    ----------
    xarr: numpy.ndarry
        array of x values

    yarr: numpy.ndarry
        array of y values

    kernal_size: int
        size of dection kernal

    sections: int
        Number of sections to divide the image into
        for detection

    Returns
    -------
    xp: numpy.ndarry
        array of x values for peaks

    fp: numpy.ndarry
        array of flux values for peaks

    """
    if sections:
        nsec = len(xarr) / sections
        xp = None
        for i in range(sections):
            x1 = int(i * nsec)
            x2 = int(x1 + nsec)
            xa = detect_lines(xarr[x1:x2], farr[x1:x2], kernal_size=kernal_size,
                              center=True)
            print(x1,x2, xa)
            if xp is None:
                xp = xa.copy()
            else:
                xp = np.concatenate((xp, xa))
    else:
        xp = detect_lines(xarr, farr, kernal_size=kernal_size, center=True)

    # create the list of the fluxes for each line
    xc = xp.astype(int)
    xf = farr[xc]
    return xp, xf

def find_backstats(f_arr, sigma, niter):
    """Iteratively calculate the statistics of an array"""
    ave = f_arr.mean()
    std = f_arr.std()
    for i in range(niter):
        mask = (abs(f_arr - ave) < sigma * std)
        ave = f_arr[mask].mean()
        std = f_arr[mask].std()
    return ave, std

def find_peaks(f_arr, sigma, niter, bsigma=None):
    """Go through an ordered array and find any element which is a peak"""
    # set up the variables
    if bsigma is None:
        bsigma = sigma

    # determine the background statistics
    back_ave, back_std = find_backstats(f_arr, sigma, niter)

    # calculate the differences between the pixels
    dfh = f_arr[1:-1] - f_arr[:-2]
    dfl = f_arr[1:-1] - f_arr[2:]

    # find the objects
    mask = (dfh > 0) * (dfl > 0) * \
        (abs(f_arr[1:-1] - back_ave) > back_std * sigma)
    t = np.where(mask)[0]
    return t + 1

def detect_lines(x, y, kernal_size=3, centroid_kernal=default_kernal,
                 center=False):
    """Detect lines goes through a 1-D spectra and detect peaks

    Parameters
    ----------
    x: ~numpy.ndarray
        Array describing the x-position

    y: ~numpy.ndarray
        Array describing the counts in each x-position

    kernal_size: int
        Size for the detection kernal

    centroid_kernal:
        Kernal to be used for centroiding

    center: boolean
        If True, centroid for detected peaks will be calculated

    Returns
    -------
    xp: ~numpy.ndarray
        Array of x-positions of peaks in the spectrum
    """
    # find all peaks
    xp = signal.find_peaks_cwt(y, np.array([kernal_size]))
    xp = np.array(xp)

    # set the output values
    if center:
        xdiff = int(0.5 * len(centroid_kernal) + 1)
        x_arr = np.arange(len(x))
        for i in range(len(xp)):
            xp[i] = mcentroid(x, y, kern=centroid_kernal, xdiff=xdiff, xc=x[xp[i]])

    return xp

def flatspectrum(xarr, yarr, mode='mean', thresh=3, iter=5, order=3):
    """Remove the continuum from a spectrum either by masking it or fitting
       and subtracting it.

       xarr= input x-vales (pixels or wavelength)
       yarr= flux or counts for the spectrum
       mode=None--no subtraction
       mean--subtract off the mean
       poly--subtact off a fit
       mask--return a spectra with continuum set to zero
    """
    if mode == 'mean':
        # subtract off the mean value
        sarr = yarr - clipstats(yarr, thresh, iter)[0]
    elif mode == 'poly':
        # calculate the statistics and mask all of the mask with values above
        # these
        it = iterfit(xarr, yarr, function='poly', order=order)
        it.iterfit()
        sarr = yarr - it(xarr)
    elif mode == 'mask':
        # mask the values
        mean, std = clipstats(yarr, thresh, iter)
        mask = (yarr < mean + thresh * std)
        sarr = yarr.copy()
        sarr[mask] = 0
    else:
        sarr = yarr.copy()
    return sarr

def findwavelengthsolution(xarr, farr, sl, sf, ws, mdiff=20, wdiff=20, sigma=5,
                           niter=5):
    """Calculates the wavelength solution given a spectra and a set of lines.
       Hopefully an accurate first guess (ws) is provided and relative fluxes
       are provided as well, but if not, then the program is still designed
       to attempt to handle it.

       returns ws
    """
    # match up the features
    # xp, wp=findfeatures(xarr, farr, sl, sf, ws, mdiff=mdiff, wdiff=wdiff,
    #                    sigma=sigma, niter=niter)
    xp, wp = crosslinematch(xarr, farr, sl, sf, ws, mdiff=mdiff, wdiff=wdiff,
                            sigma=sigma, niter=niter)

    # find the solution to the best fit
    mask = (wp > 0)
    if mask.sum() >= ws.order:
        nws = WavelengthSolution.WavelengthSolution(
            xp[mask], wp[mask], model=ws.model)
        nws.fit()
    else:
        nws = None
    # for i in range(len(xp)): print xp[i], wp[i], wp[i]-nws.value(xp[i])
    # print nws.sigma(xp,wp)
    return nws

def findfeatures(xarr, farr, sl, sf, ws, mdiff=20, wdiff=20, sigma=5, niter=5,
                 sections=3):
    """Given a spectra, detect lines in the spectra, and find lines in
       the line list that correspond to those lines
    """

    # detect lines in the input spectrum and identify the peaks and peak values
    xp, xf = find_points(xarr, farr, kernal_size=sigma, sections=sections)

    # return no solution if no peaks were found
    if len(xp) == 0:
        return None

    # find the best match to the lines
    wp = findmatch(xarr, farr, xp, xf, sl, sf, ws, xlimit=mdiff, wlimit=wdiff)

    try:
        for i in range(len(xp)):
            if wp[i] > -1:
                pass
    except Exception as e:
        message = 'Unable to match line lists because %s' % e
        raise SpecError(message)
    return xp, wp

def findmatch(xarr, farr, xp, xf, sl, sf, ws, xlimit=10, wlimit=2):
    """Find the best match between the observed arc lines and the spectral
       line list.  If available, use the line fluxes and the wavelength
       solution.  Returns a an array that is a wavelength for each peak
       wavelength

       returns wp
    """
    wp = xp * 0.0 - 1
    px = xp * 0.0

    # calculate it using only xp and sl
    if sf is None and not ws:
        print('Currently not available')

    # calculate it without any wavelength solution
    elif not ws:
        pass

    # calculate it without any flux information
    elif sf is None and ws:
        for i in xf.argsort()[::-1]:
            cx = mcentroid(xarr, farr, xc=xp[i], xdiff=4)
            if abs(cx - xp[i]) < xlimit:
                w = wavematch(ws(cx), wp, sl)
                wp[i] = w

    # calculate it using all of the information
    else:
        dcoef = ws.coef * 0.0
        dcoef[0] = 10
        dcoef[1] = dcoef[1] * 0.2
        ndstep = 20
        # this matches up the spectra but only varies the first
        # two coefficients by a small amount
        nws = spectramatch(
            xarr, farr, sl, sf, ws, dcoef, ndstep=ndstep, res=2, dres=0.1)
        for i in range(len(xf)):  # xf.argsort()[::-1]:
            cx = mcentroid(xarr, farr, xc=xp[i], xdiff=4)
            if abs(cx - xp[i]) < xlimit:
                w = wavematch(nws(cx), wp, sl, wlimit=wlimit)
                wp[i] = w
                px[i] = matchprob(cx, w, xf[i], xp, xf, sl, nws, dw=0.8)
            # print cx, nws.value(cx), wp[i], px[i], xp[i], xf[i]
    return wp

def matchprob(x, w, f, xp, xf, sl, ws, dw=5):
    """Calculate the probability that the line is the correct match.
       If it is matched up correctly and the solution is correct, then the
       other lines should be found in the right place.   The probabilibty will
       decrease by a factor of 0.1 for each line not found in the right place.
    """
    if w == -1:
        return 0
    p = 1.0
    # first assume that the zero point of the solution is set by the value
    try:
        nws = copy.deepcopy(ws)
    except:
        nws = WavelengthSolution.WavelengthSolution(
            ws.x, ws.wavelength, model=ws.model)
        nws.fit()
    nws.coef[0] = nws.coef[0] - (nws(x) - w)

    # Now loop through and see how well other objects end up fitting
    # if they are not present or there is problems, reduce the probability
    for i in xf.argsort()[::-1]:
        dist = abs(sl - nws(xp[i]))
        if dist.min() > dw:
            p = p * (1 - 0.1)
        else:
            p = p * (1 - 0.1 * dist.min() / dw * xf[i] / xf.max())
        # print x, w, xp[i], nws.value(xp[i]),sl[dist.argmin()],xf[i],
        # dist.min(),p

    return p

def spectramatch(xarr, farr, sw, sf, ws, dcoef, ndstep, res=2, dres=0.1,
                 inttype='interp'):
    """Using all the information which is available, cross correlate the
       observed spectra and the wavelength spectra to find the best
       coefficients and match the data
    """
    # create an artificial spectrum of the lines
    lmax = farr.max()

    line_table = Table([sw, sf], names=('wavelength', 'flux'))
    spec = make_artificial_spectra(line_table,  dw = dres, sigma = res)
    swarr = spec.spectral_axis.value
    sfarr = spec.flux.value * farr.max() / spec.flux.value.max()

    nws = findxcor(xarr, farr, swarr, sfarr, ws, dcoef=dcoef, ndstep=ndstep,
                   inttype=inttype)
    return nws

def mod_coef(coef, dcoef, index, ndstep):
    """For a given index, return a list of modulations in that coefficient
    """
    dlist = []

    # if we have reached the last coefficient,
    if index >= len(coef):
        return dlist

    # if the coefficient doesn't need any modulation,
    # then move on to the next coefficient
    if dcoef[index] == 0:
        if index < len(coef) - 1:
            dlist.extend((mod_coef(coef, dcoef, index + 1, ndstep)))
        else:
            dlist.append(coef)
        return dlist

    # if the index does need variation, then proceed in one of two ways:
    # if it isn't the last coefficient, iterate over the values and then
    #   step down and do all the other coefficients
    # if it is the last coefficient, then iterate over the values and
    #   create the lowest level coefficient
    if index < len(coef) - 1:
        for x in np.arange(-dcoef[index], dcoef[index],
                           2 * dcoef[index] / float(ndstep)):
            ncoef = coef.copy()
            ncoef[index] = coef[index] + x
            dlist.extend(mod_coef(ncoef, dcoef, index + 1, ndstep))
    else:
        for x in np.arange(-dcoef[index],
                           dcoef[index], 2 * dcoef[index] / float(ndstep)):
            ncoef = coef.copy()
            ncoef[index] = coef[index] + x
            dlist.append(ncoef)
    return dlist

def ncor(x, y):
    """Calculate the normalized correlation of two arrays"""
    d = np.correlate(x, x) * np.correlate(y, y)
    if d <= 0:
        return 0
    return np.correlate(x, y) / d ** 0.5

def wavematch(w, wp, sl, wlimit=10):
    """Compare a wavelength to an observed list and see if it matches up.  Skip
       if the lines is already in the wp list

    """

    # first remove anything already in the self.wp from the sl list
    lines = []
    for x in sl:
        if x not in wp:
            lines.append(x)
    if not lines:
        return -1
    lines = np.array(lines)

    # find the best match
    dist = abs(lines - w)
    if dist.min() < wlimit:
        i = dist.argmin()
    else:
        return -1

    # return the values
    return lines[i]

def findfit(xp, wp, ws=None, **kwargs):
    """Find the fit using just the matched points of xp and wp"""
    if ws is None:
        ws = WavelengthSolution.WavelengthSolution(xp, wp, **kwargs)
    else:
        ws.x = xp
        ws.wavelength = wp
    if len(xp) < ws.order:
        msg = 'Not enough points to determine an accurate fit'
        raise SpecError(msg)
    ws.fit()
    return ws

def findzeropoint(xarr, farr, swarr, sfarr, ws, dc=10, ndstep=20,
                  inttype='interp'):
    """Uses cross-correlation to find the best fitting zeropoint

    Parameters
    ----------
    xarr: numpy.ndarry
        array of x values

    farr: numpy.ndarry
        array of flux values

    swarr: numpy.ndarry
        array of wavelengths for known lines

    sfarr: numpy.ndarry
        array of flux values for known lines

    ws: ~WavelengthSolution.WavelengthSolution
        wavelength solution transforming between x and wavelength

    dc: float
        initial guess for range of zeropoint

    ndsteps: int
        number of steps to search over

    Returns
    -------
    ws: ~WavelengthSolution.WavelengthSolution
        wavelength solution with an updated zeropoint term

    """

    # if an initial solution, then cut the template lines to just be the
    # length of the spectrum
    if ws is None:
        return ws

    # set up the the dc coefficient
    dcoef = ws.coef * 0.0
    dcoef[0] = dc

    ws = findxcor(xarr, farr, swarr, sfarr, ws, dcoef=dcoef,
                  ndstep=ndstep, inttype=inttype)
    return ws

def xcorfun(p, xarr, farr, swarr, sfarr, interptype, ws):
    ws.coef=p
    # set the wavelegnth coverage
    warr = ws(xarr)
    # resample the artificial spectrum at the same wavelengths as the observed
    # spectrum
    asfarr = interpolate(
        warr, swarr, sfarr, type=interptype, left=0.0, right=0.0)
    return abs(1.0 / ncor(farr, asfarr))

def fitxcor(xarr, farr, swarr, sfarr, ws, interptype='interp', debug=False):
    """Maximize the normalized cross correlation coefficient for the full
        wavelength solution
    """
    try:
        nws = copy.deepcopy(ws)
    except:
        nws = WavelengthSolution.WavelengthSolution(
            ws.x, ws.wavelength, ws.model)
        nws.coef=ws.coef

    res = minimize(xcorfun, nws.coef, method='Nelder-Mead',
                   args=(xarr, farr, swarr, sfarr, interptype, nws))
    bcoef = res['x']
    nws.coef=bcoef
    return nws

def findxcor(xarr, farr, swarr, sfarr, ws, dcoef=None, ndstep=20, best=False,
             inttype='interp', debug=False):
    """Find the solution using crosscorrelation of the wavelength solution.
       An initial guess needs to be supplied along with the variation in
       each coefficient and the number of steps to calculate the correlation.
       The input wavelength and flux for the known spectral features should
       be in the format where they have already
       been convolved with the response function of the spectrograph

       xarr--Pixel coordinates of the image

       farr--Flux values for each pixel

       swarr--Input wavelengths of known spectral features

       sfarr--fluxes of known spectral features

       ws--current wavelength solution

       dcoef--Variation over each coefficient for correlation

       ndstep--number of steps to sample over

       best--if True, return the best value
             if False, return an interpolated value

       inttype--type of interpolation

    """

    # cross-correlate the spectral lines and the observed fluxes in order to
    # refine the solution
    try:
        nws = copy.deepcopy(ws)
    except:
        nws = WavelengthSolution.WavelengthSolution(
            ws.x, ws.wavelength, ws.model)

    # create the range of coefficents
    if dcoef is None:
        dcoef = ws.coef * 0.0 + 1.0

    dlist = mod_coef(ws.coef, dcoef, 0, ndstep)
    # loop through them and deteremine the best cofficient
    cc_arr = np.zeros(len(dlist), dtype=float)

    for i in range(len(dlist)):
        # set the coeficient
        nws.coef=dlist[i]

        # set the wavelegnth coverage
        warr = nws(xarr)

        # resample the artificial spectrum at the same wavelengths as the
        # observed spectrum
        asfarr = interpolate(
            warr, swarr, sfarr, type=inttype, left=0.0, right=0.0)

        # calculate the correlation value
        cc_arr[i] = ncor(farr, asfarr)
        #if debug: print cc_arr[i], " ".join(["%f" % k for k in dlist[i]])

    # now set the best coefficients
    i = cc_arr.argmax()
    bcoef = dlist[i]
    nws.coef=bcoef
    if best:
        return nws

    # interpoloate over the values to determine the best value
    darr = np.array(dlist)
    for j in range(len(nws.coef)):
        if dcoef[j] != 0.0:
            i = cc_arr.argsort()[::-1]
            tk = np.polyfit(darr[:, j][i[0:5]], cc_arr[i[0:5]], 2)

            if tk[0] == 0:
                bval = 0
            else:
                bval = -0.5 * tk[1] / tk[0]

            # make sure that the best value is close
            if abs(bval - bcoef[j]) < 2 * dcoef[j] / ndstep:
                bcoef[j] = bval

            # coef=np.polyfit(dlist[:][j], cc_arr, 2)
            # nws.coef[j]=-0.5*coef[1]/coef[0]

    nws.coef=bcoef

    return nws

def readlinelist(linelist):
    """Read in the line lists.  Determine what type of file it is.  The default
       is an ascii file with line and relative intensity.  The other types are
       just line, or a wavelenght calibrated fits file

       return lines, fluxes, and status
    """
    slines = []
    sfluxes = []
    status = 0

    # Check to see if it is a fits file
    # if not, then read in the ascii file
    if linelist[-4:] == 'fits':
        try:
            slines, sfluxes = readfitslinelist(linelist)
        except Exception as e:
            message = 'Unable to read in the line list %s because %s' % (
                linelist, e)
            raise SpecError(message)
    else:
        try:
            slines, sfluxes = readasciilinelist(linelist)
        except Exception as e:
            message = 'Unable to read in the line list %s because %s' % (
                linelist, e)
            raise SpecError(message)

    # conver to numpy arrays
    try:
        slines = np.asarray(slines)
        sfluxes = np.asarray(sfluxes)
    except Exception as e:
        message = 'Unable to create numpy arrays because %s' % (e)
        raise SpecError(message)

    return slines, sfluxes

def readfitslinelist(linelist):
    """Read in the line lists from an fits file.  If it is a 2-D array
       it will assume that it is an image and select the central wavlength

       return lines, fluxes, and status
    """
    slines = []
    sfluxes = []

    # open the image
    shdu = fits.open(linelist)
    nhdu = len(shdu)
    # determine if it is a one or two-d image
    # if ndhu=0 then assume that it is in the zeroth image
    # otherwise assume the data is in the first extension
    # assumes the x-axis is the wavelength axis
    if nhdu == 1:
        ctype1 = shdu[0].header['CTYPE1']
        crval1 = shdu[0].header['CRVAL1']
        cdelt1 = shdu[0].header['CDELT1']
        if shdu[0].data.ndim == 1:
            data = shdu[0].data
            wave = crval1 + cdelt1 * np.arange(len(shdu[0].data))

    # detect lines in the input spectrum and identify the peaks and peak values
    slines, sfluxes = find_points(wave, data, kernal_size=3)
    """
    figure(figsize=(8,8), dpi=72)
    axes([0.1, 0.1, 0.8, 0.8])
    plot(wave, data, ls='-')
    plot(slines, sfluxes, ls='', marker='o')
    xlim(4220,4900)
    show()
    """

    return slines, sfluxes

def readasciilinelist(linelist):
    """Read in the line lists from an ascii file.  It can either be a
        file with one or two columns.  Only read in lines that are not
        commented out.

       return lines, fluxes, and status
    """
    slines = []
    sfluxes = []

    # read in the file
    f = open(linelist)
    lines = f.readlines()
    f.close()

    # for each line,
    for l in lines:
        l = l.strip()
        if l and not l.startswith('#'):
            l = l.split()
            slines.append(float(l[0]))
            try:
                sfluxes.append(float(l[1]))
            except IndexError:
                sfluxes.append(-1)
    return slines, sfluxes

def makesection(section):
    """Convert a section that is a list of coordinates into
       a list of indices
    """
    s = []
    if section is None:
        return s
    try:
        for i in section.split(':'):
            s.append(int(i))
    except Exception as e:
        msg = 'Not able to convet section to list because %s' % e
        raise SpecError(msg)
    return s

def vac2air(w):
    """following the definition used by SDSS based on Morton (1991, ApJS, 77, 119)
       AIR = VAC / (1.0 + 2.735182E-4 + 131.4182 / VAC^2 + 2.76249E8 / VAC^4)

       returns wavelength
    """
    return w / (1.0 + 2.735182E-4 + 131.4182 / w ** 2 + 2.76249E8 / w ** 4)

def crosslinematch(xarr, farr, line_table, ws, mdiff=20, wdiff=20, res=2, dres=0.1,
                   sigma=5, niter=5, dc=20, sections=3):
    """Cross line match takes a line list and matches it with the observed
       spectra.

       The following steps are employed in order to achive the match:

    """
    # setup initial wavelength array
    warr = ws(xarr)
    # detect lines in the input spectrum and identify the peaks and peak values
    xp, xf = find_points(xarr, farr, kernal_size=sigma, sections=sections)

    # create an artificial lines for comparison
    spec = make_artificial_spectra(line_table,  dw = dres, sigma = res)
    swarr = spec.spectral_axis.value
    sfarr = spec.flux.value * farr.max() / spec.flux.value.max()

    # now loop through the lines
    # exclude those lines that are outside of the source
    # then use the wdiff region to do a cross correlation around
    # a source and then proceed to calculate what the match is
    sl = line_table['wavelength']
    sf = line_table['flux']
    si = line_table['flux'].argsort()
    dcoef = ws.coef * 0.0
    dcoef[0] = dc
    xp_list = []
    wp_list = []
    for i in si[::-1]:
        if sl[i] < warr.max() and sl[i] > warr.min():
            mask = abs(warr - sl[i]) < wdiff
            smask = abs(swarr - sl[i]) < wdiff
            nws = findxcor(xarr[mask], farr[mask], swarr[smask], sfarr[smask],
                           ws, dcoef=dcoef, ndstep=20, best=False,
                           inttype='interp', debug=False)
            # now find the best matching point
            # require it to be very close using the nws values
            # require  also that the fluxes match somehow or are close
            # ie if it is the third brightest thing in that region, then
            # it should be the third brightest thing
            # also require a good fit between observed and artificial
            nwarr = nws(xarr)
            nwp = nws(xp)
            d = abs(nwp - sl[i])
            j = d.argmin()
            if d.min() < res:
                if lineorder(xp, xf, sl, sf, sl[i], xp[j], wdiff, nws) and \
                   abs(ws(xp[j]) - sl[i]) < mdiff:
                    xp_list.append(xp[j])
                    wp_list.append(sl[i])
    return np.array(xp_list), np.array(wp_list)

def lineorder(xp, xf, sl, sf, sw, xb, wdiff, nws):
    """Determines the rank order of sw inside the set of lines and
       then determines if the xp line is the same rank order.
       Returns True if it is
    """

    # first cut the two line list down to the same size
    mask = abs(nws(xp) - sw) < wdiff
    smask = abs(sl - sw) < wdiff

    # identify the order of the spectral lines
    i = sf[smask].argsort()
    i_ord = i[sl[smask][i] == sw]
    if len(i_ord) > 1:
        return False

    # identify the order of the observed lines
    j = xf[mask].argsort()
    j_ord = j[xp[mask][j] == xb]
    if len(j_ord) > 1:
        return False
    return i_ord == j_ord

def smooth_spectra(xarr, farr, sigma=3, nkern=20):
    """Given a xarr and flux, smooth the spectrum"""
    xkern = np.arange(nkern)
    kern = np.exp(-(xkern - 0.5 * nkern) ** 2 / (sigma) ** 2)

    return gaussian_filter1d(farr, sigma)

def boxcar_smooth(spec, smoothwidth):
    # get the average wavelength separation for the observed spectrum
    # This will work best if the spectrum has equal linear wavelength spacings
    wavespace = np.diff(spec.wavelength).mean()
    # kw
    kw = int(smoothwidth / wavespace)
    # make sure the kernel width is odd
    if kw % 2 == 0:
        kw += 1
    kernel = np.ones(kw)
    # Conserve flux
    kernel /= kernel.sum()
    smoothed = spec.flux.copy()
    smoothed[(kw / 2):-(kw / 2)] = np.convolve(spec.flux, kernel, mode='valid')
    return smoothed

def getwsfromIS(k, ImageSolution, default_ws=None):
    """From the imageSolution dictionary, find the ws which is nearest to
       the value k

    k: int
         Row to return wavelength solution

    ImageSolution: dict
         Dictionary of wavelength solutions.  The keys in the dict should
         correspond to rows

    default_ws: None or ~WavelengthSolution.WavelengthSolution
         Value to return if no corresponding match in getwsfromIS

    Returns
    -------
    ws: ~WavelengthSolution.WavelengthSolution
         Wavelength solution for row closest to k

    """
    if len(ImageSolution) == 0:
        return default_ws
    ISkeys = np.array(ImageSolution.keys())
    ws = ImageSolution[ISkeys[abs(ISkeys - k).argmin()]]
    if ws is None:
        dist = abs(ISkeys[0] - k)
        ws = ImageSolution[ISkeys[0]]
        for i in ISkeys:
            if ImageSolution[i] and abs(i - k) < dist:
                dist = abs(i - k)
                ws = ImageSolution[i]
    return ws

def arc_straighten(data, istart, ws, rstep=1):
    """For a given image, assume that the line given by istart is the fiducial and then calculate
       the transformation between each line and that line in order to straighten the arc

       Parameters
       ----------
       data: ~numpy.ndarray
           Array contianing arc lines

       istart: int
           Row to use as the default row

       ws: ~WavelengthSolution.WavelengthSolution
         Initial Wavelength solution

       rstep: int
         Number of steps to take between each wavelength solution

       Returns
       -------
       ImageSolution: dict
           Dict contain a Wavelength solution for each row
    """

    ImageSolution = {}
    # now step around the central row
    k = istart
    oxarr = np.arange(len(data[k]))
    ofarr = data[k]

    ws.xarr = oxarr
    ws.warr = oxarr
    ws.fit()
    ImageSolution[k] = ws

    for i in range(rstep, int(0.5 * len(data)), rstep):
        for k in [istart - i, istart + i]:
            lws = getwsfromIS(k, ImageSolution)
            xarr = np.arange(len(data[k]))
            farr = data[k]
            nws = fitxcor(
                xarr,
                farr,
                oxarr,
                ofarr,
                lws,
                interptype='interp')
            ImageSolution[k] = nws

    return ImageSolution

def wave_map(data, iws):
    """Produce a wave map where each pixel in data corresponds to a wavelength

    Parameters
    ----------
    data: ~numpy.ndarray
        Array contianing arc lines

    ImageSolution: dict
        Dict contain a Wavelength solution for each row

    Returns
    -------
    data: ~numpy.ndarray
        Array contianing wavelengths for each pixel

    Notes
    -----
    At this time, `iws` must have an entry for every row.

    """
    # set up what we will need
    wave_map = np.zeros_like(data)
    keys = np.array(iws.keys())
    xarr = np.arange(data.shape[1])

    #now run through each and add to the array
    for i in range(keys.min(), keys.max()):
        if i in keys:
           wave_map[i,:]=iws[i](xarr)

    #TODO interpolate between empty rows

    return wave_map

def ws_match_lines(xarr, flux, ws, dw=1.0, lw=None,
                  kernal_size=3):
    """Match lines given a wavelength solution

    Parameters
    ----------
    xarr: ~numpy.ndarray
       Continuus array of x positions

    xarr: ~numpy.ndarray
       Continuus array of x positions

    ws: ~WavelengthSolution
       Wavelength solution including line list

    dw: float
       Area around line to search for peaks in wavelength space

    lw: ~numpy.ndarray
       Line list of wavelengths to be matched

    kernal_size: int
       Kernal size used in detecting lines

    Returns
    -------
    matches: ~numpy.ndarray
       Array of matched x-positions and wavelengths

    """

    xp = detect_lines(xarr, flux, kernal_size=kernal_size, center=True)
    wp = ws(xp)

    # now find all the potential matches
    if lw is None:
        lw = ws.wavelength
    match=[]
    for w in lw:
        m_i = np.where(abs(wp-w)<dw)[0]
        for i in m_i:
            match.append([xp[i], wp[i],w])

    return np.array(match)

def match_probability(a, b, m_init=mod.models.Polynomial1D(1),
                      fitter=mod.fitting.LinearLSQFitter(),
                      tol=0.01, n_iter=5):
    """Determine the probability that two lists match.   This is determine
    by fitting a transformation to the two lists and calculating the
    likelihood of each point fit to that model. The likelihood is
    calculated from the $\Chi^2$ for each point.

    Parameters
    ----------
    a: ~numpy.ndarray
        Array of matched values

    b: ~numpy.ndarry
        Array of matched values

    m_init: ~astropy.models.modelling
        Model describing the transform between the two arrays

    fitter: ~astropy.models.fitting
        Fitter to be usef for the model

    tolerance: float
        Tolerance for the fit

    n_inter: int
        Maximum number of interations

    Returns
    -------
    m: ~astropy.models.modelling
        Model describing the transform between the two arrays

    prob: ~numpy.ndarray
        Model with the likelihood of each point fitting the relationship
    """
    if a.shape!=b.shape:
        raise ValueError('Arrays are of different shapes')

    #set up the probability array
    prob = np.ones_like(a)

    for i in range(n_iter):
        m = fitter(m_init, a, b, weights=prob)
        rms = np.average((b-m(a))**2, weights=prob)**0.5
        if rms < tol: break

        #caculate the likelihood
        chi = ((b-m(a))/rms)**2
        prob = np.exp(-chi/2)
    return m, prob

def make_artificial_spectra(line_table, wavelength_range = None,  dw = 0.1,
                    sigma=1e-2, wavelength_unit=u.angstrom, flux_unit=u.electron):
    """Given a table with identified spectral lines and their fluxes, create an artifical Spectrum1D
    with each of the spectral features.

    Parameters
    ----------
    line_table: Astropy.Table
        A table of lines in the observed arc.  The table should have a column labeled
        'wavelength' and a column labeled 'flux'.

    wavelength_range:  list
        wavelenght range for the artificial spectrum.  If None, then it will default to the
        minimum and maximum in line_table.

    dw: float
        Sampling to use in the dispersion of the artificial spectrum

    wavelength_units: Atropy.Units
        Units of the wavelength array.  If None, it will assume Angstroms.

    flux_units:  Astropy.Units
        Units of the flux array.If None, it will assume electrons.

    """
    if wavelength_range is None:
        wavelength_range=[line_table['wavelength'].min(), line_table['wavelength'].max()]

    warr = np.arange(wavelength_range[0], wavelength_range[1], dw)

    flux = np.zeros(len(warr), dtype=float)
    for w, f in line_table:
        i = abs(warr - w).argmin()
        flux[i] = f

    if wavelength_unit is None:
        wavelength

    spec =  Spectrum1D(spectral_axis=warr*wavelength_unit, flux = flux * flux_unit)
    spec = gaussian_smooth(spec, stddev=sigma)

    return spec

class BoxExtract:
    """Extract a 1D spectrum from an array within a box region

    Parameters
    ----------
    ccd: CCDData
        A CCDData object describing a 2D array

    wavelength_axis: int
        Index of the dispersion axis

    """
    def __init__(self, ccd, wavelength_axis=1):
        # to do -- update to enable use of an numpy array
        self.ccd=ccd
        self.axis=wavelength_axis
        if self.axis:
            self.flux_axis = 0
        else:
            self.flux.axis = 1

    def __call__(self, y1, y2):
        """
        Parameters
        ----------
        y1: int
            lower bound of the box

        y2L int
            upper bound of the box

        Returns
        -------
        spec: Spectrum1D
            A 1D spectrum object extracted from a box region
        """
        try:
            w_unit = u.Unit(self.ccd.wcs.wcs.ctype[self.axis])
        except:
            w_unit = u.Unit('pixel')
        if w_unit is not u.Unit('pixel'):
            if self.axis == 1:
                w = self.ccd.wcs.pixel_to_world(0,x)[self.axis]
            elif self.axis == 0:
                w = self.ccd.wcs.pixel_to_world(x,0)[self.axis]
            else:
                raise ValueError('Axis must be 0 or 1')
        else:
            w = np.arange(self.ccd.shape[1])

        flux_unit = self.ccd.unit
        flux = self.ccd.data[y1:y2,:].sum(axis=self.flux_axis)

        return Spectrum1D(spectral_axis=w*w_unit, flux = flux * flux_unit)


def decode_string(string, codes):
    inv_codes = {v: k for k, v in codes.items()}
    res = ''
    i = 0
    while i < len(string):
        j = i + 1
        while j <= len(string):
            code = ''.join(string[i:j])
            liter = inv_codes.get(code)
            if liter:
                res += liter
                i = j - 1
                break
            j += 1
        i += 1
    return res

uniques, size = map(lambda x: int(x), input().split(' '))
codes = {}
for i in range(0, uniques):
    liter, code = input().split(': ')
    codes[liter] = code
encoded = input()

print(decode_string(encoded, codes))


import unittest
from sklearn.datasets import make_sparse_spd_matrix
from nitk import methods
import numpy as np
from nitk.clime import CLIME, CLIMECV
import rpy2.robjects as robjects
from rpy2.robjects.packages import importr
import rpy2.robjects.numpy2ri
import rpy2.rinterface as rinterface
from sklearn.utils.testing import assert_array_almost_equal
from sklearn.utils.testing import assert_array_less

class TestCLIME(unittest.TestCase):
    def _estimate_precision_matrix_using_r(self, X, l):
        """
        Estimates the precision matrix using the R
        implementation provided by the authors
        """
        rpy2.robjects.numpy2ri.activate()
        clime = importr('clime')
        prec = clime.clime(X, np.array([l]), perturb=True, standardize=False, linsolver="simplex")
        prec = np.array(prec[0][0])

        return prec
    def test_clime(self):
        """
        Generates a distribution with a sparse precision matrix and sees if the non-zero values are correctly picked up
        by the CLIME
        """
        p = 50
        n = 10
        K = make_sparse_spd_matrix(p, 0.7)
        C = np.linalg.inv(K)
        X = np.random.multivariate_normal(np.zeros(p), C, n)
        l = 0.5
        r_prec = self._estimate_precision_matrix_using_r(X, l)
        print(r_prec)
        cl = CLIME(l, True)
        cl.fit(X)

        assert_array_almost_equal(r_prec, cl.precision_, decimal=2)

    def test_clime_cv(self):
        """
        Sees how CLIME performs when we use cross validation to select lambda
        """
        p = 50
        n = 10
        K = make_sparse_spd_matrix(p, 0.7)
        C = np.linalg.inv(K)
        X = np.random.multivariate_normal(np.zeros(p), C, n)
        l = 0.5
        r_prec = self._estimate_precision_matrix_using_r(X, l)
        print(r_prec)
        cl = CLIMECV(True)
        cl.fit(X)
        print(cl.precision_)

if __name__ == '__main__':
    unittest.main()