Here's one way to do it.
First, let's simplify the problem a little by relabeling the sides of the dice with the number of points needed to upgrade them into a success. So 5 and 6 become 0, 4 becomes 1, 3 becomes 2, and so on.
In AnyDice, we can construct such a relabeled die D
e.g. like this:
MIN_SUCCESS: 5
D: [highest of 0 and MIN_SUCCESS - d6]
or, if you prefer, manually like this:
D: d{4, 3, 2, 1, 0, 0}
Next, let's write a function that takes a bunch of numbers rolled on such relabelled dice (as a sequence, in descending order by value) and a number of points and returns the maximum number of successes we can obtain from them.
We can do this by looping over the sequence of rolls (in reverse order, i.e. from lowest to highest) and, if we still have points left to upgrade the roll into a success, incrementing a success counter and decrementing the number of points left:
function: successes in ROLL:s with POINTS:n points {
SUCCESSES: 0
REMAINING: POINTS
loop X over [reverse ROLL] {
if X <= REMAINING {
SUCCESSES: SUCCESSES + 1
REMAINING: REMAINING - X
}
}
result: SUCCESSES
}
Note the :s
that tells AnyDice that the ROLL
argument should be a sequence. When we call this function with a dice pool (e.g. 6dD
) as the first argument, like below, AnyDice will automatically call it for each possible result of the roll (sorted in descending order by default) and collect the results into a custom die weighted by their probability:
output [successes in 6dD with 3 points]
If we want, we can also use a loop to produce multiple outputs from the code and compare them, e.g. like this:
N: 6
loop P over {0..5} {
output [successes in NdD with P points] named "[N]d6 with [P] points"
}
And there we go, that's the whole script.