War Spoils Simulator
This page presents a python code that simulates spinning the War Spoils wheel and can be run here or using a compiler of your choice, the code being available below.
Input parameter
By editing the respective equations in the code before clicking "Run", you can specify the amount of order, chaos and nature jewels (//) as well as Power Essence that you start with. Next, you type in the amount of your Seals of Valor, the current level of your War Spoils (found inside the wheel - not at the end of the progress bar) and the number of spins that you already did with that level (found in the progress bar). Also, type in the levels of your Champions. Those levels are stored for each faction within square brackets "[...]" in the order "common, common, rare, epic, legendary", where 0 denotes a champion not unlocked yet and -1 denotes that a champion of that rarity and faction doesn't exist (so don't change the -1).
Lastly, you can specify the number of simulations to be done. If you type N=1, the code will run one simulation (see below) and tell you the outcome and the levels of the champions after leveling. If you use a larger number, it will show you the total troops on average.
You don't need to change anything before "INPUT" or after "END INPUT".
What the code does
The code runs a simulation in which it spins the War Spoils as often as your specified amount of seals allows. Afterwards, it simulates leveling the champions as far as the respective faction jewels allow it, always picking the most efficient level in term of "power increase per jewels used". In the end, it sums up the champions' powers to get the total troops that you would end up with in this simulation.
Note that the need of Power Essence for every 10th level-up is ignored in this code. Thus, it gives you the "potential" total troops that you can reach with enough power essence. The reason for ignoring this is mainly technical.
How this can be helpful
If you have a rather large amount of seals - that would allow you to spin the wheel several times and/or unlock some new champions -, you can run a few simulations for each case and compare the expected troops. Then you can decide whether you want to unlock a champion or use all seals to spin the War Spoils (keep in mind that this can also raise its level, making jewel/power essence deals better).
For example, if you have 3500 Seals of Valor and no champion unlocked yet, you can...
- use
seals=3500
andoChampsStart=[1,1,-1,0,0]
to simulate using all seals to spin the wheel. - use
seals=2500
andoChampsStart=[1,1,-1,1,0]
to simulate unlocking the epic order champion for 1000 and then using the remaining 2500 seals on war spoils.
The code
Here you can find the complete code in case the link above is broken or you want to copy it somewhere else.
import random
import math
import numpy as np
#############
### INPUT ###
#############
# current faction jewels/PE/seals in possession:
ojStart = 0
cjStart = 0
njStart = 0
peStart = 0
seals = 3500
# wheel info:
warSpoilsLvlStart = 1 # current wheel level
spinsDoneStart = 0 # spins already done within current level
# champions. level 0 = locked, -1= doesn't exist
# order of rarities: [c,c,r,e,l]
oChampsStart = [1,1,-1,0,0]
cChampsStart = [1,1,0,0,-1]
nChampsStart = [1,1,0,-1,0]
# number of simulations to run:
N = 10
# for one simulation: show results (resources, levels)
# for multiple simulations: only show total troops and
# ... average (expected) total troops
#################
### END INPUT ###
#################
##################
### TROOP DATA ###
##################
### before level 1000
# troop growth
trConst = [98,147,196,245]
trFactor = [2,3,4,5]
# troops at level n with rarity r =
# trFactor[r]*n^(1.5) + trConst[r]
# cost to level from n (to n+1) =
# 2*n^(1.5) + 8
oChamps = np.copy(oChampsStart)
cChamps = np.copy(cChampsStart)
nChamps = np.copy(nChampsStart)
totTr=np.zeros(N)
### starting from level n=1000
trSlopeHigh = [100,150,200,250] # = troops at level 1
trOffsetHigh = [36600,55000,73300,91600]
# troops = trSlopeHigh[r] * n - trOffsetHigh[r]
# cost = n*65000 ???? TODO check
##################
### WHEEL DATA ###
##################
# spins needed for next level = current level + 9
spins=math.floor(seals/100) # spins to be done in this simulation
warSpoilsLvl=warSpoilsLvlStart
spinsDoneStart
scaling = 1 # multiple for jewels/PE
# scaling per level:
# lvl 1: 1
# lvl 2: 2
# lvl 3: 4
# lvl 4: 8
# lvl5+: 2*lvl^(1.5) - 8
# chance jewels = 60% (20% per faction)
# 200 jewels: 10%
# 400 jewels: 6.67%
# 600 jewels: 3.33%
# chance PE: 15%
# 35 PE: 5%
# 55 PE: 5%
# 70 PE: 5%
#####################
### RESOURCE DATA ###
#####################
oj = ojStart
cj = cjStart
nj = njStart
pe = peStart
###########################
### spin the wheel once ###
###########################
def spin():
global warSpoilsLvl,spinsDone,scaling,oj,cj,nj,pe
chance = random.random()
#print(chance)
#print(oj)
if chance <= 0.1:
oj += math.floor(200*scaling)
elif chance <= 0.1+0.0667:
oj += math.floor(400*scaling)
elif chance <= 0.1667+0.0333:
oj += math.floor(600*scaling)
elif chance <= 0.2+0.1:
cj += math.floor(200*scaling)
elif chance <= 0.3+0.0667:
cj += math.floor(400*scaling)
elif chance <= 0.3667+0.0333:
cj += math.floor(600*scaling)
elif chance <= 0.4+0.1:
nj += math.floor(200*scaling)
elif chance <= 0.5+0.0667:
nj += math.floor(400*scaling)
elif chance <= 0.5667+0.0333:
nj += math.floor(600*scaling)
elif chance <= 0.6+0.05:
pe += math.floor(35*scaling)
elif chance <= 0.65+0.05:
pe += math.floor(55*scaling)
elif chance <= 0.7+0.05:
pe += math.floor(70*scaling)
spinsDone += 1
if spinsDone == warSpoilsLvl+9 and warSpoilsLvl<50:
spinsDone=0
warSpoilsLvl+=1
#print("LEVEL " + str(warSpoilsLvl))
getScaling()
### end spin function ###
########################
### level war spoils ###
########################
def getScaling():
global warSpoilsLvl,scaling
if warSpoilsLvl == 1:
scaling=1
elif warSpoilsLvl == 2:
scaling=2
elif warSpoilsLvl == 3:
scaling=4
elif warSpoilsLvl == 4:
scaling=8
else:
scaling=2*warSpoilsLvl**1.5 - 8
########################
### output resources ###
########################
def printresources(spins):
global oj,cj,nj,pe,warSpoilsLvl
print("Possible outcome after "+str(spins)+" spins:")
print("Order jewels: "+str(oj))
print("Chaos jewels: "+str(cj))
print("Nature jewels: "+str(nj))
print("Power essence: "+str(pe))
print("WARNING: power essence is ignored for leveling in this simulation. You might be missing this resource")
print("War Spoils at level "+str(warSpoilsLvl))
########################
### reset everything ###
########################
def reset():
global warSpoilsLvl,warSpoilsLvlStart,spinsDone,spinsDoneStart,scaling
global oj,cj,nj,pe,ojStart,cjStart,njStart,peStart
global oChamps,cChamps,nChamps
global oChampsStart,cChampsStart,nChampsStart
spinsDone=spinsDoneStart
getScaling()
oj=ojStart
cj=cjStart
nj=njStart
pe=peStart
oChamps = np.copy(oChampsStart)
cChamps = np.copy(cChampsStart)
nChamps = np.copy(nChampsStart)
warSpoilsLvl=warSpoilsLvlStart
#######################
### level champions ###
#######################
# levels one hero, with best troops/jewels ratio
def levelupOrder():
global oChamps,oj,oTry
ratio=np.zeros(5)
possible=0
for i in [0,1,3,4]:
rarity = 0
if i==3:
rarity = 2
elif i==4:
rarity = 3
cost = math.floor(2*oChamps[i]**1.5 + 8)
if cost>oj or oChamps[i]<=0:
ratio[i]=0
else:
possible=1
trNow = math.floor(trFactor[rarity]*oChamps[i]**1.5 + trConst[rarity])
trNext = math.floor(trFactor[rarity]*(oChamps[i]+1)**1.5 + trConst[rarity])
newTroops=trNext-trNow
ratio[i]=newTroops/cost
if possible==1:
cheap=ratio.argmax()
oj -= math.floor(2*oChamps[cheap]**1.5 + 8)
oChamps[cheap]+=1
else:
oTry=0
def levelupChaos():
global cChamps,cj,cTry
ratio=np.zeros(5)
possible=0
for i in [0,1,2,3]:
rarity = 0
if i==2:
rarity = 1
elif i==3:
rarity = 2
cost = math.floor(2*cChamps[i]**1.5 + 8)
if cost>cj or cChamps[i]<=0:
ratio[i]=0
else:
possible=1
trNow = math.floor(trFactor[rarity]*cChamps[i]**1.5 + trConst[rarity])
trNext = math.floor(trFactor[rarity]*(cChamps[i]+1)**1.5 + trConst[rarity])
newTroops=trNext-trNow
ratio[i]=newTroops/cost
if possible==1:
cheap=ratio.argmax()
cj -= math.floor(2*cChamps[cheap]**1.5 + 8)
cChamps[cheap]+=1
else:
cTry=0
def levelupNature():
global nChamps,nj,nTry
ratio=np.zeros(5)
possible=0
for i in [0,1,2,4]:
rarity = 0
if i==2:
rarity = 1
elif i==4:
rarity = 3
cost = math.floor(2*nChamps[i]**1.5 + 8)
if cost>nj or nChamps[i]<=0:
ratio[i]=0
else:
possible=1
trNow = math.floor(trFactor[rarity]*nChamps[i]**1.5 + trConst[rarity])
trNext = math.floor(trFactor[rarity]*(nChamps[i]+1)**1.5 + trConst[rarity])
newTroops=trNext-trNow
ratio[i]=newTroops/cost
if possible==1:
cheap=ratio.argmax()
nj -= math.floor(2*nChamps[cheap]**1.5 + 8)
nChamps[cheap]+=1
else:
nTry=0
troopAverage=0
for n in range(0,N):
reset()
getScaling()
for i in range(0,spins):
spin()
if N==1: printresources(spins)
oTry=1
cTry=1
nTry=1
while oTry==1:
levelupOrder()
if N==1:
print("order jewels left: "+str(oj))
print("order champions: "+str(oChamps))
while cTry==1:
levelupChaos()
if N==1:
print("chaos jewels left: "+str(cj))
print("chaos champions: "+str(cChamps))
while nTry==1:
levelupNature()
if N==1:
print("nature jewels left: "+str(nj))
print("nature champions: "+str(nChamps))
totalTroops=0
for i in range(0,5):
name=""
rarity = 0
if oChamps[i]>=1:
if i==0:
name="order common 1"
elif i==1:
name="order common 2"
elif i==3:
name="order epic"
rarity=2
elif i==4:
name="order leg"
rarity=3
troops=math.floor(trFactor[rarity]*oChamps[i]**1.5 + trConst[rarity])
totalTroops+=troops
if N==1: print(name+", troops: "+str(troops))
for i in range(0,5):
name=""
rarity = 0
if cChamps[i]>=1:
if i==0:
name="chaos common 1"
elif i==1:
name="chaos common 2"
elif i==2:
name="chaos rare"
rarity=1
elif i==3:
name="chaos epic"
rarity=2
troops=math.floor(trFactor[rarity]*cChamps[i]**1.5 + trConst[rarity])
totalTroops+=troops
if N==1: print(name+", troops: "+str(troops))
for i in range(0,5):
name=""
rarity = 0
if nChamps[i]>=1:
if i==0:
name="nature common 1"
elif i==1:
name="nature common 2"
elif i==2:
name="nature rare"
rarity=1
elif i==4:
name="nature leg"
rarity=3
troops=math.floor(trFactor[rarity]*nChamps[i]**1.5 + trConst[rarity])
totalTroops+=troops
if N==1: print(name+", troops: "+str(troops))
itercounter=""
if n<10:
if N>1: itercounter = " in simulation #"+str(n+1)
print("total troops"+itercounter+": "+str(totalTroops))
elif n==10:
print("not showing results of "+str(N-n)+" more simulations...")
troopAverage+=totalTroops
totTr[n]=totalTroops
if N>1:
avg=troopAverage/N
print("average total troops ("+str(N)+" simulations): "+str(math.floor(avg)))
sigma=0
for n in range(0,N):
sigma+=(totTr[n]-avg)**2
sigma=sigma/(N-1)
sigma=np.sqrt(sigma)
print("standard deviation: "+str(math.floor(sigma)))
- Pages using deprecated source tags