import random
import math
from matplotlib import pyplot as plt
import numpy as np
from copy import copy
import re
import datetime
def getStep(s):
prefixes = ["f","s","h","fl","c","d","fi"]
bs2,ls2 = "x",0
try:
match = re.match(r"([a-z]+)([0-9]+)([a-z]+)([0-9]+)", s, re.I)
bs, ls, bs2, ls2 = match.groups()
except:
#print("except")
match = re.match(r"([a-z]+)([0-9]+)", s, re.I)
bs, ls = match.groups()
#print(bs,ls,bs2,ls2)
b = prefixes.index(bs)
l = int(ls)
b2 = prefixes.index(bs2) if bs2 != "x" else "x"
l2 = int(ls2)
return b, l, b2, l2
def getTask(s):
if s == 0:
return -1,-1,-1
prefixes = ["f","s","h","fl","c","d","fi"]
codes = ["co","tr","ge"]
match = re.match(r"([a-z]+)([0-9]+)", s, re.I)
string, num = match.groups()
t = 0
b = -1
if string[:2] in codes:
if string[2:3] in prefixes:
if string[2:4] in prefixes:
b = prefixes.index(string[2:4])
else:
b = prefixes.index(string[2:3])
t = string[:2]
elif "m" in string:
t = "m"
if len(string) == 2:
b = prefixes.index(string[:1])
else:
b = prefixes.index(string[:2])
elif string in prefixes:
t = "le"
b = prefixes.index(string)
elif string[:1] == "u":
t = "up"
n = int(num)
return t, b, n
def simulation(managers,town,order,dt,levelsAhead):
mcosts = [[10,20,40,120,360],[10,20,40,120,360],[10,20,30,60,120],[15,30,60,120,240],[20,40,80,160,320],[25,50,100,200,400],[30,60,120,240,480]]
costs = []
for i in range(len(managers)):
costs.append(sum(mcosts[i][:managers[i]]))
t1 = [0,"h25","co50000",0,"fl1","fm3","u50","co1000000","c1","fl50","cm1","tr250000000","h100","flm2","u50","ge1000000000","d1","dm2","c50","u50","hm3","cm3","fl100","co50000000000","sm4","u100","tr1000000000000","fim2","u150","c100","ge4000000000000","gefl10000000000","d50","u200","h200","co16000000000000000","u250","fi75","f999","f999","f999"]
t2 = ["f10","sm1","sm3","geh60000","fl1","u50","flm2","tr15000000","c1","c25","fm3","u100","co99000000000","h100","dm2","u100","ged5000000000","cm3","d25","fl100","co16000000000","fi1","flm3","u150","h200","tr32000000000","fim2","c100","gec15000000000000","fi50","u150","gefl50000000000","fl200","s300","sm4","co18000000000000000","geh200000000000","u200","f999","f999","f999"]
t3 = ["hm1","s10","geh50000","flm1","tr3000000","u50","fl50","fm2","c1","flm2","u50","co1000000000","sm3","c25","cm2","gec25000000000","h100","u100","d1","dm3","d25","gefl3000000000","fm4","u100","fi1","tr30000000000000","fl150","fim2","d50","u150","gefi10000000000000000","c100","fi50","h200","u200","co12000000000000000","d100","ged10000000000000000","f999","f999","f999"]
tasks = [t1,t2,t3]
# Milestones and factors for fest/ship (m) and production (p) buildings
m1 = [5,15,25,50,100,150,200,250,300,350]
m2 = [2,4,8,16,32,64,4,4,4,4]
p1 = [10,25,50,100,200,300]
p2 = [2,4,8,16,32,2]
# Base building values - all other values are calculated from these
prods = [250,350,11,9000 ,1_700_000,2_700_000_000,8_400_000_000_000]
price = [100,125,14,14730,2_180_000,2_730_000_000,8_360_000_000_000]
times = [10,15,3,10,60,45,180]
# Upgrade cost scaling factor
f = [1.15,1.15,1.1,1.1,1.1,1.1,1.1]
# Manager boosts
pBoosts = [[1.2,1.2,1.8,1.8,3.95],[1.2,1.2,1.5,1.5,3.0],[1.15,1.15,1.5,1.5,3.0],[1.15,1.15,1.9,1.9,3.7],[1.15,1.15,1.5,1.5,2.5],[1.05,1.05,2.0,2.0,4.0],[1.05,1.05,1.5,1.5,2.5]]
tBoosts = [[1,1.25,1.25,2.75,2.75],[1,1.35,1.35,3.5,3.5],[1,1.5,1.5,3.0,3.0],[1,1.2,1.2,2.0,2.0],[1,1.3,1.3,2.3,2.3],[1,1.15,1.15,2.0,2.0],[1,1.25,1.25,2.25,2.25]]
# Update times based on managers
for i in range(7):
times[i] /= tBoosts[i][managers[i]-1]
# Divide shipyard time in 2 for the two parts of the shipyard
times[1] /= 2
shipPos = True # Use a flag to keep track of where ship is. True = east, False = west
# Set up initial values - these are kept track of and updated during the simulation
cTimes = [x for x in times] # Timers for all the buildings
cProd = [240,320,12,0,0,0,0] # Production amounts (unboosted)
cPrice = [x for x in price] # Upgrade cost for next level
cLevel = [1,1,1,0,0,0,0] # Current level of buildings
time = 0 # Total time (in sec) of the simulation
ltime = 0 # Time when last step completed, used in calculating time for step
east = 0 # Shamrocks stockpiled on production side
west = 0 # Shamrocks stockpiled on collection side
ship = 0 # Shamrocks in ship
shamrocks = 0 # Collected shamrocks
# Names used for nice printing :)
names = ["Festival","Shipyard","Hats","Flowers","Cakes","Drinks","Fireworks"]
# Set up current tasks
tIndex = 0 # Number of latest task (1-indexed)
rTasks = copy(tasks[town-1]) # Make a new list of all tasks of chosen town
totalTasks = 0 # Number of tasks completed
ta = [] # Task type
bu = [] # Building
nu = [] # Number
iu = [] # Task number
tu = [] # Task timer
while len(ta) < 3: # Add 3 tasks
tIndex += 1 # Increment task number
t = getTask(rTasks[0]) # Parse next task
del rTasks[0] # Remove the task from the list
if t[0] == -1: # This indicates the task is auto-completed
totalTasks += 1
print(" - Completed",totalTasks,"/ 38:","task",tIndex,"-",tasks[town-1][tIndex-1],"- Time: 0:00:00")
continue # Move on to next task without adding this to active tasks
elif t[0] == "m": # If the task is a manager task, check if it is completed
if managers[t[1]] >= t[2]:
totalTasks += 1
print(" - Completed",totalTasks,"/ 38:","task",tIndex,"-",tasks[town-1][tIndex-1],"- Time: 0:00:00")
continue # Move on to next task without adding this to active tasks
# Add task to current list of tasks
# This is quite a messy way to do it, but I started doing it this way so I just kept on adding lists instead of being smart about it :P
ta.append(t[0])
bu.append(t[1])
nu.append(t[2])
iu.append(tIndex)
tu.append(0)
# Keep track of if a task slot has been completed
complete = [False,False,False]
# The start of the simulation! Run through each step of the upgrade order
for step in order:
task = False
wait = False
# Check if the step is waiting for a task to be active
if str(step).isnumeric(): # Wait for task
task = True
ltime = time
taskTarget = step
# Check if the step is to wait for a given time
elif step[0].isnumeric(): # Wait a given time
amount, typ = re.match(r"([0-9]+)([a-z]+)", step, re.I).groups()
amount = int(amount)
wait = True
ltime = time
wtime = amount if typ == "s" else amount*60 if typ == "m" else amount*3600
# Upgrade building to given level
else:
ltime = time
b1, l1, b2, l2 = getStep(step)
b, l = b1, l1
while True:
# Check if task you need to wait for is active
if task:
if taskTarget <= max(iu):
break
# Check if wait time is over
elif wait:
if time-ltime >= wtime:
break
# Target level reached?
elif cLevel[b1] >= l1:
if b2 != "x": # If leveling 2 buildings at the same time, check if 2nd building has also reached target
if cLevel[b2] >= l2:
break
else:
break
# Check if tasks are completed
for j in range(len(complete)):
# If task has been completed, remove it from list and prin completed message
if complete[2-j]:
totalTasks += 1
ttime = str(datetime.timedelta(seconds=time-tu[2-j]))
print(" - Completed",totalTasks,"/ 38:","task",iu[2-j],"-",tasks[town-1][iu[2-j]-1],"- Time:",ttime)
#if iu[2-j] == 20:
#print(cLevel)
del ta[2-j]
del bu[2-j]
del nu[2-j]
del iu[2-j]
del tu[2-j]
complete[2-j] = False
# Update current tasks - if a task has been removed (completed) this will add until 3 tasks are in the active tasks list (or there are no more tasks)
while (len(ta) < 3):
t = getTask(rTasks[0])
tIndex += 1
del rTasks[0]
# Check if task is already completed
if t[0] == -1:
totalTasks += 1
print(" - Completed",totalTasks,"/ 38:","task",tIndex,"-",tasks[town-1][tIndex-1],"- Time: 0:00:00")
continue
if t[0] == "m":
if managers[t[1]] >= t[2] and cLevel[t[1]] > 0:
totalTasks += 1
print(" - Completed",totalTasks,"/ 38:","task",tIndex,"-",tasks[town-1][tIndex-1],"- Time: 0:00:00")
continue
if t[0] == "le":
if cLevel[t[1]] >= t[2]:
totalTasks += 1
print(" - Completed",totalTasks,"/ 38:","task",tIndex,"-",tasks[town-1][tIndex-1],"- Time: 0:00:00")
continue
# If not completed, add to list
ta.append(t[0])
bu.append(t[1])
nu.append(t[2])
iu.append(tIndex)
tu.append(time)
#if(tIndex == 31):
# print(cLevel)
# Step ahead one time step
time += dt
# Updated timers for buildings. This is done by subtracting time step
cTimes = [x - dt for x in cTimes]
# If timers are below 0, collection is ready. Add all ready collections to a list
collectable = [x for x in cTimes if x < 0]
# If any buildings are ready to collect
if len(collectable) > 0:
for _ in range(len(collectable)):
# Get the lowest value - handle the building that was first completed first
val = min(collectable)
del collectable[collectable.index(val)]
i = cTimes.index(val) # Index of building
if cTimes[i] < 0: # Unnecesary check that's still in place that I would rather write this long description for than remove, which would probably be quicker :P
cTimes[i] += times[i] # Add production time to the building. This ensures minimum drift if time step is too big. I saw practically no difference between 1 sec and 0.1 sec, etc.
if i == 0: #Festival - add shamrocks to collected shamrocks
p = min(west,cProd[i]*pBoosts[i][managers[i]-1]) # Pick the minimum of stockpile and collection rate
shamrocks += p
west -= p
# If a collection task is active, update that
for j in range(len(ta)):
if ta[j] == "co" and bu[j] < 0:
nu[j] -= p
if nu[j] < 0: # Task completed?
complete[j] = True
elif i == 1: #Shipyard
if shipPos: # Step 1 - collect on eastern side of the river
ship = min(east,cProd[i]*pBoosts[i][managers[i]-1])
east -= min(east,cProd[i]*pBoosts[i][managers[i]-1])
else: # Step 2 - drop off on western side of river
west += ship
# If transportation task is active, update that
for j in range(len(ta)):
if ta[j] == "tr":
nu[j] -= ship
if nu[j] < 0:
complete[j] = True
ship = 0
shipPos = not shipPos # Alternate flag when a step has been completed
else: #Production - add shamrocks to eastern side
p = cProd[i]*pBoosts[i][managers[i]-1]
east += p
# If collection task is active, update that
for j in range(len(ta)):
if ta[j] == "ge":# and bu[j] == i:
if bu[j] == -1:
nu[j] -= p
elif bu[j] > 0 and bu[j] == i:
nu[j] -= p
if nu[j] < 0:
complete[j] = True
# Upgrade building (if not waiting)
while True and not wait:
# If yo don't have enough shamrocks, or the building has reached target level, move on to next timestep
if (cPrice[b] > shamrocks) or (cLevel[b] >= l):
break
# Level building
shamrocks -= cPrice[b] # Subtract cost
cPrice[b] *= f[b] # Update price for next level
if cLevel[b] == 0: # If this is the first level of the building, update production rate and timer
cProd[b] = prods[b]
cTimes[b] = times[b]
for j in range(len(ta)):
if ta[j] == "m" and bu[j] == b:
if managers[b] >= nu[j]:
complete[j] = True
else: # If not the first level, scale production by the formula x[n] = x[n-1]*(1+1/(n-1)). (cLevel is already n-1, so that's why 1 is not subtracted here)
cProd[b] *= (1+(1/(cLevel[b])))
cLevel[b] += 1
# Check if upgrade task or building level task is completed
for j in range(len(ta)):
if ta[j] == "up":
nu[j] -= 1
if nu[j] <= 0:
complete[j] = True
if ta[j] == "le" and bu[j] == b:
if cLevel[b] >= nu[j]:
#print(nu[j],cLevel[b])
complete[j] = True
# Check for milestone level, multiply by factor if it is
if b < 2: # Shipyard/Festival
if cLevel[b] in m1:
cProd[b] *= m2[m1.index(cLevel[b])]
else: # Production buildings
if cLevel[b] in p1:
cProd[b] *= p2[p1.index(cLevel[b])]
# Update what the current building is (if leveling 2 at the same time)
if b2 != "x":
# Pick the lowest, with b1 the priority if the same level
b = b1 if (cLevel[b1] < cLevel[b2]+levelsAhead) else b2
l = l1 if (cLevel[b1] < cLevel[b2]+levelsAhead) else l2
if cLevel[b1] >= l1: # If target level has been reached
b,l = b2, l2
# This executes when a step has been completed
stime = str(datetime.timedelta(seconds=time-ltime)) # Time to complete this step
ctime = str(datetime.timedelta(seconds=time)) # Total time completed so far
if task:
print("| Step:",stime," | Total:",ctime,"| Completed waiting for task \"",tasks[town-1][taskTarget-1],"\" to start")
elif wait:
print("| Step:",stime," | Total:",ctime,"| Completed waiting for",step)
else:
name = names[b1] if b2 == "x" else names[b1] + "/" + names[b2]
level = l1 if b2 == "x" else str(l1) + "/" + str(l2)
print("| Step:",stime," | Total:",ctime,"| Completed leveling",name,"to level",level)
# After all steps are completed, collect 8.4Q. Could probably have included this in the loop above, but I didn't wanna add a bunch of conditions so just copied the relevant parts xD
ltime = time
# Collect 8.4Q
while True:
# Check if tasks are completed
for j in range(len(complete)):
if complete[2-j]:
totalTasks += 1
ttime = str(datetime.timedelta(seconds=time-tu[2-j]))
print(" - Completed",totalTasks,"/ 38:","task",iu[2-j],"-",tasks[town-1][iu[2-j]-1],"- Time:",ttime)
del ta[2-j]
del bu[2-j]
del nu[2-j]
del iu[2-j]
del tu[2-j]
complete[2-j] = False
# Update current tasks
while len(ta) < 3:
t = getTask(rTasks[0])
tIndex += 1
del rTasks[0]
if t[0] == -1:
totalTasks += 1
print(" - Completed",totalTasks,"/ 38:","task",tIndex,"-",tasks[town-1][tIndex-1],"- Time: 0:00:00")
continue
elif t[0] == "m":
if managers[t[1]] >= t[2]:
totalTasks += 1
print(" - Completed",totalTasks,"/ 38:","task",tIndex,"-",tasks[town-1][tIndex-1],"- Time: 0:00:00")
continue
elif t[0] == "le":
if cLevel[t[1]] >= t[2]:
totalTasks += 1
print(" - Completed",totalTasks,"/ 38:","task",tIndex,"-",tasks[town-1][tIndex-1],"- Time: 0:00:00")
continue
ta.append(t[0])
bu.append(t[1])
nu.append(t[2])
iu.append(tIndex)
tu.append(time)
# Step ahead one time step
time += dt
# Add completed productions
cTimes = [x - dt for x in cTimes]
collectable = [x for x in cTimes if x < 0]
if len(collectable) > 0:
for _ in range(len(collectable)):
val = min(collectable)
del collectable[collectable.index(val)]
i = cTimes.index(val)
if cTimes[i] < 0:
cTimes[i] += times[i]
if i == 0: #Festival
p = min(west,cProd[i]*pBoosts[i][managers[i]-1])
shamrocks += p
west -= p
for j in range(len(ta)):
if ta[j] == "co" and bu[j] < 0:
nu[j] -= p
if nu[j] < 0:
complete[j] = True
elif i == 1: #Shipyard
if shipPos:
ship = min(east,cProd[i]*pBoosts[i][managers[i]-1])
east -= min(east,cProd[i]*pBoosts[i][managers[i]-1])
else:
west += ship
for j in range(len(ta)):
if ta[j] == "tr":
nu[j] -= ship
if nu[j] < 0:
complete[j] = True
ship = 0
shipPos = not shipPos
else: #Production
p = cProd[i]*pBoosts[i][managers[i]-1]
east += p
for j in range(len(ta)):
if ta[j] == "ge":# and bu[j] == i:
if bu[j] == -1:
nu[j] -= p
elif bu[j] > 0 and bu[j] == i:
nu[j] -= p
if nu[j] < 0:
complete[j] = True
if shamrocks > 8.4*(10**15):
break
stime = str(datetime.timedelta(seconds=time-ltime))
ctime = str(datetime.timedelta(seconds=time))
print("\n==Completed collecting 8.4Q Shamrocks - Step:",stime,"| Total:",ctime)
print("==Manager Cost:",sum(costs),costs)
# print(ta)
# print(bu)
# print(nu)
# print(iu)
# print(cLevel)