Advertisement
Guest User

abyss.py

a guest
Aug 29th, 2020
104
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 8.30 KB | None | 0 0
  1. # exalted.py
  2.  
  3.  
  4. import random
  5. from collections import Counter
  6.  
  7.  
  8. # type player = nonce * skill * trophies
  9.  
  10.  
  11. def init_players(num_players, starting_trophies):
  12.     players = [init_player(starting_trophies) for _ in range(num_players)]
  13.     return sorted(players)
  14.  
  15.  
  16. def init_player(starting_trophies):
  17.     return (
  18.         random.random(),
  19.         random.gauss(0, 1),
  20.         starting_trophies,
  21.     )
  22.  
  23.  
  24. def get_trophies(player):
  25.     _nonce, _skill, trophies = player
  26.     return trophies
  27.  
  28.  
  29. def get_player_with_updated_trophies(player, change):
  30.     nonce, skill, trophies = player
  31.     return nonce, skill, trophies + change
  32.  
  33.  
  34. def get_skill(player):
  35.     _nonce, skill, _trophies = player
  36.     return skill
  37.  
  38.  
  39. REQS = [
  40.     (0, "forbidden"),
  41.     (100, "sinful-1"),
  42.     (300, "sinful-2"),
  43.     (500, "sinful-3"),
  44.     (700, "agony-1"),
  45.     (900, "agony-2"),
  46.     (1200, "agony-3"),
  47.     (1500, "lotus"),
  48.     (2000, "nirvana"),
  49. ]
  50.  
  51.  
  52. def get_league(player):
  53.     trophies = get_trophies(player)
  54.     result = None
  55.     for required_trophies, league in REQS:
  56.         if trophies >= required_trophies:
  57.             result = league
  58.         # can also break on else
  59.     return result
  60.  
  61.  
  62. def _test_get_league():
  63.     assert get_league(init_player(1200)) == "agony-3"
  64.     assert get_league(init_player(0)) == "forbidden"
  65.     assert get_league(init_player(1499)) == "agony-3"
  66.     assert get_league(init_player(2000)) == "nirvana"
  67.     assert get_league(init_player(4000)) == "nirvana"
  68.  
  69.  
  70. def divide_players_into_leagues(players):
  71.     leagues = {}
  72.     for p in players:
  73.         league_name = get_league(p)
  74.         league_players = leagues.get(league_name, [])
  75.         leagues[league_name] = league_players
  76.         league_players.append(p)
  77.     return leagues
  78.  
  79.  
  80. def _test_divide_players_into_leagues():
  81.     players = [
  82.         init_player(1200),
  83.         init_player(0),
  84.         init_player(1499),
  85.         init_player(2000),
  86.         init_player(4000),
  87.     ]
  88.     expected = {
  89.         "agony-3": [players[0], players[2]],
  90.         "forbidden": [players[1]],
  91.         "nirvana": [players[3], players[4]],
  92.     }
  93.     assert divide_players_into_leagues(players) == expected
  94.  
  95.  
  96. def even_distribution_algo(n, bucket_size):
  97.     # find number of buckets
  98.     num_buckets = int(n / bucket_size) + (1 if n % bucket_size > 0 else 0)
  99.     # find gap to all buckets full
  100.     gap = num_buckets * bucket_size - n
  101.     # init full buckets
  102.     buckets = [bucket_size] * num_buckets
  103.     # round robin subtract from each bucket until gap is accounted for
  104.     for i in range(gap):
  105.         j = i % num_buckets
  106.         buckets[j] -= 1
  107.     buckets = list(reversed(buckets))
  108.     return buckets
  109.  
  110.  
  111. def _test_even_distribution_algo():
  112.     assert even_distribution_algo(43, 20) == [15, 14, 14]
  113.     assert even_distribution_algo(1413, 20) == [20] * 64 + [19] * 7
  114.  
  115.  
  116. def shuffled(l):
  117.     result = l[:]
  118.     random.shuffle(result)
  119.     return result
  120.  
  121.  
  122. def randomly_partition_by_ratio_list(s, distribution):
  123.     assert len(s) == sum(distribution)
  124.     l = shuffled(s)
  125.     result = []
  126.     for size in distribution:
  127.         if size > 0:
  128.             result.append(l[-size:])
  129.             del l[-size:]
  130.         else:
  131.             assert size == 0
  132.             result.append([])
  133.     return result
  134.  
  135.  
  136. def flatten(l):
  137.     return [element for sublist in l for element in sublist]
  138.  
  139.  
  140. def _test_randomly_partition_by_ratio_list():
  141.     substrate = [0, 1, 2, 3, 4, 5, 6, 7]
  142.     distribution = [4, 0, 1, 3]
  143.     result = randomly_partition_by_ratio_list(substrate, distribution)
  144.     assert [len(l) for l in result] == distribution
  145.     assert set(flatten(result)) == set(substrate)
  146.  
  147.  
  148. def divide_set_into_brackets(s):
  149.     distribution = even_distribution_algo(len(s), 20)
  150.     return randomly_partition_by_ratio_list(s, distribution)
  151.  
  152.  
  153. def bracketize(players):
  154.     leagues = divide_players_into_leagues(players)
  155.     result = []
  156.     for league_name in leagues:
  157.         s = leagues[league_name]
  158.         brackets = divide_set_into_brackets(s)
  159.         for bracket in brackets:
  160.             result.append((league_name, bracket))
  161.     return result
  162.  
  163.  
  164. def rank_players(players):
  165.     # just use their raw skill rating, higher is better
  166.     return list(reversed(sorted(players, key=get_skill)))
  167.  
  168.  
  169. rewards_table = None
  170.  
  171.  
  172. def init_rewards_table():
  173.     global rewards_table
  174.     table = {
  175.         "forbidden": [100] * 7 + [50] * 5 + [0] * 8,
  176.         "sinful": [150] * 5 + [100] * 3 + [0] * 4 + [-75] * 3 + [-100] * 5,
  177.         "agony": [200] * 3 + [100] * 3 + [0] * 6 + [-75] * 3 + [-150] * 5,
  178.         "lotus": [100] * 3 + [0] * 7 + [-100] * 10,
  179.         "nirvana": [100] * 5 + [-200] * 15,
  180.     }
  181.     assert all([len(l) == 20 for l in table.values()])
  182.     # For brackets with fewer than 20 players, chop values from the rewards
  183.  
  184.     def chop(base_list, indices):
  185.         for i in indices:
  186.             base_list[i] = None
  187.         return [e for e in base_list if e is not None]
  188.     chopping_order = [0, 19, 9, 15, 4] + \
  189.         [12, 16, 13, 8, 1, 17, 3, 6, 18, 5, 14, 10, 7, 11, 2]
  190.     rewards_table = {}
  191.     for bracket_size in range(1, 21):
  192.         rewards_table[bracket_size] = {}
  193.         for league_name in table:
  194.             base_list = table[league_name][:]
  195.             chop_n = 20 - bracket_size
  196.             new_list = chop(base_list, chopping_order[:chop_n])
  197.             rewards_table[bracket_size][league_name] = new_list
  198.  
  199.  
  200. def stringify_rewards_table():
  201.     rows = []
  202.     for bracket_size in rewards_table:
  203.         for league_name in rewards_table[bracket_size]:
  204.             bracket_rewards = rewards_table[bracket_size][league_name]
  205.             for i in range(len(bracket_rewards)):
  206.                 rank = i + 1
  207.                 rows.append((bracket_size, league_name,
  208.                              rank, bracket_rewards[i]))
  209.     rows = sorted(rows)
  210.     return "\n".join([", ".join([str(e) for e in row]) for row in rows])
  211.  
  212.  
  213. def get_player_rewards(league, ranked_players):
  214.     name_mapping = {
  215.         "forbidden": "forbidden",
  216.         "sinful-1": "sinful",
  217.         "sinful-2": "sinful",
  218.         "sinful-3": "sinful",
  219.         "agony-1": "agony",
  220.         "agony-2": "agony",
  221.         "agony-3": "agony",
  222.         "lotus": "lotus",
  223.         "nirvana": "nirvana",
  224.     }
  225.     if rewards_table is None:
  226.         _init_rewards_table()
  227.     league = name_mapping[league]
  228.     bracket_size = len(ranked_players)
  229.     return rewards_table[bracket_size][league]
  230.  
  231.  
  232. def run_single_bracket(league, players):
  233.     ranked_players = rank_players(players)
  234.     result = []
  235.     for reward, player in zip(get_player_rewards(league, ranked_players), ranked_players):
  236.         result.append(get_player_with_updated_trophies(player, reward))
  237.     return result
  238.  
  239.  
  240. def run_abyss_cycle(players):
  241.     brackets = bracketize(players)
  242.     all_updated_players = []
  243.     for league_name, bracket_players in brackets:
  244.         updated_players = run_single_bracket(league_name, bracket_players)
  245.         all_updated_players += updated_players
  246.     return sorted(all_updated_players)
  247.  
  248.  
  249. def stringify_player(player):
  250.     skill = get_skill(player)
  251.     trophies = get_trophies(player)
  252.     league = get_league(player)
  253.     return f"player, {skill}, {trophies}, {league}"
  254.  
  255.  
  256. def stringify_players(players):
  257.     return "\n".join([stringify_player(p) for p in players])
  258.  
  259.  
  260. def get_leagues_summary(players):
  261.     league_only = [get_league(p) for p in players]
  262.     return Counter(league_only)
  263.  
  264.  
  265. def stringify_summary(c):
  266.     leagues = [league_name for _, league_name in REQS]
  267.     row = [c[league_name] for league_name in leagues]
  268.     return ", ".join([str(n) for n in row])
  269.  
  270.  
  271. if __name__ == "__main__":
  272.     _test_get_league()
  273.     _test_even_distribution_algo()
  274.     _test_divide_players_into_leagues()
  275.     _test_randomly_partition_by_ratio_list()
  276.     # Audit the rewards table
  277.     with open("rewards_table.csv", "w") as f:
  278.         init_rewards_table()
  279.         f.write(stringify_rewards_table())
  280.     random.seed(102750340)
  281.     players = init_players(10000, 1200)
  282.     # print(stringify_players(players))
  283.     with open("exalted_summaries.csv", "w") as f:
  284.         for _ in range(500):
  285.             players = run_abyss_cycle(players)
  286.             summary = get_leagues_summary(players)
  287.             s = stringify_summary(summary)
  288.             print(s)
  289.             f.write(s)
  290.             f.write("\n")
  291.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement