The answer I posted to a similar question can be pretty easily generalized to handle this:
function: sum IDX:s in A:s B:s {
result: IDX@[sort {A, B}]
}
output [sum {1,2} in 2d10 1d8] named "highest 2 of 2d10 and 1d8"
output [sum {2,3} in 2d10 1d8] named "lowest 2 of 2d10 and 1d8"
The trick is that, when you pass a die (like 2d10
) to a function expecting a sequence (like A:s
) here, AnyDice will automatically evaluate the function for all the possible rolls of the dice (e.g. {1,1}
, {1,2}
, {1,3}
and so on up to {10,10}
) and return a new die (i.e. a probability distribution) consisting of the outputs of the function weighted by their likelihood. If you have two or more such parameters, like here, AnyDice will do the same for all possible combinations here.
So the function defined here will receive a single sequence named IDX
(which tells it which of the sorted dice to sum and return), and two sequences named A
and B
corresponding to the two types of dice rolled. (In this example, sequence A
will always contain two numbers between 1 and 10, and sequence B
will just contain one number between 1 and 8.) It will then concatenate these sequences, sort the resulting sequence in descending order, and then pick the elements given by the index list IDX
from the sorted sequence and sum them. (That's what seq @ seq
does in AnyDice; see the section titled "Introspection" in the docs for details.)
The only somewhat annoying limitation is that if you want to make the function handle pools with more than two types of dice, you'll need to add more parameters to the function signature. Of course, while you're at it, you could always add a few extra ones "for future expansion", and just pad them with empty sequences when calling the function, like this:
function: sum IDX:s in A:s B:s C:s D:s E:s {
result: IDX@[sort {A, B, C, D, E}]
}
output [sum {1,2} in 2d10 1d8 {} {} {}] named "highest 2 of 2d10 and 1d8"
output [sum {2,3} in 2d10 1d8 {} {} {}] named "lowest 2 of 2d10 and 1d8"
Also, while taking an explicit list of indices to sum makes the function above nice and flexible, it might be a bit inconvenient if you, say, always want to sum the n lowest dice in a pool of variable size. In that case, you can use introspection to find the size of the dice pool inside the function, and base the indexing on that:
function: highest N:n of A:s B:s C:s D:s E:s {
result: {1..N} @ [sort {A, B, C, D, E}]
}
function: lowest N:n of A:s B:s C:s D:s E:s {
S: [sort {A, B, C, D, E}]
result: {#S-N+1 .. #S} @ S
}
output [highest 2 of 2d10 1d8 {} {} {}] named "highest 2 of 2d10 and 1d8"
output [lowest 2 of 2d10 1d8 {} {} {}] named "lowest 2 of 2d10 and 1d8"
(Note: While testing this code, I found what seems like a bug in AnyDice: passing 0dX
, for any X
, into a function expecting a sequence will turn it into a one-element sequence containing a single zero, rather than an empty sequence. Using {}
does produce an actual zero-length sequence, however.)