# How can I model the probabilities for this mechanic involving cancelling out dice pools in AnyDice?

So I'm struggling with the probabilities for a dice mechanic.

You create a d6 pool of Edge dice and Snag dice and roll all of them.

Each Snag die cancels an Edge die of a lower value.

After cancelling out, you pick the single highest Edge die left.

If no Edge dice are left, you pick the single lowest Snag die.

If there's no die left, consider the result a 1.

Example 01: I roll 3 Edge dice {3, 5, 5} and 2 Snag dice {5, 6}. Result: 5

Example 02: I roll 2 Edge dice {3,4} and 4 Snag dice {2, 3, 5, 5}. Result: 2

Example 03: I roll 1 Edge die {3} and 1 Snag die {5}. Result: 1

Would you guys help me model it on AnyDice?

• Do the edge dice always cancel in ascending order? So E{1,2,3} and S{4,4} cannot yield 1 or 2 (which is valid based on your rules above where it just cancels any die of lower value) Jul 8, 2019 at 16:34
• Welcome to RPG.SE! Take the tour if you haven't already, and check out the help center for more guidance. I assume this is a homebrew mechanic unassociated with any existing RPG? (I ask because if it were associated with a particular RPG, tagging it with that system could help attract experts in that system to the question.)
– V2Blast
Jul 8, 2019 at 21:41
• Hi! Yes,it is a homebrew! Should I clarify it with an edit? Jul 9, 2019 at 13:18

## Anydice program

I've written the following anydice function which I think implements your desired mechanic, as described. I have assumed that, when cancelling, the highest snag die cancels the highest edge die that it can, and then so on descending from there.

function: edgesnag EDGE:s SNAG:s {
loop X over {1..#EDGE} {
if X@EDGE >= X@SNAG { result: X@EDGE }
}
if #EDGE < #SNAG { result: #SNAG@SNAG }
result: 1
}


This function expects to be invoked with two dice pools, e.g. [edgesnag 2d6 3d6].

So the way this works is that we cast the die pools to sequences, to fix them for inspection, and then we'll loop over those sequences to compare the dice. Remember that by default therefore anydice sorts the pool in descending order (so a roll like 3, 5, 3 becomes {5,3,3}). We thus consider the dice in the two sequences in pairs.

If the first die in the EDGE sequence is greater than or equal to the first die in the SNAG sequence, we are already certain that this edge die will not be cancelled by any snag dice, so it will remain at the end and is therefore the result. Otherwise, the snag die cancels the edge die, and we loop on to the next pair, comparing them in the same way.

If we run out of snag dice to cancel edge dice without finding a keeper, we'll take the edge die we're currently considering as the highest remaining result (the value of a nonexistent element in a sequence is 0, so the check will favour the edge die). Otherwise, the loop will continue until we run out of edge dice.

If we run out of edge dice, and there were more snag dice than edge dice, snag dice must remain and so the result will be the smallest snag die. Otherwise, it must be the case that no dice remain, and the result is 1.

It is necessary for us to optimise the algorithmic implementation of your mechanic in this way because otherwise, anydice will choke pretty quickly on relatively small dice pools. Even as it is, it can just about handle [edgesnag 5d6 5d6]; beyond this, the possible sequence permutations are too large and it chokes. (Some greater anydice expert might be able to further optimise it past this limitation but this is as far as I go.)

## Observations

A couple of observations about your mechanic.

Firstly, because snag die only cancel lower edge die, an edge die of 6 will never be cancelled, this skews your results very heavily towards sixes - no matter how large the snag dice pool is, it doesn't change the odds of getting a result of 6, only alters the rest of the distribution.

You also get some funky crossover points where your average result improves when you have more snag die, because you can only ever end up taking the lowest snag die when snag dice outnumber edge dice, and the lowest snag die might be greater than 1. For instance, if your edge pool is 1d6, and your snag pool is 1d6, your average result is 2.94; but if your snag pool is 2d6, you average 3.66, or 3.17 for 3d6. (anydice link)

• My original idea was for snag dice to cancel lower or equal edge die, but I felt it punished players too much. I might be wrong, though. I assume removing the equal sign at the third line wouldbe enough to test it, am I right? Also, maybe if all dice are cancelled, roll 1d6 and keep that as a result? Your observations made me realize this mechanic is probably broken. I tried to mend it, but... function: edgesnag EDGE:s SNAG:s { loop X over {1..#EDGE} { if X@EDGE > X@SNAG { result: X@EDGE } } if #EDGE < #SNAG { result: #SNAG@SNAG } result: 1d6 } Jul 9, 2019 at 13:31
• The proposed change still has a bit of an issue where occasionally more snag dice are better (compare [snagedge 2d6 1d6] and [snagedge 2d6 2d6] for example). But yes, changing the comparison to a straight > rather than >= represents snag dice cancelling equally or lesser edge die. Jul 9, 2019 at 14:16
• I see. How about I keep the lowest result anyway, instead of cancelling, even if the last two dice match? (Should I post this as another question?) Jul 11, 2019 at 14:44
• SE the site isn't a good fit for workshopping mechanical ideas in progress (though with context we can review a proposed mechanic based on what you're trying to achieve) - maybe you could pop into the Role-playing Games Chat if you want to discuss your ideas, many of the regulars enjoy chatting about that kind of thing! Jul 11, 2019 at 15:09