ThunderLeague Map Selector


Having successfully used the ThunderScraper to create a csv file containing all of the map information, the next step was to divide the maps based on map size so I could get an even mix of differently-sized maps in each of my map pools.

Then, I could look at each of the maps, that were balanced for a specific matchup in a specific size range, and use that to arbitrarily (by my own preferences) construct the map pools.

Once I had the map pools constructed, I also needed a function that I could use to dynamically select the maps. Basically, the process was as follows: Two players knew that they could see play on any of 16 maps. A map would be selected from the pool at random without replacement, and one player could either veto or stay on that map. If they veto, their veto count gets decremented, and the map is rejected. If they stay, the other player either vetoes or stays. If there are two stays, the map is added to the pool. If one player runs out of vetoes, he stays on every subsequent selection. The process repeats until a prespecified number of maps are selected.

Generally speaking, players seemed to enjoy the novel map selection process.

Next, check out the Competitor Bracket Generator .


App.py File



        #!/usr/bin/env python
        # coding: utf-8
        
        # In[1]:
        
        
        import numpy as np
        import pandas as pd
        import random
        
        
        # In[2]:
        
        
        first_guy = pd.read_csv("MapCSV/true_full_list.csv")
        
        
        # In[47]:
        
        
        # full_maps_df = first_guy.rename(columns = {"Unnamed: 0": "Map"})
        
        # full_maps_df.loc[full_maps_df['Map'] == 'Abiogenesis_LE']
        
        first_guy.loc[first_guy["Map"] == "Alterzim_Stronghold_TE"]
        
        
        # 

So It Begins.

# In[50]: maps_with_some_games = first_guy.dropna().sort_values("Map").drop(columns = ['Unnamed: 0']) tvz_maps_low_count = maps_with_some_games.loc[maps_with_some_games['tvz count'].astype(int) <= 30] zvp_maps_low_count = maps_with_some_games.loc[maps_with_some_games['zvp count'].astype(int) <= 30] pvt_maps_low_count = maps_with_some_games.loc[maps_with_some_games['pvt count'].astype(int) <= 30] tvz_maps_balanced = maps_with_some_games.loc[(maps_with_some_games['tvz winrate'] > 46) & (maps_with_some_games['tvz winrate'] < 54)] zvp_maps_balanced = maps_with_some_games.loc[(maps_with_some_games['zvp winrate'] > 46) & (maps_with_some_games['zvp winrate'] < 54)] pvt_maps_balanced = maps_with_some_games.loc[(maps_with_some_games['pvt winrate'] > 46) & (maps_with_some_games['pvt winrate'] < 54)] len(tvz_maps_balanced), len(zvp_maps_balanced), len(pvt_maps_balanced) # In[ ]: # PvT # In[51]: pvt_maps_tiny = pvt_maps_balanced.loc[pvt_maps_balanced['total size'] <= 18000] pvt_maps_tiny # In[52]: pvt_maps_small = pvt_maps_balanced.loc[(pvt_maps_balanced['total size'] > 18000) & (pvt_maps_balanced['total size'] < 20000)] pvt_maps_small #PvTList = ['Antiga_Shipyard', 'Cloud_Kingdom_LE', 'Kairos_Junction_LE', 'Fracture_LE', 'Korhal_Floating_Island','Backwater_LE', 'Cyber_Forest_LE', 'Dreamcatcher_LE', 'Interloper_LE','Ulrena', 'Entombed_Valley', 'Dusk_Towers', 'Zen_LE', 'Waystation', 'Whirlwind_LE'] # In[69]: pvt_maps_medium = pvt_maps_balanced.loc[(pvt_maps_balanced['total size'] > 20000) & (pvt_maps_balanced['total size'] < 23000)] pvt_maps_medium # In[81]: pvt_maps_large = pvt_maps_balanced.loc[(pvt_maps_balanced['total size'] > 23000) & (pvt_maps_balanced['total size'] < 26000)] pvt_maps_large # In[71]: pvt_maps_huge = pvt_maps_balanced.loc[(pvt_maps_balanced['total size'] > 26000)] pvt_maps_huge # ZvP # In[72]: zvp_maps_tiny = zvp_maps_balanced.loc[zvp_maps_balanced['total size'] <= 18000] zvp_maps_tiny # In[73]: zvp_maps_small = zvp_maps_balanced.loc[(zvp_maps_balanced['total size'] > 18000) & (zvp_maps_balanced['total size'] < 20000)] zvp_maps_small # In[74]: zvp_maps_medium = zvp_maps_balanced.loc[(zvp_maps_balanced['total size'] > 20000) & (zvp_maps_balanced['total size'] < 23000)] zvp_maps_medium # In[75]: zvp_maps_large = zvp_maps_balanced.loc[(zvp_maps_balanced['total size'] > 23000) & (zvp_maps_balanced['total size'] < 26000)] zvp_maps_large # In[76]: zvp_maps_huge = zvp_maps_balanced.loc[(zvp_maps_balanced['total size'] > 26000)] zvp_maps_huge # TvZ # In[65]: tvz_maps_tiny = tvz_maps_balanced.loc[tvz_maps_balanced['total size'] <= 18000] tvz_maps_tiny # In[67]: tvz_maps_small = tvz_maps_balanced.loc[(tvz_maps_balanced['total size'] > 18000) & (tvz_maps_balanced['total size'] < 20000)] tvz_maps_medium # In[82]: tvz_maps_medium = tvz_maps_balanced.loc[(tvz_maps_balanced['total size'] > 20000) & (tvz_maps_balanced['total size'] < 23000)] tvz_maps_medium.sort_values("Map") # In[83]: tvz_maps_large = tvz_maps_balanced.loc[(tvz_maps_balanced['total size'] > 23000) & (tvz_maps_balanced['total size'] < 26000)] tvz_maps_large # In[80]: tvz_maps_huge= tvz_maps_balanced.loc[(tvz_maps_balanced['total size'] > 26000)] tvz_maps_huge # Wildcard Maps # In[22]: wildcard_maps.loc[wildcard_maps['total size'] < 18000].sort_values("Map") # In[75]: wildcard_maps.loc[(wildcard_maps['total size'] > 18000) & (wildcard_maps['total size'] < 21000)].sort_values("Map") # In[76]: wildcard_maps.loc[(wildcard_maps['total size'] > 21000) & (wildcard_maps['total size'] < 24000)].sort_values("Map") # In[77]: wildcard_maps.loc[wildcard_maps['total size'] > 24000].sort_values("Map") # In[ ]: full_maps_df #

Map Selector Function

# In[23]: ZvZList # In[3]: PvTList = ['Antiga_Shipyard', 'Nimbus_LE', 'Cloud_Kingdom_LE', 'Kairos_Junction_LE', 'Fracture_LE', 'Dasan_Station_LE', 'Cyber_Forest_LE', 'Dreamcatcher_LE', 'Interloper_LE','Ulrena', 'Dusk_Towers', 'Zen_LE', 'Waystation', 'Heavy_Rain_LE'] TvZList = ['Blistering_Sands', "Dreamcatcher_LE", 'Daybreak_LE', "Ulrena", 'Korhal_Sky_Island', 'Bridgehead_LE', "Entombed_Valley", "Acropolis_LE", 'Cerulean_Fall_LE', 'Catallena_LE', "Coda_LE", 'Polar_Night_LE', 'Acolyte_LE', 'Frost_LE', 'Dash_and_Terminal_LE', 'Merry_Go_Round_LE'] ZvPList = ['Moonlight_Madness_LE', 'Shakuras_Plateau', 'Fracture_LE', "Xel'Naga_Caverns", 'Acid_Plant_LE', 'Coda_LE', 'Echo_LE', 'Redshift_LE', 'Expedition_Lost','Heavy_Rain', 'Interloper_LE', 'Foxtrot_Labs_LE', 'King_Sejong_Station_LE', 'Sequencer_LE', 'Cactus_Valley_LE', 'Invader_LE'] TvTList = ['Abiogenesis_LE', "Arid_Plateau", 'Blood_Boil_LE', 'Dasan_Station_LE', 'Desert_Oasis', "Defender's_Landing_LE", 'Fractured_Glacier', 'Howling_Peak', 'Incineration_Zone', 'Klontas_Mire', 'Korhal_Carnage_Knockout_LE', 'Lost_Temple', 'Nerazim_Crypt', 'Newkirk_Precinct_TE', 'Odyssey_LE', 'Prion_Terraces'] PvPList = ['16-bit_LE', 'Abyssal_Caverns', 'Backwater_Gulch', 'Battle_on_the_Boardwalk_LE', 'Cerulean_Fall_LE', 'Ephemeron_LE', 'Jungle_Basin', 'Iron_Fortress_LE', 'Korhal_City', 'Lerilak_Crest', 'Metalopolis', 'New_Repugnancy_LE', 'Shakuras_Plateau', 'Star_Station_TE', 'Steppes_of_War', 'Yeonsu_LE'] ZvZList = ['Apotheosis_LE', 'Backwater_Gulch', 'Blueshift_LE', 'Cloud_Kingdom_LE', 'Darkness_Sanctuary_LE', 'Delta_Quadrant', 'Habitation_Station_LE', 'Inferno_Pools', 'Kulas_Ravine', 'Metropolis_LE', 'Moonlight_Madness_LE', 'New_Gettysburg_LE', 'Ruins_of_Seras', 'Scrap_Station', 'Secret_Spring', 'Slag_Pits'] len(sorted(ZvPList)) Exhibition1 = ['Blood Boil','New Gettysburg', 'Moonlight Madness', 'Invader'] PvTList2 = ['Antiga_Shipyard', 'Nimbus_LE', 'Cloud_Kingdom_LE', 'Kairos_Junction_LE', 'Fracture_LE', 'Dasan_Station_LE', 'Cyber_Forest_LE', 'Dreamcatcher_LE','Ulrena', 'Zen_LE'] AllMaps = ['Blood Boil', 'Desert Oasis', 'Orbital Shipyard', 'Moonlight Madness', 'Klontas Mire', 'New Gettysburg', 'Merry Go Round'] #

Version 1

# In[4]: def mapselector(listchoice, BoX): maplist = [] parentlist = listchoice.copy() for i in range(BoX): map_option = random.choice(parentlist) maplist.append(map_option) parentlist.remove(map_option) return maplist mapselector(Exhibition1, 4) #

Version 2

# In[6]: def mapselector2(listchoice, BoX): i = 0 vetos_remaining = 3 maplist = [] parentlist = listchoice.copy() while (i < BoX) & (vetos_remaining > 0): map_option = random.choice(parentlist) parentlist.remove(map_option) print(f"Map Choice: {map_option}") playerchoice = input() if playerchoice == "Stay": maplist.append(map_option) i += 1 else: vetos_remaining -= 1 while len(maplist) < BoX: map_option = random.choice(parentlist) parentlist.remove(map_option) maplist.append(map_option) return maplist mapselector2(PvTList2, 2) # In[4]: import random listy = [1,2,3] bro = random.shuffle(listy) bro #

Version 3

# In[8]: parentlist = PvPList parentlist # random.choice(parentlist) # In[9]: class VetoLogger: def __init__(self, Active, Vetoes): self.Active = True self.Vetoes = 3 P1 = VetoLogger(True, 3) P2 = VetoLogger(False, 3) def mapselector3(listchoice, BoX): i = 0 staycount = 0 maplist = [] parentlist = listchoice.copy() map_option = random.choice(parentlist) parentlist.remove(map_option) while i < BoX: if (P1.Vetoes > 0) & (P1.Active == True): print(f"P1: The map is {map_option}. You still have {P1.Vetoes} vetoes. Veto or Stay?") P1choice = input() if P1choice == "Veto": P1.Vetoes -= 1 map_option = random.choice(parentlist) parentlist.remove(map_option) P2.Active = True P1.Active = False staycount = 0 elif P1choice == "Stay": P2.Active = True P1.Active = False staycount += 1 else: print(f"P1 has no vetoes. Forcing Stay.") staycount += 1 P1.Active = False P2.Active = True if staycount > 1: print(f"added {map_option} to list") maplist.append(map_option) map_option = random.choice(parentlist) parentlist.remove(map_option) staycount = 0 i = len(maplist) if (P2.Vetoes > 0) & (P2.Active == True): print(f"P2: The map is {map_option}. You still have {P2.Vetoes} vetoes. Veto or Stay?") P2choice = input() if P2choice == "Veto": P2.Vetoes -= 1 map_option = random.choice(parentlist) parentlist.remove(map_option) P2.Active = False P1.Active = True staycount = 0 elif P2choice == "Stay": P2.Active = False P1.Active = True staycount += 1 else: print(f"P2 has no vetoes. Forcing Stay.") staycount += 1 P2.Active = False P1.Active = True if staycount > 1: print(f"added {map_option} to list") maplist.append(map_option) map_option = random.choice(parentlist) parentlist.remove(map_option) staycount = 0 i = len(maplist) return maplist mapselector3(PvTList, 3)