Skip to content

Instantly share code, notes, and snippets.

@dantaeyoung
Last active July 6, 2018 06:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dantaeyoung/79e483c6c0a6671b7cbf9ed156520cf0 to your computer and use it in GitHub Desktop.
Save dantaeyoung/79e483c6c0a6671b7cbf9ed156520cf0 to your computer and use it in GitHub Desktop.
process to generate all possible studio combinations and to rank them by trying to make the lowest ranking the highest
import random, sys, itertools, math, statistics
PEOPLES_CHOICES = [
['K','D','C','N','A','E','H','I','L','M'],
['I','H','J','E','C','F','D','N','K','A'],
['N','M','D','L','A','K','J','D','G','I'],
['D','N','K','L','M','J','G','I','H','F'],
['D','K','N','F','B','G','J','E','C','I'],
['D','N','K','I','H','A','E','C','F','M']
]
# generate all possible studio space combos -- for example, a K studio can only exist with an L studio
# (order doesn't matter)
def gencombos():
s1 = ["A"]
s2 = ["KL", "BC", "GH"]
s3 = ["D"]
s4 = ["IJ", "MN", "EF"]
combos = []
for this1 in s1:
for this2 in s2:
for this3 in s3:
for this4 in s4:
combos.append(this1 + this2 + this3 + this4)
return combos
GENCOMBOS = gencombos()
# compare two strings as sets (order doesn't matter)
def setcmp(a, b):
return set(a) == set(b)
def is_studiocombo_valid(cs):
if(sum([setcmp(cs, thisg) for thisg in GENCOMBOS]) == 0):
# chromosome isn't a valid studio possibility because this studio combo doesn't match any of the possible studio combos
return false
# calculate a studio layout score based on each person's choice
def studiocombo_rank_function(cs):
peoples_rank = []
for i, thisc in enumerate(cs):
if thisc in PEOPLES_CHOICES[i]:
rank = PEOPLES_CHOICES[i].index(thisc)
else:
rank = 20 # if the choice isn't part of someone's top 10 choices, set it as their 20th choice (aka really bad)
peoples_rank.append(rank)
# each rank adds 10**rank to the score.. so if you get your second choice, you get 10**2 points
# this way the GA is incentivized to minimize the worst rank as much as possible
# because someone having their 5th choice is literally 10 times worse than someone having their 4th choice
total_rank_base_10 = 0
for pr in peoples_rank:
total_rank_base_10 += 10**pr
return total_rank_base_10
def pretty_print_combo(combo):
peoples_rank = []
for i, thisc in enumerate(combo):
if thisc in PEOPLES_CHOICES[i]:
rank = PEOPLES_CHOICES[i].index(thisc)
else:
rank = 20 # if the choice isn't part of someone's top 10 choices, set it as their 20th choice
peoples_rank.append(rank)
for i, r in enumerate(zip(combo, peoples_rank)):
print("the " + ordinal(i + 1) + " person gets " + str(r[0]) + ", which is their " + ordinal(r[1] + 1) + " choice")
#from https://codereview.stackexchange.com/questions/41298/producing-ordinal-numbers
def ordinal(num):
SUFFIXES = {1: 'st', 2: 'nd', 3: 'rd'}
# I'm checking for 10-20 because those are the digits that
# don't follow the normal counting scheme.
if 10 <= num % 100 <= 20:
suffix = 'th'
else:
# the second parameter is a default.
suffix = SUFFIXES.get(num % 10, 'th')
return str(num) + suffix
########
if __name__ == '__main__':
# generate all the possible studio distributions
allgencombos = list(itertools.chain.from_iterable(
[[''.join(p) for p in itertools.permutations(thisgc)] for thisgc in GENCOMBOS]
))
# calculate all of their scores based on each person's choice
allgencombos_and_scores = [(studiocombo_rank_function(agc), agc) for agc in allgencombos]
# sort them by scores, ascending
sorted_combos = sorted(allgencombos_and_scores, key=lambda x: x[0])
# print the top 20 best scores
for i, sc in enumerate(sorted_combos[:20]):
print("========== " + ordinal(i + 1) + " best: ==== " + sc[1])
pretty_print_combo(sc[1])
print(" total score (smaller is better): " + str(sc[0]))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment