Jump to content
The Lotus Eaters: Share Bug Reports and Feedback Here! ×
  • 0

Warframe Blueprint Drop Chances


Ozlol
 Share

Question

Greetings,

 

So lately after farming for some warframes, I started wondering about the likelihood to obtain all blueprints after doing couple runs. So to quench my curiosity, I wrote a small program that simulates boss runs and the corresponding blueprint drops.

 

Of the data I found across three warframe posts (see below for the reference to the original posts), the likelihood to obtain all blueprints for the following warframes are:

 

Rhino Warframe Drop Chance

fDqmzrr.png

If attempting 9 runs, you have a ~90% chance of obtaining all parts of Rhino.

 

Excalibur Warframe Drop Chance

IY7vTdh.png

90% of the time after doing 29 runs, you will obtain 

If attempting 11 runs, you have a ~90% chance of obtaining all parts of Excalibur.

 

Nyx Warframe Drop Chance

DHEZQvJ.png

If attempting 13 runs, then you have a ~90% chance of obtaining all parts of Nyx.

 

Some Unfortunate Warframe Drop Chance

0UZOOh6.png

If attempting 29 runs, then you have a ~90% chance of obtaining this all parts of this unfortunate Warframe.

 
The real point of interest is the cumulative probability (green line) as opposed to the probability (red line). The cumulative probability (green line) gives the probability of obtaining all Warframe parts during any of the consecutive runs. On the other hand, the probability (red line) gives the probability of obtaining all Warframe parts in exactly some specified runs. So for instance looking at Nyx's graph, we have a ~0.05 chance of all Nyx parts dropping after exactly 10 runs but we have a ~0.80 chance of getting all Nyx parts in any of the runs leading up to the 10th run.
 
A Bit About The Graphs:
The graphs are obtained through numerical means so there is some small error between them and reality but nothing significant. Crudely speaking, each graph simulates 50 consecutive boss runs and repeats this process 100,000 times to arrive at a better average of the probabilities (so a total of 5,000,000 runs).
 
As for the correctness of the model, I calculated the theoretical values of some data points which fit in well with the graphs. Also, the calculated drop chances of each item after running the consecutive runs simulation only differs by a fraction from the theoretical values (which are the ones displayed in the legend of the graphs). So it seems to be fine.
 
If anyone wants some more graphs posted, then I can gladly do so but I will require the drop chance of each individual item.

 

Misconceptions:

 

Question: Does that mean after I do 11 runs of Excalibur, that my chances of getting the last piece (say item 'c') is roughly above 90% on the 12th and subsequent runs?

 

Answer: No, that isn't true, that is known as the Gambler's Fallacy. For the 12th run, your probability of obtaining the last item (item 'c') will still 40% as always.

 

If you have completed 11 runs and not all your Warframe parts have dropped, then the next subsequent run will not have an above 90% drop chance. But, if you start a new second series of 11 runs from this point, then over the span of those runs, you have a chance at least greater than ~90% of obtaining all parts (it's actually ~99.7%). The second series of 11 runs have a higher probability than the first series of 11 runs because they assume you already have 2/3 pieces within possession. And now suppose after completing the second series of runs (so a total of 22 runs so far), the last piece didn't drop unfortunately. Then, if you complete a third series of 11 runs, you would still have a ~99.7% chance of getting the last piece (with a total of 33 runs).

 

This probability differs from if you initially attempted to complete a series of 33 runs without 'stopping' (which is ~99.9%). Why? Because in the case of where we 'stopped', the probability of obtaining all the parts didn't proc in the first nor second series of 11 runs. So we only had 11 more tries as oppose to 33 hence the probability being less (even though we had 2/3 items already which increased it).

 

On a side note, the probability mentioned in the question is cumulative so that implies when looking at the corresponding runs, they essentially mean from any number of runs less than or equal to the run.

 

 

Code:

As for those interested in the code, it's done in Python using numpy and matplotlib:

 

# Calculates the cumulative probability of obtaining all n items from a# a boss after some k runs. We assume that each item has an equal chance# of dropping. We resort to numerical estimations in doing so. import matplotlib.pyplot as pltimport numpy as npimport string as string class Item():    """    Representation of an in-game item that can be dropped.    """     itemsGenerated = 0     def __init__(self, probability=0.0, isWanted=True):        """        Assigns an alphabet ID to the item generated and initializes.        """        self.id = string.ascii_lowercase[Item.itemsGenerated]        Item.itemsGenerated += 1         self.probability = probability        self.isWanted = isWanted         self.hasDroppedRecently = False     # Flag used to simplify code        self.totalDrops = 0        self.totalAttempts = 0 class Instance():    """    Representation of an in-game instance which drops items.    """     def __init__(self, itemsList):        """        Constructs the instance. Extracts the total amount of wanted items        to be dropped. Also, extracts the probabilities for each item to be        dropped.        """        self.runNum = 1        self.totalAttempts = 0        self.totalWantedItems = 0        self.droppedWantedItems = 0         self.itemsList = itemsList        self.itemsProbabilityList = []        for item in itemsList:            self.itemsProbabilityList.append(item.probability)            if(item.isWanted):                self.totalWantedItems += 1     def plotSimulationProbabilities(self, maxRuns, iterations=10000):        """        maxRuns - maximum number of boss runs         Plots the probability and cumulative probability of successfully getting        all items from the boss against the number of runs on a 2D graph using        matplotlib.        """         title = "Items Dropped By Boss: {} ({})"\            .format(len(self.itemsList), iterations)        fileName = "Items {} Iterations {}"\            .format(len(self.itemsList), iterations)         # Initializing the y-axis tick marks        yticksList = []        for i in range(11):            yticksList.append(i/10)         # Generating the data        runList, runsProbabilityList, runsCumulativeProbabilityList = \            self.generateData(maxRuns, iterations)         # Plotting the data        fig = plt.figure()        fig.canvas.set_window_title(fileName)        subplot = fig.add_subplot(111)         plt.plot(runList,                 runsProbabilityList,                 color="r",                 label="Probability")        plt.plot(runList,                 runsCumulativeProbabilityList,                 color="g",                 label="Cumulative Probability")         # Shrinking graph to allow extra information to be placed on the it's        # right (items and their drop chances)        box = subplot.get_position()        subplot.set_position([box.x0, box.y0, 0.8*box.width, box.height])         for i, item in enumerate(self.itemsList):            plt.figtext(0.78, 0.7 - i/20,                        "Item {}: {:<3.0f}%"                        .format(item.id, 100*item.probability),                        bbox=dict(facecolor="white", alpha=0.5, width=130),                        fontweight='bold',                        fontsize=12)         # Adjusting graph settings        plt.title(title, fontweight="bold")        plt.legend(loc='upper right', fontsize=12)        plt.ylabel('Probability')        plt.yticks(yticksList)        plt.ylim(plt.ylim()[0], 1.2)        plt.xlabel('Runs')         plt.show()     def generateData(self, maxRuns, iterations=10000):        """        Executes the consecutive runs simulation, obtains data, calculates        probabilities for each set of successful consecutive runs, then returns        the processed data ready to be plotted.        """         runsDroppedDict = self.simulateConsecutiveRuns(maxRuns, iterations)         return self.calculateSimulationProbabilities(runsDroppedDict)     def simulateConsecutiveRuns(self, maxRuns, iterations=10000):        """        maxRuns     - maximum number of tries        iterations  - number of times to repeat the consecutive runs         Per iteration, generates a consecutive sequence of runs until the upper        limit is reached or until all the items have dropped in the sequence.         Returns a dictionary that contains items of form (runNumber : Number        of times successfully obtained all wanted items)        """         runsDroppedDict = {i:0 for i in range(1, maxRuns+1)}         # Generating Data:        # The inner while-loop represents items dropping in consecutive runs up        # to a maximum of maxRuns runs. The outer-loop is solely to repeat this        # process multiple times for a better numerical solution.        for _ in range(iterations):            # Initialization per new series of runs            self.reset()             while(self.runNum <= maxRuns):                self.dropItem()                 # Checks if all items have dropped yet                if(self.haveAllItemsDropped()):                    runsDroppedDict[self.runNum] += 1                    break                 self.runNum += 1         return runsDroppedDict     def calculateSimulationProbabilities(self, runsDroppedDict):        """        Calculates the probabilities from the data generated by the        simulation function. The runs, probabilities and cumulative        probabilities are calculated.        """         dimension = len(runsDroppedDict)         runsList = dimension*[0]        runsProbabilityList = dimension*[0]        runsCumulativeProbabilityList = dimension*[0]         # Calculating Data:        # The probabilities of successful runs        print("\nProbabilities:")        for i, (run, drops) in enumerate(runsDroppedDict.items()):            runsList[i] = run            runsProbabilityList[i] = drops / self.totalAttempts            print("Runs: {:<3} {:<3} Probability: {:<3.4f}"                  .format(run, "||", runsProbabilityList[i]))         # The cumulative probabilities of successful runs        runsCumulativeProbabilityList =\            self.calculateCumulativeProbabilities(runsProbabilityList)        print("\nCumulative Probabilities:")        for i, _ in enumerate(runsCumulativeProbabilityList):            print("Runs: {:<3} {:<3} Cumulative Probability: {:<3.4f}"                  .format(runsList[i], "||", runsCumulativeProbabilityList[i]))         # The estimated drop chance of each item        print("\nItem Drop Chances From Simulation Data:")        for item in self.itemsList:            print("Item '{}' drop chance in sample: {:.4f}"                  .format(item.id, item.totalDrops/item.totalAttempts))         return runsList, runsProbabilityList, runsCumulativeProbabilityList     def dropItem(self):        """        Selects an item to drop based on weighted probabilities and updates        the instance correspondingly.        """        itemChosen = np.random.choice(self.itemsList,                                      p=self.itemsProbabilityList)         # Updates by checking if the item is wanted and has dropped before        if(itemChosen.hasDroppedRecently is False):            itemChosen.hasDroppedRecently = True            if(itemChosen.isWanted):                self.droppedWantedItems += 1         # Updates by incrementing the drop variables of the item objects        itemChosen.totalDrops += 1        for item in self.itemsList:            item.totalAttempts += 1     def haveAllItemsDropped(self):        """        Checks whether all wanted items have dropped from the instance.        """        if(self.droppedWantedItems == self.totalWantedItems):             return True        else:            return False     def reset(self):        """        Resets the instance to allow a new set of consecutive runs.        """        self.totalAttempts += 1         self.runNum = 1        self.droppedWantedItems = 0        for item in self.itemsList:            item.hasDroppedRecently = False     def calculateCumulativeProbabilities(self, probabilityList):        """        Calculates and returns the cumulative probabilities list when given a        probability list.        """        cumulativeProbability = 0        cumulativeProbabilityList = []         for probability in probabilityList:            cumulativeProbability += probability            cumulativeProbabilityList.append(cumulativeProbability)         return cumulativeProbabilityList def main():    """    Creates items, then runs the simulation with the specified items and    subsequently plots.    """    iterations = 100000    runs = 50     item1 = Item(8/10)    item2 = Item(1/10)    item3 = Item(1/10)    itemsList = [item1, item2, item3]     instance = Instance(itemsList)    instance.plotSimulationProbabilities(runs, iterations) if __name__ == "__main__":    main()

 

References and many hats off to fellow Tennos:

Nyx: https://forums.warframe.com/index.php?/topic/195825-thank-you-phorid/#entry2276005

Rhino: https://forums.warframe.com/index.php?/topic/206582-warframe-part-drop-rates-experiments/

Excalibur: https://forums.warframe.com/index.php?/topic/119448-drop-proportions-of-warfarme-blueprints/ 

Edited by Ozlol
Link to comment
Share on other sites

0 answers to this question

Recommended Posts

There have been no answers to this question yet

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...