daily pastebin goal
1%
SHARE
TWEET

Hearthstone Economy Simulation Code

a guest Oct 10th, 2013 4,005 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. # By Hamlet, 10/10/2013
  2. # as attachment to this post:
  3. # http://iam.yellingontheinternet.com/2013/10/10/from-dust-to-dust-the-economy-of-hearthstone/
  4.  
  5. import random
  6. import math
  7.  
  8. #throughout:
  9. #  0/1/2/3 = common/rare/epic/legendary
  10. #  0/1 = normal/gold
  11.  
  12. #Parameters
  13.  
  14. #Disenchant[rarity][gold]
  15. Disenchant = [[5, 50], [20, 100], [100, 400], [400, 1600]]  
  16. Craft = [[40, 400], [100, 800], [400, 1600], [1600, 3200]]
  17.  
  18. #NeutralCardCount = [40, 36, 10, 24]
  19. #ClassCardCount = [6, 5, 3, 1] #Currently same for each class
  20. TotalCardCount = [94, 81, 37, 33]
  21.  
  22. Required = [2,2,2,1]
  23.  
  24.  
  25. RarityDist = [0.21, 0.04, 0.01] #set rarity of rare/epic/legendary
  26.  
  27. RarityDist = [1-sum(RarityDist)] + RarityDist #insert common
  28. CumulativeDist = [0]*3 #chance that rarity is <= [index]
  29. for x in range(3):
  30.     CumulativeDist[x] = sum(RarityDist[:x+1])
  31.  
  32. GoldFrequency = [0.02, 0.05, 0.05, 0.05]
  33.  
  34. #Options
  35.  
  36. #Size of card subset we're trying to complete
  37. DesiredCardCount = TotalCardCount
  38. # [46, 41, 13, 1] #
  39. # [94, 81, 37, 0] #
  40.  
  41. ForceDisenchant = 0     # 1 = Disenchant all cards outside desired set
  42.  
  43. RequireGold = 0         # 1 = Collect only golden cards
  44.  
  45. #Craft cost of desired cards
  46. TotalDustNeeded = sum([DesiredCardCount[x]*Craft[x][RequireGold]*Required[x] for x in range(4)])
  47. CardsNeeded = [DesiredCardCount[i]*Required[i] for i in range(4)]
  48.  
  49. #Stats collected
  50.  
  51. Runs = 100
  52.  
  53. PacksOpenedRecord = [0]*Runs
  54. EndingDustRecord = [0]*Runs
  55. FoundPercentRecord = [[0]*4 for i in range(Runs)] # FPR[run][rarity]
  56.  
  57. #simulation
  58.        
  59. for Run in range(Runs): #begin each run
  60.     PacksOpened = 0
  61.     DustNeeded = TotalDustNeeded    #Craft value of remaining cards this run
  62.     FoundCardValue = 0
  63.     FoundCards = [0]*4
  64.     CardsCollected = [[[0]*2 for i in range(j)] for j in TotalCardCount]
  65.     #CardsCollected[rarity][index][gold]
  66.  
  67.     while DustNeeded > 0: #open packs
  68.         PacksOpened += 1
  69.         for Card in range(5): #create cards
  70.             Rarity = 3
  71.             Gold = 0
  72.             CardIndex = 0
  73.            
  74.             rand = random.random()
  75.             for x in range(3):  #determine rarity
  76.                 if rand < CumulativeDist[x]:
  77.                     Rarity = x
  78.                     break
  79.             if random.random() < GoldFrequency[Rarity]:
  80.                 Gold = 1
  81.             CardIndex = random.randrange(TotalCardCount[Rarity])
  82.             CardsCollected[Rarity][CardIndex][Gold] += 1
  83.  
  84.             #disenchant card if not needed
  85.  
  86.             if (RequireGold and Gold == 0):  #if disenchanting any non-gold
  87.                 CardsCollected[Rarity][CardIndex][Gold] -= 1
  88.                 DustNeeded -= Disenchant[Rarity][Gold]
  89.                
  90.             elif sum(CardsCollected[Rarity][CardIndex]) > Required[Rarity]:
  91.                 #extra card
  92.                 if CardsCollected[Rarity][CardIndex][1] > 0: #disenchant gold
  93.                     CardsCollected[Rarity][CardIndex][1] -= 1
  94.                     DustNeeded -= Disenchant[Rarity][1]
  95.                 else:
  96.                     CardsCollected[Rarity][CardIndex][0] -= 1
  97.                     DustNeeded -= Disenchant[Rarity][0]
  98.  
  99.             elif CardIndex < DesiredCardCount[Rarity]:  #card we care about
  100.                 DustNeeded -= Craft[Rarity][RequireGold] #reduce remaining goal
  101.                 FoundCardValue += Craft[Rarity][RequireGold]
  102.                 FoundCards[Rarity] += 1
  103.                
  104.             elif ForceDisenchant:   #Disenchanting all unwanted cards
  105.                 CardsCollected[Rarity][CardIndex][Gold] -= 1
  106.                 DustNeeded -= Disenchant[Rarity][Gold]
  107.  
  108.     #Record once we're done            
  109.     PacksOpenedRecord[Run] = PacksOpened
  110.     EndingDustRecord[Run] = TotalDustNeeded - FoundCardValue
  111.     FoundPercentRecord[Run] = map(lambda x,y: 0 if y==0 else x/float(y),FoundCards,CardsNeeded)
  112.        
  113. # Outputs
  114.  
  115. MeanPacks = sum(PacksOpenedRecord)/float(Runs)
  116. MeanDust = sum(EndingDustRecord)/float(Runs)
  117. MeanFoundPercent = [0]*4
  118. for Run in range(Runs):
  119.     MeanFoundPercent = map(lambda x,y: x+y, MeanFoundPercent, FoundPercentRecord[Run])
  120. MeanFoundPercent = [x/float(Runs) for x in MeanFoundPercent]
  121. VarPacks = [(x-MeanPacks)**2 for x in PacksOpenedRecord]
  122. VarDust = [(x-MeanDust)**2 for x in EndingDustRecord]
  123. StdDevPacks = math.sqrt(sum(VarPacks)/float(Runs))
  124. StdDevDust = math.sqrt(sum(VarDust)/float(Runs))
  125.  
  126. print("Runs", Runs, "Desired Card Set", DesiredCardCount, "Gold?",
  127.             RequireGold, "Force DE", ForceDisenchant)
  128. print("Packs Opened", MeanPacks, StdDevPacks)
  129. print("Dust used to craft", MeanDust, StdDevDust, MeanDust/float(TotalDustNeeded))
  130. print("% cards found", MeanFoundPercent)
RAW Paste Data
Top