import random
import math
import numpy as np
from matplotlib import pyplot as plt
def simulator(startingStars,goForKeys,requiredProgress,numKeys,simNum):
# Show plots
showPlots = True
# Fragments required
fragments = 4
def getRandomList():
# 4 - shuffle, 5 - key, 15 - daily, 20 - double
if random.random() <= 1/3:
mainList = [3,4,5,15,20,0,0,0,0,0,0,0,0,0,0,0]
else:
mainList = [3,4,0,15,20,0,0,0,0,0,0,0,0,0,0,0]
random.shuffle(mainList)
return mainList
def pickPresent(days,mainList,showTwoList,showTwoIndex,dsFound,stars,doubleFound,dailySpecials,keys,firstKey,hasKey,skipped):
pickIndex = 0
showTwoPicked = False
# If any revealed presents are available
if(len(showTwoList) > 0):
# If any of the revealed presents are of interest
if sum(showTwoList) > 0:
# If shuffle is in the list of revealed presents and you have already found the daily special (and you're not going for keys), choose shuffle.
if (dsFound and (not goForKeys or (days > 32))) and 4 in showTwoList:
pickIndex = showTwoList.index(4)
showTwoPicked = True
# If shuffle is in the list (and daily hasn't been found)
elif 4 in showTwoList:
# If *only* shuffle is in the list, pick a random present from the main list
if goForKeys and 5 not in mainList:
pickIndex = showTwoList.index(4)
showTwoPicked = True
elif sum(showTwoList) == 4:
pickIndex = random.choice(range(len(mainList)))
# If not, pick the other reward of interest :)
else:
pickIndex = showTwoList.index(sum(showTwoList)-4)
showTwoPicked = True
# If shuffle is not in the list, pick the highest priority: Double > Daily > 14 Stars > Key
else:
pickIndex = showTwoList.index(max(showTwoList))
showTwoPicked = True
# If nothing good in show 2 list, pick random from main list
else:
pickIndex = random.choice(range(len(mainList)))
# If show 2 hasn't been picked, pick a random present
else:
pickIndex = random.choice(range(len(mainList)))
# If show 2 has been picked, get chosen reward and remove it from the show 2 list
if showTwoPicked:
res = showTwoList[pickIndex]
del showTwoList[pickIndex]
del showTwoIndex[pickIndex]
# Otherwise get chosen present from main list and remove it from the list
else:
res = mainList[pickIndex]
del mainList[pickIndex]
if goForKeys and not hasKey and skipped < 14:
skipped += 1
mainList = getRandomList()
hasKey = (5 in mainList)
# If reward is "show 2", pick 2 random rewards and add them to a separate list.
elif res == 3:
showTwoIndex = random.sample(range(len(mainList)),min(2,len(mainList)))
showTwoList = [mainList[showTwoIndex[x]] for x in range(len(showTwoIndex))]
del mainList[max(showTwoIndex)]
if len(showTwoIndex) > 1:
del mainList[min(showTwoIndex)]
stars += 3*doubleFound
# If reward is "shuffle", clear lists and get a brand new main list. Add stars and reset daily found.
elif res == 4:
showTwoList = []
showTwoIndex = []
mainList = getRandomList()
hasKey = (5 in mainList)
dsFound = False
stars += 10*doubleFound
# If result is "key"
elif res == 5:
# If going for calendar, add a full key, otherwise add a fragment instead (0.2 keys)
#keys += 1 if goForKeys else 1/fragments
# If you're going for keys, and you haven't picked up keys for 32 days yet (lol, never happens for free xD), then reset
# the lists and get a new one. This simulates waiting for the next day. Increment days to keep track of how many has passed.
if goForKeys and (days <= 32):
keys += 1
days += 1
showTwoList = []
showTwoIndex = []
mainList = getRandomList()
hasKey = (5 in mainList)
dsFound = False
# If you're not going for keys, add 10 stars to stars remaining instead (in addition to the fragment above)
else:
if firstKey:
keys += 1
firstKey = False
else:
keys += 1/fragments
#stars += 10
# If double is found, add additional key fragment and stars
if doubleFound == 2:
keys += 1/fragments
#stars += 10
# If "14 Stars" is picked, add 14 stars to stars remaining
elif res == 14:
stars += 14*doubleFound
# If "daily special" is found, add it and note that daily has been found.
elif res == 15:
dailySpecials += 1*doubleFound
dsFound = True
# If "double reward" is picked, double next reward.
if res == 20:
doubleFound = 2
else: # Otherwise reset double found
doubleFound = 1
return days, mainList,showTwoList,showTwoIndex,dsFound,stars,doubleFound,dailySpecials,keys,firstKey,hasKey,skipped
# Lists to track results
keys = []
dailies = []
matches = []
gpProgress = []
# Run through "simNum" number of simulations, simulating a full "playthrough" of the event each time (with your parameters)
for x in range(simNum):
# Print status every 10% :)
if x % round(simNum/10) == 0:
print(round((x/simNum)*100),"%")
# Number of starting stars
remainingStars = startingStars
# Variables to store results for this simulation
resDS = 0
resKeys = 0
resMatches = 0
# Other variables for this simulation
double = 1
days = 0
mainList = getRandomList()
hasKey = 5 in mainList
showTwoList = []
showTwoIndex = []
dsFound = False
firstKey = True
skipped = True
while remainingStars >= 10:
remainingStars -= 10
resMatches += 1
days,mainList,showTwoList,showTwoIndex,dsFound,remainingStars,double,resDS,resKeys,firstKey,hasKey,skipped = pickPresent(days,mainList,showTwoList,showTwoIndex,dsFound,remainingStars,double,resDS,resKeys,firstKey,hasKey,skipped)
dailies.append(resDS)
keys.append(math.floor(resKeys))
matches.append(resMatches)
gp = 0
for _ in range(resMatches):
gp += random.choice([1,2])
gpProgress.append(gp)
printStats = True
if printStats:
c = np.average(matches)
dailySpecials = np.average(dailies)
avgKeys = np.average(keys)
gp = np.average(gpProgress)
kU = [k for k in keys if k < numKeys]
kO = [k for k in keys if k >= numKeys]
cU = round(100*(len(kU)/len(keys)),2)
cO = round(100*(len(kO)/len(keys)),2)
gppU = [k for k in gpProgress if k < requiredProgress]
gppO = [k for k in gpProgress if k >= requiredProgress]
if len(gppU) == 0:
gppU.append(0)
if len(gppO) == 0:
gppO.append(0)
gpU = round(100*(len(gppU)/len(gpProgress)),2)
gpO = round(100*(len(gppO)/len(gpProgress)),2)
try:
maxM = requiredProgress - min(gpProgress)
except Exception:
maxM = 999
try:
avgM = round(requiredProgress - np.average(gppU),2)
except Exception:
avgM = 999
try:
meanM = int(requiredProgress-np.median(gppU))
except Exception:
meanM = 999
print("---------")
if goForKeys:
print("Average Totals (going for Keys):")
else:
print("Average Totals (going for Dailies):")
print("Starting stars:",startingStars)
print("Stars spent:",round(c*10,2),"(x" + str(round(c*10/startingStars,3)) + ")")
print()
print("Matches:",round(c,2))
print("Stars* per Match:",round(startingStars/c,2))
print()
print("Daily Specials:",round(dailySpecials,2))
print("Stars* per Daily Special:",round(startingStars/dailySpecials,2))
print()
print("Grand Prize Progress:",round(gp,2))
print("Stars* per Grand Prize Progress:",round(startingStars/gp,2))
print("Change of getting Full Building:",str(gpO) + "%")
print("When missing progress:")
print("Maximum Missing Progress:",str(maxM))
print("Average Missing Progress:",str(avgM))
print()
print("Keys:",round(avgKeys,2))
print("Stars* per Key:",round(startingStars/avgKeys,2))
print("Chance of getting",numKeys,"keys:",str(cO) + "%")
print()
print("")
print()
print("*Starting Stars")
if showPlots:
labels = ["Keys","Dailies","Grand Prize Progress","Matches"]
results = [keys,dailies,gpProgress,matches]
fig, ax = plt.subplots(4,1,figsize=(10,21))
#fig, ax = plt.subplots(3,1,figsize=(10,15))
for i in range(4):
label = labels[i]
rmin = min(results[i])
rmax = max(results[i])
ax[i].hist(results[i],edgecolor='white', label=label, bins=range(rmin,rmax,1))
#ax.set_title(label)
if i == 0:
ax[i].axvline(x = numKeys, color = "r", label = str(numKeys) + " Required for Calendar")
if i == 2:
ax[i].axvline(x = requiredProgress, color = "r", label = "Required for Target")
ax[i].legend()
c = np.average(matches)
gppU = [k for k in gpProgress if k < requiredProgress]
gppO = [k for k in gpProgress if k >= requiredProgress]
if len(gppU) == 0:
gppU.append(0)
if len(gppO) == 0:
gppO.append(0)
gpU = round(100*(len(gppU)/len(gpProgress)),2)
gpO = round(100*(len(gppO)/len(gpProgress)),2)
try:
maxM = requiredProgress - min(gpProgress)
except Exception:
maxM = 999
try:
avgM = round(requiredProgress - np.average(gppU),2)
except Exception:
avgM = 999
try:
meanM = int(requiredProgress-np.median(gppU))
except Exception:
meanM = 999
mode = "(Daily Special Focus)" if not goForKeys else "(Keys Focus)"
fig.suptitle("Expected Grand Prize Progress w/ " + str(startingStars) + " Starting Stars " + mode + "\nActual stars spent (average): " + str(round(c*10,2)) +
" | Chance of Reaching Target: " + str(gpO) + "%\nMissing Progress (when target not reached): Max: " + str(maxM) + " | Average: " + str(avgM) + " | Median: " + str(meanM))
plt.show()