Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/env python
- #
- # Runs a simulation to estimate how many packs you'll have to open before you
- # can dust any one card in Magic Arena's new crafting model.
- #
- # tl;dr, the rate of growth with respect to set size seems to be about
- # x^{3/4}. At the 95% confidence level, you'll need to open on average
- # e^{1.75} * n^{3/4} packs in order to be able to craft one rare.
- #
- # If we assume that the ratio of dust-to-craft in Vault is weighted the same
- # as Eternal (4 rares to 1), then you'll need to dust 4 rares for every rare you
- # craft, and that gives you a model of
- #
- # e^{1.935} * n^{3/4}
- #
- # As a concrete example, this means you'd have to open about 130 packs before
- # you can craft any one given rare in Ixalan (with 50 rares)
- #
- ##############################################################################
- import random
- import sys
- import pylab
- import numpy
- class CardSet:
- def __init__(self, size):
- self.size = size
- def get_card(self):
- return random.randrange(self.size)
- ##############################################################################
- class Collection:
- def __init__(self, set):
- self.set = set
- self.cards = [0] * set.size
- self.coll_size = 0
- self.hearthstone_dustables = 0
- self.arena_dustables = 0
- def add_card(self):
- card = self.set.get_card()
- self.cards[card] += 1
- self.hearthstone_dustables += 1
- if self.cards[card] > 4:
- self.arena_dustables += 1
- ##############################################################################
- def find_crossing(lst, value):
- try:
- for ix in range(len(lst)):
- if lst[ix] < value and lst[ix+1] >= value:
- return ix
- except IndexError:
- raise Exception("No crossing?")
- raise Exception("No crossing?")
- def run_simulation(size):
- card_set = CardSet(size)
- run_length = 1000
- n_runs = 100
- arena_averages = [0.0] * run_length
- arena_xx = [0.0] * run_length
- for _ in range(n_runs):
- arena = []
- coll = Collection(card_set)
- for i in range(run_length):
- coll.add_card()
- arena.append(coll.arena_dustables)
- arena_averages[i] += coll.arena_dustables
- arena_xx[i] += coll.arena_dustables ** 2
- # return the unlucky runs at the 2-stdev level through the normal
- # approximation. This is not ideal
- stdev = [((sxx / n_runs) - (sx / n_runs) ** 2) ** 0.5 for (sx, sxx) in zip(arena_averages, arena_xx)]
- return [(v / n_runs) - (2.0 * s) for (v, s) in zip(arena_averages, stdev)]
- if __name__ == '__main__':
- xs = []
- ys = []
- for i in xrange(100):
- x = random.randrange(10, 200)
- y = find_crossing(run_simulation(x), 1.0) # use 4.0 here to get the Eternal rate of dust-to-craft
- xs.append(float(x))
- print(x, y)
- ys.append(float(y))
- fit = numpy.polyfit(numpy.log(xs), numpy.log(ys), 1)
- print(fit)
- pylab.plot(numpy.log(xs), numpy.log(ys), 'go')
- pylab.plot([numpy.log(10), numpy.log(200)],
- [numpy.log(10) * fit[0] + fit[1], numpy.log(200) * fit[0] + fit[1]], 'k-')
- pylab.show()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement