Advertisement
Guest User

Untitled

a guest
Jan 17th, 2018
213
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 3.21 KB | None | 0 0
  1. #!/usr/bin/env python
  2. #
  3. # Runs a simulation to estimate how many packs you'll have to open before you
  4. # can dust any one card in Magic Arena's new crafting model.
  5. #
  6. # tl;dr, the rate of growth with respect to set size seems to be about
  7. # x^{3/4}. At the 95% confidence level, you'll need to open on average
  8. # e^{1.75} * n^{3/4} packs in order to be able to craft one rare.
  9. #
  10. # If we assume that the ratio of dust-to-craft in Vault is weighted the same
  11. # as Eternal (4 rares to 1), then you'll need to dust 4 rares for every rare you
  12. # craft, and that gives you a model of
  13. #
  14. # e^{1.935} * n^{3/4}
  15. #
  16. # As a concrete example, this means you'd have to open about 130 packs before
  17. # you can craft any one given rare in Ixalan (with 50 rares)
  18. #
  19. ##############################################################################
  20.  
  21. import random
  22. import sys
  23. import pylab
  24. import numpy
  25.  
  26. class CardSet:
  27.     def __init__(self, size):
  28.         self.size = size
  29.     def get_card(self):
  30.         return random.randrange(self.size)
  31.  
  32. ##############################################################################
  33.  
  34. class Collection:
  35.     def __init__(self, set):
  36.         self.set = set
  37.         self.cards = [0] * set.size
  38.         self.coll_size = 0
  39.         self.hearthstone_dustables = 0
  40.         self.arena_dustables = 0
  41.     def add_card(self):
  42.         card = self.set.get_card()
  43.         self.cards[card] += 1
  44.         self.hearthstone_dustables += 1
  45.         if self.cards[card] > 4:
  46.             self.arena_dustables += 1
  47.  
  48. ##############################################################################
  49.  
  50. def find_crossing(lst, value):
  51.     try:
  52.         for ix in range(len(lst)):
  53.             if lst[ix] < value and lst[ix+1] >= value:
  54.                 return ix
  55.     except IndexError:
  56.         raise Exception("No crossing?")
  57.     raise Exception("No crossing?")
  58.        
  59. def run_simulation(size):
  60.     card_set = CardSet(size)
  61.     run_length = 1000
  62.     n_runs = 100
  63.    
  64.     arena_averages = [0.0] * run_length
  65.     arena_xx = [0.0] * run_length
  66.  
  67.     for _ in range(n_runs):
  68.         arena = []
  69.         coll = Collection(card_set)
  70.         for i in range(run_length):
  71.             coll.add_card()
  72.             arena.append(coll.arena_dustables)
  73.             arena_averages[i] += coll.arena_dustables
  74.             arena_xx[i] += coll.arena_dustables ** 2
  75.  
  76.     # return the unlucky runs at the 2-stdev level through the normal
  77.     # approximation. This is not ideal
  78.     stdev = [((sxx / n_runs) - (sx / n_runs) ** 2) ** 0.5 for (sx, sxx) in zip(arena_averages, arena_xx)]
  79.     return [(v / n_runs) - (2.0 * s) for (v, s) in zip(arena_averages, stdev)]
  80.  
  81. if __name__ == '__main__':
  82.     xs = []
  83.     ys = []
  84.     for i in xrange(100):
  85.         x = random.randrange(10, 200)
  86.         y = find_crossing(run_simulation(x), 1.0) # use 4.0 here to get the Eternal rate of dust-to-craft
  87.         xs.append(float(x))
  88.         print(x, y)
  89.         ys.append(float(y))
  90.    
  91.     fit = numpy.polyfit(numpy.log(xs), numpy.log(ys), 1)
  92.     print(fit)
  93.     pylab.plot(numpy.log(xs), numpy.log(ys), 'go')
  94.     pylab.plot([numpy.log(10), numpy.log(200)],
  95.                [numpy.log(10) * fit[0] + fit[1], numpy.log(200) * fit[0] + fit[1]], 'k-')
  96.     pylab.show()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement