• Dear forum reader,
    To actively participate in our forum discussions or to start your own threads, in addition to your game account you need a forum account. You can
    REGISTER HERE!
    Please ensure a translation in to English is provided if your post is not in English and to respect your fellow players when posting.

Feedback Summer Event 2023

CrashBoom

Legend
As may know there is no level one for the grand prize. I have all the 9 upgrades and the special upgrade to bring it to level 10. I went to build it and was told there is no blg to upgrade or can you turn a upgrade to lvl one. In the event game lve one prize isn't until the the 20th win. I have a call into support as to what's up or is this a cash grab
it was at progress 0 !!! so directly ready to collect at start of the event
and a second at 100 progress

so how can't you have those 2 base buildings ?
 

Kronan

Viceroy
Just out of curiosity, does anyone remember how many stars were we getting in the Christmas event for daily login and for the quest tasks? I simply do not remember, but I bet it was more than 10 each. Was it 60? or 80? or even 100? Don't know but surely more than 10. And that's the whole problem.
Inno copied mechanics from another event (whether we like it or not is beside the question), but kinda forgot to copy the appropriate numbers going with said mechanics. And that's that.
They can either fix it for live servers (it is too late for us here now unless they would credit us all for the extra currency we missed by wrong amount of quests and daily logins until now) ), or simply people will ignore the event on the live servers.
Event does not have to be easy and "given without effort", but it should be doable. This one is MATHEMATICALLY impossible to do, no matter the amount of luck . And that's wrong, plain and simple.

I threw a bunch (2 buys of 1050 diamonds = 2100 total) of Inno's FREE beta compensation diamonds at the event, this morning. But you're right. I just don't (can't) see how the math is going to work without that - for ANYONE.

You're right again - glad we (beta) caught it - vs releasing this to live and watching it unfold incorrectly as well.

If someone knows of "the magical" path to "do-ability" given the design of how we in beta got it, I'd love to see the math from whoever has it figured out.
 

xivarmy

Overlord
Perk Creator
I threw a bunch (2 buys of 1050 diamonds = 2100 total) of Inno's FREE beta compensation diamonds at the event, this morning. But you're right. I just don't (can't) see how the math is going to work without that - for ANYONE.

You're right again - glad we (beta) caught it - vs releasing this to live and watching it unfold incorrectly as well.

If someone knows of "the magical" path to "do-ability" given the design of how we in beta got it, I'd love to see the math from whoever has it figured out.
It didn't seem too far off with my back of the envelope math.

330 login + 670 quests + 100 milestones = ~1100 doubloons.

13 stars refunded out of 16 treasures = .08125
.08125+0.08125^2+0.08125^3+... = 0.0884
So about 9.116 doubloons per treasure.

The show-2 and double could improve that a little.

1100/9.116 = ~120 presents = ~240 grand prize progress.
You need 280 for the building, so short 40 progress = 20 presents = ~182 doubloons.

Some slight tweaks to the currency given should fix that (and they did say more changes were coming). Say add 5 per to the daily quests (=+160), and increase the 2nd milestone to 100 (=+50).
 

xivarmy

Overlord
Perk Creator
Ahoy! We bring ya mo' balancing changes. starting with the next update.
  • One Hidden Goods change was to hidden for ma, I missed that. It provides 2 Previous Era Goods and 1-2% Defense for Attacking army since the 28th already!
  • Ya now gain more Doubloons. The pirates gained more and increased the amount from Daily Quests from 10 to 30 and from the free daily reward from 10 to 25! Of course they did not forget what ya already achieved, so they will bring ya the missing ones too! Go get looking under the tiles even more.
  • As the Pirates brought more Doubloons, the Chip tossing got a change as well. Ya no longer receive 1-3 Heads, but now only 1-2, ya know, to prevent the inflation from all those extra shiny Doubloons!
  • Ya now also get a lower chance for keys to. Now only roughly every 3rd board will have a key on it. Hope ya can still have a clear look with ya eye patch!
And that's all for now yarr. Tell us what you think hearr!

So analyzing the change from back of the envelope math:

New doubloon total: 25*33+30*32+10*35 + 50*2 = 2235 doubloons
Openable chests (@9.2 doubloons each): ~243
Grand Prize Progress: 243*1.5 = 365. Looks comfortable.

Calendar might be a bit of a nightmare now though. That Skull Rock just got a lot more expensive! (always took diamonds; but now you probably need to spend somewhere closer to 200 doubloons a day on average to find the key)
 

UBERhelp1

Viceroy
New event changes dropped! First time in a while we've had buffs rather than nerfs for event currency :D

Some analysis/back of the napkin math:
You get 2265 doubloons now:
  • 110 from milestones/start
  • 340 from main quests
  • 33 * 25 = 825 from daily free currency
  • 33 * 30 = 990 from daily quests
  • Total: 2265 doubloons
This means you get ~226 tiles to flip (assuming 10 doubloons/tile, it's actually less due to doubloons from shuffle and reveal). To get to 280 progress (a level 9 Trading Post) would mean you'd only have to average 1.24 progress/tile, which should be more than do-able, even with the nerf to only 1-2 progress from the coins. With an even 1.5 progress/tile (which is unlikely), that's 339 progress, which would get you close to winning 2 sets of fragments from the grand prizes, but I'm guessing the actual value for progress/tile is more like 1.3 (293 progress) or 1.4 (316 progress).

And xivarmy beat me to it :p
 
Last edited:

MooingCat

Viceroy
Spoiler Poster
The change is definitely good, but I don't understand the focus on making the calendar unachievable ... With the update it went from a very low chance of completing it, to absolutely impossible:

CieRejy.png

I updated my simulator to only give a key every 3rd game (1/3 chance of giving key each board), which gives the result above. If you do all daily challenges you can get 14 keys, so you need 18 from the minigame. As seen in the graph, none of the 10k playthroughs I simulated resulted in enough keys. As a reminder, this is when you play every day until you find a key, then stop.

Updating to a key every other game doesn't help much:
zYiGRh1.png


But if things were just kept as is, it would be really well balanced!
sr05a9i.png


That would mean that if you do every daily challenge and completely shift your playstyle towards keys, you would have a very high chance of succeeding. That's completely reasonable to me, and would make it an actually interesting way of playing the event. But with the current balancing there's not really any choice to make, it's not worth focusing on the calendar.

Code:
from simulator import simulator

# Number of stars you start off with
startingStars = 2255

# If True, simulate stopping after finding each daily key. If False, spend all the same day.
goForKeys = True

# Required Progress (for your goal, 300 for 1 full building)
requiredProgress = 280

# Number of keys required for calendar (you can get ~11 for free from daily challenges)
numKeys = 32-14

# Number of Simulations
simNum = 10000

simulator(startingStars,goForKeys,requiredProgress,numKeys,simNum)
Code:
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):
        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 reward is "show 2", pick 2 random rewards and add them to a separate list. 
        if 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()
            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()
                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
    
    # 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()
        showTwoList = []
        showTwoIndex = []
        dsFound = False
        firstKey = True 
        while remainingStars >= 10:
            remainingStars -= 10
            resMatches += 1
            days,mainList,showTwoList,showTwoIndex,dsFound,remainingStars,double,resDS,resKeys,firstKey = pickPresent(days,mainList,showTwoList,showTwoIndex,dsFound,remainingStars,double,resDS,resKeys,firstKey)
        
        
        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()
 

xivarmy

Overlord
Perk Creator
The change is definitely good, but I don't understand the focus on making the calendar unachievable ... With the update it went from a very low chance of completing it, to absolutely impossible:

CieRejy.png

I updated my simulator to only give a key every 3rd game (1/3 chance of giving key each board), which gives the result above. If you do all daily challenges you can get 14 keys, so you need 18 from the minigame. As seen in the graph, none of the 10k playthroughs I simulated resulted in enough keys. As a reminder, this is when you play every day until you find a key, then stop.

Updating to a key every other game doesn't help much:
zYiGRh1.png


But if things were just kept as is, it would be really well balanced!
sr05a9i.png


That would mean that if you do every daily challenge and completely shift your playstyle towards keys, you would have a very high chance of succeeding. That's completely reasonable to me, and would make it an actually interesting way of playing the event. But with the current balancing there's not really any choice to make, it's not worth focusing on the calendar.

Code:
from simulator import simulator

# Number of stars you start off with
startingStars = 2255

# If True, simulate stopping after finding each daily key. If False, spend all the same day.
goForKeys = True

# Required Progress (for your goal, 300 for 1 full building)
requiredProgress = 280

# Number of keys required for calendar (you can get ~11 for free from daily challenges)
numKeys = 32-14

# Number of Simulations
simNum = 10000

simulator(startingStars,goForKeys,requiredProgress,numKeys,simNum)
Code:
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):
        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 reward is "show 2", pick 2 random rewards and add them to a separate list.
        if 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()
            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()
                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
  
    # 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()
        showTwoList = []
        showTwoIndex = []
        dsFound = False
        firstKey = True
        while remainingStars >= 10:
            remainingStars -= 10
            resMatches += 1
            days,mainList,showTwoList,showTwoIndex,dsFound,remainingStars,double,resDS,resKeys,firstKey = pickPresent(days,mainList,showTwoList,showTwoIndex,dsFound,remainingStars,double,resDS,resKeys,firstKey)
      
      
        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()
There is a little room for improvement on this:

Assuming the state of key/not-a-key is correct pre-shuffle, you can (somewhat) choose ~10-11 days where you're likely to get the key faster because it's a possibility on first board if you don't get bit by the shuffle first. Can say ~6 of those are cheap successes (a bit better than 50/50 per board because of the show-2).

Your 14 wilds are obviously used on days where this was not the case. So That's up to ~20 keys. Leaving 12 Keys to be found the painful way of "maybe next board"
 

MooingCat

Viceroy
Spoiler Poster
There is a little room for improvement on this:

Assuming the state of key/not-a-key is correct pre-shuffle, you can (somewhat) choose ~10-11 days where you're likely to get the key faster because it's a possibility on first board if you don't get bit by the shuffle first. Can say ~6 of those are cheap successes (a bit better than 50/50 per board because of the show-2).

Your 14 wilds are obviously used on days where this was not the case. So That's up to ~20 keys. Leaving 12 Keys to be found the painful way of "maybe next board"
True! It definitely helps, but not by that much. I still think a key every board makes perfect sense considering all else you sacrifice going for this strategy.

Every third game:
R2awz9y.png

Every other game:
8U9EZF0.png

Every game (no change):
sr05a9i.png


Code:
from simulator import simulator

# Number of stars you start off with
startingStars = 2255

# If True, simulate stopping after finding each daily key. If False, spend all the same day.
goForKeys = True

# Required Progress (for your goal, 300 for 1 full building)
requiredProgress = 280

# Number of keys required for calendar (you can get ~11 for free from daily challenges)
numKeys = 32-14

# Number of Simulations
simNum = 10000

simulator(startingStars,goForKeys,requiredProgress,numKeys,simNum)
Code:
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()
 

Retired Guy

Marquis
  • Ya now gain more Doubloons. The pirates gained more and increased the amount from Daily Quests from 10 to 30 and from the free daily reward from 10 to 25! Of course they did not forget what ya already achieved, so they will bring ya the missing ones too! Go get looking under the tiles even more.
Can someone explain the last 2 sentences.. Arggg.. been in the rum all day, me matey's... Where do I find the missing ones? (Thought I did good finding the rum !!!)
 

xivarmy

Overlord
Perk Creator
  • Ya now gain more Doubloons. The pirates gained more and increased the amount from Daily Quests from 10 to 30 and from the free daily reward from 10 to 25! Of course they did not forget what ya already achieved, so they will bring ya the missing ones too! Go get looking under the tiles even more.
Can someone explain the last 2 sentences.. Arggg.. been in the rum all day, me matey's... Where do I find the missing ones? (Thought I did good finding the rum !!!)
After the change they'll be giving you extra doubloons you "missed" based on what you've already done in the event. Basically in the morning look for a whole bunch of extra doubloons in your event window if you're up to date on the questing.
 

xivarmy

Overlord
Perk Creator
So seeing as the calendar was something I was half-planning to get on live before the changes, I did some more back of the envelope math:

14 wilds, yay

10.67 "Situation 1" Days (the key is visible on the first board):

% Tried​
Cost​
Keys Gained​
100.00%​
48.3​
0.568​
14.72%​
48.3​
0.568​
2.17%​
48.3​
0.568​
0.32%​
48.3​
0.568​
0.05%​
48.3​
0.568​
0.01%​
48.3​
0.568​
0.00%​
48.3​
0.568​

The Cost is the average cost to hit *either* a key or a shuffle
The additional lines represents the previous attempt to find a key failing because it hit a shuffle, but the new board still having a key visible. On situation 1 days I'm assuming if I hit a shuffle into a board with no key, I just give up for that day.

Expected Average Cost and Key gain on a situation 1 day is 56.7 doubloons for 0.67 keys.

Overall, situation 1 days are expected to cost ~600 doubloons for ~7 keys.

So ~11 keys to go, with ~1600 doubloons... Now the bad news, "situation 2" days. Where there is no key visible, but i gotta try to find one:

Round​
% No Key​
Cost​
% Key​
Cost​
Keys​
% Done​
1​
100.00%​
65.2​
0.00%​
48.3​
0.568​
0.00%​
2​
66.67%​
65.2​
33.33%​
48.3​
0.568​
0.00%​
3​
54.26%​
65.2​
27.13%​
48.3​
0.568​
18.61%​
4​
44.16%​
65.2​
22.08%​
48.3​
0.568​
33.76%​
5​
35.94%​
65.2​
17.97%​
48.3​
0.568​
46.09%​
6​
29.25%​
65.2​
14.63%​
48.3​
0.568​
56.12%​
7​
23.81%​
65.2​
11.90%​
48.3​
0.568​
64.29%​
8​
19.38%​
65.2​
9.69%​
48.3​
0.568​
70.93%​
9​
15.77%​
65.2​
7.89%​
48.3​
0.568​
76.34%​
10​
12.84%​
65.2​
6.42%​
48.3​
0.568​
80.75%​
11​
10.45%​
65.2​
5.22%​
48.3​
0.568​
84.33%​
12​
8.50%​
65.2​
4.25%​
48.3​
0.568​
87.25%​
13​
6.92%​
65.2​
3.46%​
48.3​
0.568​
89.62%​
14​
5.63%​
65.2​
2.82%​
48.3​
0.568​
91.55%​
15​
4.58%​
65.2​
2.29%​
48.3​
0.568​
93.12%​
16​
3.73%​
65.2​
1.87%​
48.3​
0.568​
94.40%​
17​
3.04%​
65.2​
1.52%​
48.3​
0.568​
95.45%​
18​
2.47%​
65.2​
1.24%​
48.3​
0.568​
96.29%​
19​
2.01%​
65.2​
1.01%​
48.3​
0.568​
96.98%​
20​
1.64%​
65.2​
0.82%​
48.3​
0.568​
97.54%​

(and more rows because there's still a 2.5% chance after 20 boards that I have failed to win a key yet between only 1 in 3 boards having a key and no guarantee of winning that key when it shows - and unlike situation 1, in situation 2 I have to keep forcing it).

Overall average cost to force the win of the key of the day is ~390 doubloons for 1.02 keys (some chance you get a double-key when you finally win it for an extra 0.25 keys). So... ~4 of the remaining 11 keys can be handled with the free currency, and if I wanted to get the last 7 it'd cost about 2800! extra doubloons - about 30k diamonds worth. It seems like going for the calendar *this* way only makes sense for someone going for extra buccaneers anyways.

If you just want the skull cave though, 7 extra wild-keys are only ~2800 diamonds... Is 2800 diamonds worth it for pretty much just a skull cave given that calendar tiles tend to be worthless crap? Maybe. Food for thought. Regardless buying doubloons to try and get extra keys seems like a trap with the 1/3 boards actually having one.
 

Juber

Overlord
Community Manager
Just some information before the change goes live later today:
The image in the middle of the board has not been adjusted yet and will continue to display "1-3" for the entire beta test. Depending on the results, it will be adjusted accordingly.
The same goes for the Coins tossed after each unlocked tile: It will still have 3 coins, however only 1 or 2 can show heads. You can never have 0 or 3 heads.
 

UBERhelp1

Viceroy
So seeing as the calendar was something I was half-planning to get on live before the changes, I did some more back of the envelope math:

... cut out all your great math :) ...

If you just want the skull cave though, 7 extra wild-keys are only ~2800 diamonds... Is 2800 diamonds worth it for pretty much just a skull cave given that calendar tiles tend to be worthless crap? Maybe. Food for thought. Regardless buying doubloons to try and get extra keys seems like a trap with the 1/3 boards actually having one.

With how the calendar is currently balanced, it seems really odd to me. It's near impossible to get for free, so the draw for people to spend diamonds is a portrait, a single exclusive building, and then two upgrade kits (alongside some FP and goods that are nice, but imo don't necessitate spending)? It feels like it's missing something.

The calendar still shows the governor's villa selection kit with a gold background, which is weird. I think that if the calendar got the Viceroy's Villa upgrade, it could be a lot more sensible to spend for, and would allow free to play players to get one Viceroy's Villa upgrade by spending diamonds instead of buying the event pass. For 2800 diamonds, I could definitely see many more players going for the calendar.


1683166754113.png
 

xivarmy

Overlord
Perk Creator
With how the calendar is currently balanced, it seems really odd to me. It's near impossible to get for free, so the draw for people to spend diamonds is a portrait, a single exclusive building, and then two upgrade kits (alongside some FP and goods that are nice, but imo don't necessitate spending)? It feels like it's missing something.

The calendar still shows the governor's villa selection kit with a gold background, which is weird. I think that if the calendar got the Viceroy's Villa upgrade, it could be a lot more sensible to spend for, and would allow free to play players to get one Viceroy's Villa upgrade by spending diamonds instead of buying the event pass. For 2800 diamonds, I could definitely see many more players going for the calendar.


View attachment 9596
Well I mean the Skull Cave is crazy good efficiency wise - 1.5 FP/square, 5% att for att/square, 5% att for def/square. But is still ultimately only a single 2x2. A 4 square building that "saves" 19 squares (if you want everything it does). By comparison a Panda Shrine is a 22 square building that "saves" 40.
 
Top