Skip to content

Instantly share code, notes, and snippets.

@abe33
Last active July 21, 2018 12:03
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save abe33/db339fba4df0f4147c35e3b7738a8ad5 to your computer and use it in GitHub Desktop.
Save abe33/db339fba4df0f4147c35e3b7738a8ad5 to your computer and use it in GitHub Desktop.
cool_map_list.py
from random import shuffle
# First thing first, using global should be avoided at all costs, I won't
# explain all the reasons, there's a lot of litterature on that topic.
# So, let's start by removing these globals everywhere and look for
# a way to replace them
# These lists really look like externalities to me, this should problably
# be passed as arguments to the program, or with some other kind of setup,
# but as is, Ill just past them as constant to make it explicit that we won't
# touch them.
SPLAT_ZONES_MAPS = [
"Arowana Mall",
"Blackbelly Skatepark",
"Camp Triggerfish",
"Goby Arena",
"Humpback Pump Track",
"Inkblot Art Academy",
"Kelp Dome",
"MakoMart",
"Manta Maria",
"Moray Towers",
"Musselforge Fitness",
"New Albacore Hotel",
"Piranha Pit",
"Port Mackerel",
"Shellendorf Institute",
"Snapper Canal",
"Starfish Mainstage",
"Sturgeon Shipyard",
"The Reef",
"Wahoo World",
"Walleye Warehouse"
]
TOWER_CONTROL_MAPS = [
"Manta Maria",
"Musselforge Fitness",
"New Albacore Hotel",
"Snapper Canal",
"Starfish Mainstage",
"Sturgeon Shipyard",
"Wahoo World",
"Walleye Warehouse"
]
RAINMAKER_MAPS = [
"Humpback Pump Track",
"Inkblot Art Academy",
"Kelp Dome",
"MakoMart",
"Manta Maria",
"New Albacore Hotel",
"Piranha Pit",
"Sturgeon Shipyard"
]
CLAM_BLITZ_MAPS = [
"Arowana Mall",
"Goby Arena",
"Moray Towers",
"New Albacore Hotel",
"Port Mackerel",
"Shellendorf Institute",
"The Reef",
"Wahoo World"
]
MODES = [
"Tower Control",
"Rainmaker",
"Clam Blitz"
]
# IIUC the process is as follow:
# - given the amount of rounds provided as input
# - given the lists above for maps/modes
# - for each games of each rounds we're gonna pick a mode
# (odd=TC/RM/CB, even=SZ)
# - the mode is picked in order in a list of three, used mode are placed at the # end of the list once used
# - the first map that was not last used in one of the other modes is picked
# from the corresponding pool and removed from it, once empty, these lists are
# refilled from the used lists. As far as I understand the current code,
# there's an hypothetical risk of getting the same map in a single round for
# the same mode (if refill/shuffle occurs between the two picks) as we're not
# checking the last map for the same mode
# - with that we generate strings (that's the easy part so I won't expand here)
# - modes list is shuffled only once at start, so the order is then fixed for # all rounds (is that intended? I'll assume so)
# - maps lists are shuffled everytime they are refilled
#
# Initially:
# - refresh_maplist takes care of refills
# - generate_maps takes care of iterating to generate the strings.
#
# The first thing I'll do is probably to create iterators to take care of
# rotating and shuffling the lists. The biggest use is that we can manage the
# refill/cycling/shuffle stuff in a more elegant way. The code that will consume
# the modes/maps don't need to know about the refill/shuffle logic at all. It
# makes it easier to reuse/change the code as the need changes. Compared to the
# initial version it won't require specific code for each lists neither.
# Here is an infinite generator that takes the modes list and iterates over
# that list indefinitely. Calling it just gives us an iterator to use later.
def get_mode_iterator(modes):
num = 0
# I'm storing that just to save a call to len on every iteration
num_modes = len(modes)
# looping indefinitely
while True:
yield modes[num % num_modes]
num += 1
# Calling the generator gives us an iterator object.
modes = get_mode_iterator(MODES)
# Calling next() with the iterator will return the next mode
# for i in range(10):
# print(next(modes))
# For maps we're also going to use an infinite generator, except we're going
# to create one iterator for each modes and shuffle when reaching the end of
# the list
def get_map_iterator(maps):
num = 0
# same as previously
num_maps = len(maps)
while True:
yield maps[num % num_maps]
num += 1
# when reaching the end, we shuffle the list
if num == num_maps:
shuffle(maps)
splat_zones_maps = get_map_iterator(SPLAT_ZONES_MAPS)
tower_control_maps = get_map_iterator(TOWER_CONTROL_MAPS)
rainmaker_maps = get_map_iterator(RAINMAKER_MAPS)
clam_blitz_maps = get_map_iterator(CLAM_BLITZ_MAPS)
# Same thing here, we can call next over and over again to get a different
# map each time
# for i in range(20):
# print(next(clam_blitz_maps))
# Now that we have our iterators, we can store that in a dict so that when
# we have the name of a mode we can get the corresponding maps list
maps_for_mode = {
"Splat Zones": splat_zones_maps,
"Tower Control": tower_control_maps,
"Rainmaker": rainmaker_maps,
"Clam Blitz": clam_blitz_maps,
}
# Ok, next step, now we have our maps and modes iterators, we need a function
# to iterate over maps while excluding some of them
def next_map(iterator, excluded):
map = next(iterator)
while map in excluded:
map = next(iterator)
return map
# That's how one use that function
# for i in range(20):
# print(next_map(clam_blitz_maps, ["Moray Towers"]))
# Now I'll just define a few utilities to get rid of the formatting
# in strings and simple operations
def title(str):
return "\n**{}**\n".format(str)
def list_item(str, bullet):
return "{}) {}".format(bullet, str)
def mode_on_map(mode, map):
return "{} on {}".format(mode, map)
def is_odd(value):
return value % 2 != 0
# Let's get to some more concrete stuff, the logic to build a round
# is the same every time, so we can make a function out of itself.
# To make it simple, this function will just return the strings in a list
# so that we can just concat the output to our printables
# For the sake of simplicity I'll use a ban list for the round, so that each
# picked map is excluded from the possible picks. Depending on the exact
# exclusion logic this can be handled really differently
def round(bo_x):
ban_list = []
output = []
for game in range(bo_x):
# mode is either SZ or the next mode depending on the game
# here game is 0-indexed so we check oddity
if is_odd(game):
mode = "Splat Zones"
else:
mode = next(modes)
# gets our next map for that mode
map = next_map(maps_for_mode[mode], ban_list)
# creates and appends the output string
output.append(list_item(mode_on_map(mode, map), game + 1))
# bans that map
ban_list.append(map)
return output
# Now that we have our round function we can rewrite the generate_maps
# function.
# Same thing than with round, we'll return a list of strings
def generate_maps(rounds, bo_x, title_template):
output = []
for r in range(rounds):
output.append(title(title_template.format(r + 1)))
output = output + round(bo_x)
return output
# Typical python startup call
def main():
# Now we're at the point we need to gather inputs and do the real job
bo3_rounds_amount = int(input("How many Bo3 rounds is there? "))
bo5_rounds_amount = int(input("How many Bo5 rounds is there? "))
bo7_rounds_amount = int(input("How many Bo7 rounds is there? "))
print("{} Bo3 rounds, {} Bo5 rounds & {} Bo7 rounds".format(bo3_rounds_amount, bo5_rounds_amount, bo7_rounds_amount))
printables = generate_maps(bo3_rounds_amount, 3, "GROUPS ROUND {}") + generate_maps(bo5_rounds_amount, 5, "BRACKET ROUND {}") + generate_maps(bo7_rounds_amount, 7, "GRAND F{}NAL")
for line in printables:
print(line)
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment