# How can I examine the distribution of successes-counting mixed dice pools?

After looking at AnyDice's Documentation and Function Library, I remain baffled. I know that AnyDice can do this, but I don't know how to tell it to. Scott Gray's Dice Pool Generator is easier to use but doesn't return the results I need, or, at least, I lack arithmetic sufficient to force it to.

The mechanic uses a 6-die pool with a target number of 4. I need to know the percentage chances of rolling a 4 or higher on 1 or more, 2 or more, 3 or more, 4 or more, 5 or more, and all 6 dice in the pool using the following pools of dice:

• 6d4
• 5d4 and 1d6
• 4d4 and 2d6
• 3d4 and 3d6
• 2d4 and 4d6
• 1d4 and 5d6
• 6d6
• 5d6 and 1d8
• 4d6 and 2d8

... and so on until 6d12 becomes 5d12 and 1d20. I can do 6d4 and 6d6 myself, but I wanted the progression to be clear. (I'm skipping d14s and d16, by the way, because I couldn't find d18s, and most folks don't own d14s and d16s anyway.)

Can this be done?

By the way, the results needn't be from AnyDice--that's just frequently mentioned as a good odds generator. Results are the important part not the tool.

Here's the link to the program, and here it is in its entirety:

DICE:{4,6,8,10,12,20}
loop D over {1..(#DICE-1)}{
loop SECOND over {0..5}{
FIRST: 6-SECOND
FIRSTD: D@DICE
SECONDD: (D+1)@DICE
output [count {4..20} in FIRSTdFIRSTD] + [count {4..20} in SECONDdSECONDD] named "[FIRST]d[FIRSTD] and [SECOND]d[SECONDD]"
}
}

• That's... beautiful. Thank you. I'm gonna let the question sit for a day to be polite, but this is exactly what I needed. – Hey I Can Chan May 7 '14 at 6:23
• Is there a way to modify this program to include 14-, 16-, 24-, and 30-sided dice? – Hey I Can Chan May 17 '14 at 12:45
• Theoretically, all it takes is modifying the DICE array to include those values, like so: "DICE:{4,6,8,10,12,14,16,20,24,30}"; then changing the two instances of {4..20} to {4..30} to expand the range of values being counted as successes. However, including d24 and d30 in this program seems to overflow something in Anydice. Once you start using d20s though, you're almost guaranteed to roll high enough. – Magician May 18 '14 at 13:25
• @Macgian Adding d14s, d16s, and d24s works, but d30s leave the poor thing endlessly ...calculating... Weird. Thanks again. – Hey I Can Chan May 18 '14 at 14:05

As requested in the comments, here's my optimized version of Magician's code, using the die-relabeling trick instead of simply counting:

\ roll AdX + BdY, target 4, where X is one size less than Y and A+B = 6 \

DICE: {4,6,8,10,12,20}

loop I over {2..#DICE} {
X: (I-1)@DICE
Y: I@DICE

output 6d(dX >= 4) named "6d[X]"

loop B over {1..5} {
A: 6-B
output Ad(dX >= 4) + Bd(dY >= 4) named "[A]d[X] and [B]d[Y]"
}
}
output 6d(dY >= 4) named "6d[Y]"


This code will handle arbitrarily large dice (yes, really, even something crazy like d1000), and can also be easily modified to use a larger dice pool.

Looking at the averages, it's pretty clear that going up from d4 to d6 in the beginning, and from d12 straight to d20 in the end, give the most rapid increases in the success rate, while there's relatively little difference between, say, a d10 and a d12 in the middle of the progression.

For some purposes this kind of a curve, with rapid progress in the beginning that gradually slows down, before speeding up again at the final levels, might be exactly what you want. That said, if you'd prefer something a bit more linear, one way to speed up the middle part of the curve would be to drop the d10 from the progression, or, alternatively, to keep the d10 but drop both d8 and d12.

Ps. What's "the die-relabeling trick", you ask? Well, it turns out that, if you're rolling NdX and counting successes against some target number T, by far the most efficient way to do that in AnyDice is to first create a custom X-sided die with all the sides less than T relabeled as "0" and the rest as "1", and then roll that die N times.

The easiest way to do that is to take a single normal X-sided die and let AnyDice relabel it for you by applying a function or a comparison operator to it.

That is, instead of doing something like this:

output [count {4..20} in 6d20] named "6d20, target 4"


output 6d[count {4..20} in d20] named "6d20, target 4"


or just this:

output 6d(d20 >= 4) named "6d20, target 4"


Here, [count {4..20} in d20] (or, equivalently, d20 >= 4) is a custom 20-sided die with the sides 1–3 relabeled as "0" and the sides 4–20 relabeled as "1".

The last example above works because AnyDice comparison operators like >= return 1 for "true" and 0 for "false" and because comparing a die with a number applies the comparison to each roll of the die, relabeling the sides according to the result.

It's also possible to construct such relabeled dice "manually", without starting with a normal dX at all, e.g. like this:

output 6d{0:3, 1:17} named "6d20, target 4"


Here, d{0:3, 1:17} is a die with three sides labeled "0" and 17 sides labeled "1", for a total of 20.

I used to recommend this method in older versions of this answer, but I now feel that it's uglier and more prone to mistakes than just starting with a normal die and letting AnyDice relabel it for you.

You can check for yourself that all of these programs produce the same results, but the first one takes up to several seconds to run (and might time out, if the server is busy), while the other three finish instantly. And the bigger you make the dice, or the more dice you add to the pool, the more obvious the difference becomes. Trying to calculate, say, 8d20 vs. 4 in the naïve way is pretty much guaranteed to time out, whereas with relabeled dice the code will run pretty much instantly even for, say, 100d20 vs. 4.

The reason for this is that, if you pass a large dice pool to a function like [count ... in ...], AnyDice will waste a lot of time rolling all the possible outcomes of, say, 6d20, and then counting the number of successes in each of them — it's not smart enough to realize that, say, (2, 7, 8, 14, 16, 18) is just as good a roll as (2, 7, 8, 14, 16, 19), and that those cases don't really need to be considered separately. Using relabeled dice tells AnyDice that all the sides of the die equal to or greater than the target number really are equivalent, and so are all those less than the target.

Pps. One situation where the "manual" relabeling method can be useful is if you need a more complex relabeling scheme like, say, having a natural 20 count as two successes:

output 6d{0:3, 1:16, 2:1} named "6d20, target 4, double success on nat 20"


However, you can also achieve the same result with a custom relabeling function, e.g. like this:

function: relabel SIDE:n target TARGET:n {
if SIDE = 20 { result: 2 }
if SIDE >= TARGET { result: 1 }
result: 0
}
output 6d[relabel d20 target 4] named "6d20, target 4, double success on nat 20"


Using a helper function is more verbose, but it can also be a lot more readable, especially if the relabeling involves a bunch of special cases like autofail on natural 1, autocrit on natural 20, etc. In particular, note that the relabeling function can itself return a (relabeled) die to simulate a reroll, or even the "empty die" d{) to make AnyDice ignore that particular roll entirely, as if it never happened.

For even more control over the results (e.g. if certain rolls count as critical successes or fumbles that modify the outcome in some non-additive manner) you can also pass the results of rolling the relabeled dice into a function for further processing, like here. Often it's still useful to start with relabeling a single die, though, since letting AnyDice know that certain sides of the die are equivalent can make it handle large pools of such dice a lot faster.

GamesDice is a Ruby library that is aimed at slightly different use than AnyDice (mainly at Ruby developers who are looking for a library for manipulating and simulating dice systems).

Here is a Ruby script that uses GamesDice to calculate the odds. I won't post it here, if anyone has questions they can ask in comments on the gist, or on Stack Overflow.

Here is the output (now showing cumulative percentage of given number of successes or higher):

6d4, target 4+
1: 82.2%   2: 46.6%   3: 16.9%   4:  3.8%   5:  0.5%   6:  0.0%

5d4 + 1d6, target 4+
1: 88.1%   2: 56.5%   3: 23.5%   4:  6.0%   5:  0.8%   6:  0.0%

4d4 + 2d6, target 4+
1: 92.1%   2: 65.7%   3: 31.4%   4:  9.2%   5:  1.5%   6:  0.1%

3d4 + 3d6, target 4+
1: 94.7%   2: 73.6%   3: 40.2%   4: 13.7%   5:  2.5%   6:  0.2%

2d4 + 4d6, target 4+
1: 96.5%   2: 80.1%   3: 49.2%   4: 19.5%   5:  4.3%   6:  0.4%

1d4 + 5d6, target 4+
1: 97.7%   2: 85.2%   3: 57.8%   4: 26.6%   5:  7.0%   6:  0.8%

6d6, target 4+
1: 98.4%   2: 89.1%   3: 65.6%   4: 34.4%   5: 10.9%   6:  1.6%

5d6 + 1d8, target 4+
1: 98.8%   2: 91.0%   3: 69.5%   4: 38.3%   5: 12.9%   6:  2.0%

4d6 + 2d8, target 4+
1: 99.1%   2: 92.7%   3: 73.2%   4: 42.4%   5: 15.1%   6:  2.4%

3d6 + 3d8, target 4+
1: 99.3%   2: 94.1%   3: 76.7%   4: 46.6%   5: 17.7%   6:  3.1%

2d6 + 4d8, target 4+
1: 99.5%   2: 95.2%   3: 79.9%   4: 51.0%   5: 20.6%   6:  3.8%

1d6 + 5d8, target 4+
1: 99.6%   2: 96.2%   3: 82.8%   4: 55.3%   5: 23.8%   6:  4.8%

6d8, target 4+
1: 99.7%   2: 96.9%   3: 85.4%   4: 59.6%   5: 27.4%   6:  6.0%

5d8 + 1d10, target 4+
1: 99.8%   2: 97.4%   3: 86.9%   4: 62.2%   5: 29.6%   6:  6.7%

4d8 + 2d10, target 4+
1: 99.8%   2: 97.8%   3: 88.3%   4: 64.7%   5: 31.8%   6:  7.5%

3d8 + 3d10, target 4+
1: 99.9%   2: 98.1%   3: 89.7%   4: 67.3%   5: 34.2%   6:  8.4%

2d8 + 4d10, target 4+
1: 99.9%   2: 98.4%   3: 90.9%   4: 69.7%   5: 36.7%   6:  9.4%

1d8 + 5d10, target 4+
1: 99.9%   2: 98.7%   3: 92.0%   4: 72.1%   5: 39.3%   6: 10.5%

6d10, target 4+
1: 99.9%   2: 98.9%   3: 93.0%   4: 74.4%   5: 42.0%   6: 11.8%

5d10 + 1d12, target 4+
1: 99.9%   2: 99.0%   3: 93.6%   4: 76.0%   5: 43.8%   6: 12.6%

4d10 + 2d12, target 4+
1: 99.9%   2: 99.2%   3: 94.2%   4: 77.5%   5: 45.7%   6: 13.5%

3d10 + 3d12, target 4+
1:100.0%   2: 99.3%   3: 94.8%   4: 78.9%   5: 47.5%   6: 14.5%

2d10 + 4d12, target 4+
1:100.0%   2: 99.4%   3: 95.3%   4: 80.4%   5: 49.5%   6: 15.5%

1d10 + 5d12, target 4+
1:100.0%   2: 99.5%   3: 95.8%   4: 81.7%   5: 51.4%   6: 16.6%

6d12, target 4+
1:100.0%   2: 99.5%   3: 96.2%   4: 83.1%   5: 53.4%   6: 17.8%

5d12 + 1d20, target 4+
1:100.0%   2: 99.7%   3: 97.1%   4: 85.7%   5: 57.3%   6: 20.2%

4d12 + 2d20, target 4+
1:100.0%   2: 99.8%   3: 97.8%   4: 88.1%   5: 61.4%   6: 22.9%

3d12 + 3d20, target 4+
1:100.0%   2: 99.9%   3: 98.4%   4: 90.3%   5: 65.5%   6: 25.9%

2d12 + 4d20, target 4+
1:100.0%   2: 99.9%   3: 98.8%   4: 92.2%   5: 69.7%   6: 29.4%

1d12 + 5d20, target 4+
1:100.0%   2: 99.9%   3: 99.2%   4: 93.9%   5: 73.7%   6: 33.3%

6d20, target 4+
1:100.0%   2:100.0%   3: 99.4%   4: 95.3%   5: 77.6%   6: 37.7%


I hope this is useful.

On a positive note, it looks like AnyDice and GamesDice agree on this distribution!

I usually use Troll for probability calculations like this. It also produces graphs. A few examples:

count 4<= 6d4
0     17.798     100.000
1     35.596      82.202
2     29.663      46.606
3     13.184      16.943
4      3.296       3.760
5      0.439       0.464
6      0.024       0.024

count 4<= (4d6 @ 2d8)
0      0.879     100.000
1      6.445      99.121
2     19.434      92.676
3     30.859      73.242
4     27.246      42.383
5     12.695      15.137
6      2.441       2.441


There's a downloadable script in addition to the web interface, and while I'm entirely sure it's possible to write a full script that will count down the one number while counting up the next, I'm not as proficient with it as I once was and don't have an example.