Categories
Game Design

Core Mechanics: Mixed Dice Probabilities

I’ve recently purchased both Marvel Heroic Roleplaying and Savage Worlds. One thing those two games have in common is that they both have mechanics where different sizes of dice are rolled against one another. In Savage Worlds this is generally a single die of each size, but for Marvel it is pools of dice of mixed sizes being rolled. I wrote a Core Mechanics post on randomization last year, but I decided to write a follow-up specifically to look at the probabilities involved when dealing with mixed sets of dice.

How much better than a d4 is a d8?

When using mixed dice, the probabilities involved aren’t as clear as they are when all of the rolls use the same sized die (or dice). When rolling one die against another, you can find the probability with the following formula: P(dA ≥ dB) = (A + max(A – B + 1, 1)) × (A + 1 – max(A – B + 1, 1)) ÷ (2 × A × B). So for example, a d8 will beat a d4 about 81.3% of the time ((8 + 5) × (8 + 1 – 5) ÷ (2 × 4 × 8)). That formula isn’t exactly something that most people can compute on the fly though, so here’s a table with the results for the standard die sizes:

1d4 1d6 1d8 1d10 1d12 1d20
1d4 62.5% 41.7% 31.3% 25.0% 20.8% 12.5%
1d6 75.0% 58.3% 43.8% 35.0% 29.2% 17.5%
1d8 81.3% 68.8% 56.3% 45.0% 37.5% 22.5%
1d10 85.0% 75.0% 65.0% 55.0% 45.8% 27.5%
1d12 87.5% 79.2% 70.8% 62.5% 54.2% 32.5%
1d20 92.5% 87.5% 82.5% 77.5% 72.5% 52.5%

Marvel Heroic Dice Pools

For the system used in Marvel Heroic Roleplaying, you roll a large pool of dice and then take the highest two as your result. For example, you might roll 1d10, 1d8, 2d6 and end up with 6, 5, 4, and 2 as the die rolls which gives you a result of 11. In addition to your result, you also set aside one die not used in the sum as the effect die. The number showing on this die doesn’t matter, but instead you want to maximize the number of sides on the effect die. On top of that, dice that end up as 1s indicate complications and cannot be used in the result or as the effect die.

The probabilities involved are pretty complex, so rather than diving into a bunch of general computations, I’m going to break down some common choices that come up during play. I’ll be using Captain America in the examples since his data file is available as a free download from Margaret Weis Productions.

Let’s say that Captain America is stuck on his own and fighting against some Hydra soldiers with his shield. He can build his basic pool with Solo d6, Enhanced Strength d8, Weapon d8, and Combat Master d10, so let’s look at what that gives him as a baseline before we look at other options like distinctions and SFX. As an assumption to make things a little simpler, let’s assume that he wants to maximize his result rather than his effect die. That pool has a potential result range of 0 to 18 with the following probabilities:

Result Probability
0 0.03%
1 0.00%
2 0.10%
3 0.10%
4 0.39%
5 0.83%
6 1.69%
7 2.79%
8 4.53%
9 6.41%
10 8.85%
11 10.91%
12 12.79%
13 13.33%
14 12.63%
15 10.05%
16 7.84%
17 4.38%
18 2.34%

That data set has an average result of 12.35 and will most often end up with either a d8 effect die (51.6% of rolls) or a d10 effect die (31.0% of rolls). In addition, rolling that pool will result in an average of about 0.52 complications per roll with 42.6% of rolls having at least one complication.

Distinctions: d8, d4, or Neither?

On each roll, you can use one of your character’s Distinctions either as an advantage or a disadvantage. If you use the distinction as an advantage, you can add a d8 to your dice pool. On the other hand, if you use it as a disadvantage, you add a d4 to your dice pool and gain a Plot Point. It’s obvious that a d8 increases the odds of a high result, makes a better effect die, and has less chance of adding a complication, but how much does it actually affect the probabilities?

Using the baseline example above, let’s say that Captain America uses his Sentinel of Liberty distinction to add an extra d8 to the pool. This bumps up his average result to 13.19, but it also increases the average number of complications to 0.64 with 49.8% of rolls now having at least one complication. What I feel is the more meaningful impact of this choice is that it boosts the chance of having a large effect die with 56.6% of rolls now getting a d8 and 39.6% ending up with d10s.

If instead Captain America had used his Man Out of Time distinction to gain a Plot Point and add a d4 to the pool, then his average result would instead be 12.43 with an average of 0.77 complications per roll and 56.9% of rolls having at least one complication. The average result barely budged since the d4 is unlikely to be one of the top two dice, but the chance of a complication is noticeably higher than either the baseline or using the distinction as an advantage.

SFX: Step Up or Double?

Another common choice for characters in Marvel Heroic Roleplaying is to use a SFX option to either step up the size of a die or add another die of the same size to the pool. Both options will increase the average roll result and, assuming the die is towards the high-end for the pool, increase the chance of a larger effect die. Adding dice will always increase the chances of getting a complication, while stepping up a die will reduce the chance of complications.

For example, Captain America could use his Last Ditch Effort SFX to either increase his Enhanced Strength to a d10 or add a second d8 to the pool. In this case, adding another d8 will have the same effect as using a distinction as an advantage (average result of 13.19, average of 0.64 complications, 49.8% of rolls with at least 1 complication). On the other hand, stepping up the die changes the average result to 13.13 with a lower average of 0.49 complications per roll and only 40.9% of rolls having at least one complication. Stepping up to a d10 also greatly increases the chance of a higher effect die with 24.5% of rolls having a d8 effect and 58.5% having a d10 effect.

A Quick Summary

When rolling two different sized dice against one another, each step higher that your die is than the other results in roughly a 5-10% higher chance of rolling equal to or higher than your opponent.

In addition, here are some things to keep in mind when building dice pools in Marvel Heroic Roleplaying or other Cortex+ games:

  • Adding another die to the pool will always result in a higher chance of complications occurring.
  • Adding a d4 for a distinction likely won’t affect your roll’s result much, but increases the risk of a complication more than any other die type.
  • Adding a d8 for a distinction on an already large pool of 4+ dice doesn’t have a ton of impact on the average result, but can increase the chance of having a larger effect die.
  • Stepping up a die can really increase the chance of having a larger effect die while also decreasing the chance of complications.

By Scott Boehmer

A game enthusiast and software engineer.

16 replies on “Core Mechanics: Mixed Dice Probabilities”

Thanks for the analysis! The results aren’t surprising, I actually find it fairly intuitive. My stats is a bit rusty so I didn’t have the numbers crunched. This useful to keep in mind as players spend plot points to alter their die rolls. It makes me think that a pool of large dice is probably better served by spending the PP to keep an extra die for the total or adding a second effect.

Yeah, if you already have a large pool of dice, I’d recommend against spending PP to add more dice in most cases because you’ll probably get more benefit by spending the PP after the roll to add an extra die to the total or keep an extra effect die. On the other hand, if you only have a couple dice in your initial pool for an action, then using the PP to add more dice is a much better option.

One minor correction: you don’t have to take the two highest dice for your total. You can take any two. This does weird things because you may really want that d12 as an effect die and figure you may be ok with a slightly smaller total. Most of the time, though, I think people do go for the two highest rollers.

Cheers,
Cam

Right, these numbers assume that the player is trying to maximize the roll’s result and then always taking the remaining die with the most sides as the effect die. In actual play, there are a lot more options: taking a lower result for a better effect die, using plot points to boost the total, using multiple effect dice with area attack, etc.

Your first dice table is wrong in that you state “a d8 will beat a d4 about 81.3% of the time”. You should have said that “a d8 will beat or equal a d4 about 81.3% of the time”.
A d8 will have a higher number than a d4 about 68.8% of the time.
A d8 will have a lower number than a d4 about 18.8% of the time.
A d8 will equal a d4 about 12.5% of the time.

Adding 68.8% to 12.5% gives the 81.3% figure.
The same applies to all the figures you give in the table. They are all greater than or equal percentages.

After all, one d4 against a d4 will not win 62.5% of the time!
The correct odds are that each d4 will win 37.5% of the time. 25% will be ties.

Let me know if you agree – perhaps I have misunderstood what you were attempting to show. : -)

Hi Jan, you’re right that the probabilities in the table are for the first die’s result being equal to or greater than the second die’s result and the formula is for P(dA ≥ dB). That was the set of numbers that I decided to use because in many games an acting character will win a roll on a tie.

I wonder if you could share the methods / code you use to generate these numbers. Since I get consistently lower averages. But my complication probabilities are spot-on.

These are the averages I get:
> cortexavg([d6, d8, d8, d10]);
11.803054
> cortexavg([d6, d8, d8, d10, d4]);
11.871336
> cortexavg([d6, d8, d8, d10, d8]);
12.695276
> cortexavg([d6, d8, d10, d10]);
12.078522

All of these numbers are generated by averaging 1,000,000 rolls of the dice pool, and taking the highest two (I also correct for the ones being removed).

I tested my dice functions (by rolling a d10 1,000,000,000 times). They check out. And the complication numbers I get are exactly the same as you. So I’m doing something right…

Hope you can help.

I had written a program that essentially builds a table of all possible results and then groups those by result to compute the percentages. I’ll see if I can find the code for it.

I’ve also implemented your method now. Still the same results:

cortexenumavg([m6, m8, m8, m10])
11.804166666666667
cortexenumavg([m6, m8, m8, m10, m4])
11.869270833333333
cortexenumavg([m6, m8, m8, m10, m8])
12.691927083333333
cortexenumavg([m6, m8, m10, m10])
12.076666666666666

Here is my code. It’s JavaScript code, so run it in node.js or in the developer console of your browser:

(I need to add comments…)

var m4 = [1, 2, 3, 4];
var m6 = [1, 2, 3, 4, 5, 6];
var m8 = [1, 2, 3, 4, 5, 6, 7, 8];
var m10 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
var m12 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];

var flatten = function(l) {
return l.reduce(function(m, x) {
if (x.length) m = m.concat(x);
return m;
}, []);
};

var first = function(list) {
return list[0];
};

var rest = function(list) {
return list.slice(1);
};

var sum = function(list) {
return list.reduce(function(total, value) {
return total == 0 ? value : total.map(function(val, index) {
return val + value[index];
});
}, 0);
};

var enumerate = function(lists) {
if (!lists || lists.length == 0) return [];
if (lists.length == 1) return first(lists);
return flatten(first(lists).map(function(value) {
return enumerate(rest(lists)).map(function(value2) {
return [value].concat(value2);
});
}));
};

var cortex2 = function(rolls) {
return rolls.sort().reverse().map(function(roll) {
return roll == 1 ? 0 : roll; // turn the ones into zeros, so we don’t accidentally add them to the total
}).reduce(function(rolls, roll) {
return [rolls[0] + (rolls[2] < 2 ? roll : 0), rolls[1] + (roll == 0 ? 1 : 0), rolls[2] + 1];
}, [0, 0, 0]);
};

var cortexenum = function(dice) {
return sum(enumerate(dice).map(cortex2)).map(function(value) {
return value / dice.reduce(function(total, die) {return total * die.length}, 1);
});
};

cortexenum([m6, m8, m8, m10])

I’ve rerun my app and confirmed my earlier results:

average(d6,d8,d8,d10) = 12.347
average(d4,d6,d8,d8,d10) = 12.426
average(d6,d8,d8,d8,d10) = 13.188
average(d6,d8,d10,d10) = 13.131

After a bit of debugging, I think you’re running into unexpected behavior of JavaScript’s sort() function. I’m seeing [1,2,4,10].sort() result in [1,10,2,4] rather than [1,2,4,10] because it is sorting as strings rather than as numbers. That would cause your average to be lower for any pool with a d10 or d12 in it.

I’ll post a cleaned up version of my C# code soon.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s