AnyDice handles exploding dice in a peculiar fashion that's poorly-suited for roll-and-count dice pools. I have cobbled together a somewhat inelegant solution, but it appears to work correctly.
Here's the link to the program.
Instead of using dice in the usual manner, I've created several functions that, given parameters of a die, return its output, i.e. the number of successes it has produced.
function: roll ROLL:n threshold T {
if ROLL >=T {result: 1}
result: 0
}
function: rollexploding ROLL:n threshold T{
if ROLL =6 {result: 1+[rollexploding 1d6 threshold T]}
result: [roll ROLL threshold T]
}
function: rerollfailures ROLL:n threshold T{
if ROLL < T {result: [roll 1d6 threshold T]}
result: [roll ROLL threshold T]
}
function: rerollthenexplode ROLL: n threshold T {
if ROLL < T {result: [rollexploding 1d6 threshold T]}
result: [rollexploding ROLL threshold T]
}
Then I made a wrapper function that would figure out which of these functions to call, and handle requests for multiple dice being rolled:
function: wrapper DICE:n threshold T explode E reroll R{
RES:0
loop N over {1..DICE} {
if E & R {RES: RES+[rerollthenexplode 1d6 threshold T]}
else {if E {RES:RES+[rollexploding 1d6 threshold T]}
else {if R {RES:RES+[rerollfailures 1d6 threshold T]}
else {RES:RES+[roll 1d6 threshold T]}
}
}
}
result:RES
}
Finally, I made a bunch of functions that simplify input by providing pre-determined combinations of parameters. I'll provide only 3 of them here:
function: b DICE:n{
result:[wrapper DICE threshold 4 explode 0 reroll 0]
}
function: be DICE:n{
result:[wrapper DICE threshold 4 explode 1 reroll 0]
}
function: gr DICE:n{
result:[wrapper DICE threshold 3 explode 0 reroll 1]
}
To use it, type things like output [b 4]
What you need to do is have your conditional inside a function with a number parameter. Then when you pass it a die, anydice will roll the die at that time and use the result in the function.
function: X:n conditional {
if X = 1 {execute arbitrary code here}
if X = 2 {execute arbitrary code here}
if X = 3 {execute arbitrary code here}
if X = 4 {execute arbitrary code here}
if X = 5 {execute arbitrary code here}
if X = 6 {execute arbitrary code here}
}
output [d6 conditional]
There are some slightly more practical examples of this technique in my answer here.
Best Answer
As a minor addendum to Someone_Evil's answer, their program will run a lot faster if you replace the line:
with:
The only difference is that I've relabeled the sides 1–11 on the initial dice with the number 0. The reason this makes the code faster is that, instead of having to call the function for all the \$\frac{12 \cdot 13}2 = 78\$ possible ordered 2d12 rolls, AnyDice now has to call it for only three possible rolls: {0, 0}, {12, 0} and {12, 12}. Since the function only counts the number of 12s in the roll, the results are still the same.
BTW, here's another solution using (almost) no functions:
Unfortunately, it seems that AnyDice will raise an error if you try to evaluate the expression
P@S
whereP
is a die instead of a number, even though it has a perfectly meaningful and useful interpretation consistent with AnyDice's usual handling of dice in numeric expressions (i.e. evaluate the expression for every possible roll of the dice and collect the results into a custom die). Wrapping the expression in a trivial helper function works around this seemingly arbitrary limitation.So, how does it work?
dX = X
yields, in effect, a custom dX with the highest side relabeled "1" and all other sides relabeled "0".Nd(dX = X)
rolls N of these dice, effectively giving the number of X rolls on NdX.TARGETS
sequence (via the helper function, since AnyDice refuses to let us do it otherwise), thus mapping each possible value ofNd(dX = X)
to a distinct element of the sequence: in this case 0 → 12 (which is an impossible target to exceed with a d12), 1 → 7 and 2 → 4.Note that we had to include the impossible target value 12 at the beginning of the
TARGETS
sequence to account for the possibility of the player rolling no twelves on any of the initial dice. Of course, if you wanted to experiment with the possibility of letting the player have a chance to crit even in this case, you could specify some lower (and thus actually achievable) target value here instead.