# Modelling an opposed dice pool mechanic in AnyDice

I humbly request an AnyDice program for this mechanic:

1. The attacker (A) rolls a number of d6 based on his parameters. The defender (D) rolls a number of d6 based on his parameters.

2. The highest die rolled by A sets the target number for B's dice.

The highest die rolled by B sets the target number for A's dice.

3. A counts his rolled dice that generated a number meeting or exceeding the target number determined by B's roll.

B counts his rolled dice that generated a number meeting or exceeding the target number determined by A's roll.

4. If A has more successes, he wins. If B has more successes, he wins.

Example 1: A rolls [6, 6, 4, 3, 3, 2]. B rolls [4, 2, 2, 2]. A's TN is 4. B's TN is 6. A scores 3 successes (6, 6, 4). B scores 0 successes. A wins.

Example 2: A rolls [6, 6, 5, 3, 1, 1]. B rolls [6, 6, 6, 2]. A's TN is 6. B's TN is 6. A scores 2 successes (6, 6). B scores 3 successes (6, 6, 6).

Depending on the probability of a tie, a tie-breaker mechanic could be introduced: in the case of a tie, both A and B remove their tied highest dice, then proceed to count successes using the new highest dice as target numbers. Using the latter example, A and B would each remove two 6s. Thus, A's new TN is 6. B's new TN is 5. A scores 0 successes. B scores 1 success.

• Unless I'm mistaken, one side automatically has 0 successes unless both happen to roll the same highest number. Is that intentional?
– Erik
May 27, 2015 at 19:52
• You are correct. It is not exactly intentional, but not necessarily a flaw. In the end, only the winner's successes matter, making this flaw (as far as I can tell) negligible. May 27, 2015 at 19:56
• So this is essentially a fancy tie-breaker for a Nd6-keep-highest pool mechanic? May 27, 2015 at 20:00
• Except for the fact that you keep a variable number of dice (depending on the highest die of the opposition) and call them successes, yes. I believe Ironclaw uses a similar system, except it uses dice of all sizes. May 27, 2015 at 20:33
• I have started on a small program for an answer here, but it's late and it's both unfinished and doesn't actually work for some reason I can't figure out. Maybe someone can salvage it for an answer. May 27, 2015 at 21:16

Here's a straightforward brute-force solution:

function: compare A:s vs B:s {
SA: A >= 1@B
SB: B >= 1@A
result: (SA > SB) - (SA < SB)
}
output [compare 5d6 vs 4d6]


It just iterates over all the possible rolls for each player (this happens automatically in AnyDice when you pass dice to a function expecting sequences), calculates the number of successes for each player, and returns -1, 0 or +1 depending on whether A got less then, as many as or more successes than B.

Implementing the tie-breaker turns out to be even simpler:

function: compare A:s vs B:s {
result: (A > B) - (A < B)
}
output [compare 5d6 vs 4d6]


The reason this works is that, when you compare two sequences in AnyDice, they're compared lexicographically from left to right (i.e. from highest to lowest, in the default sort order). Thus, e.g. {6,5,5,1} > {6,5,4,4} is true (i.e. returns 1), because the first two elements of both sequences are equal, but the third element is greater in the first sequence.

(A bit confusingly, comparing a sequence to a number does something different: it compares the number to each element in the sequence, and returns the number of elements for which the comparison is true. And comparing a sequence to a die does something different again. It doesn't help that the documentation is kind of ambiguously phrased, and could be interpreted to mean that comparing two sequences would return the number of successful comparisons between respective elements. A quick test will show that this is not the case, however.)

As it happens, this is precisely equivalent to your tie-breaking rule, at least as far as determining the winner goes. To show why, let me first write your rules in a more compact (but hopefully obviously equivalent) form:

1. If one player's highest die is greater than the other's (or if only one player has any dice left and the other doesn't), that player wins.
2. If the highest dice are tied, the player with more of those dice wins.
3. (tie-breaker) If the players have the same number of highest dice, those dice are discarded, and we repeat from step 1. (If both players simultaneously run out of dice, the roll is a perfect tie. This can only happen if both players have the same number of dice to begin with.)

Now, it should not be hard to see that steps 2 and 3 above can equivalently be replaced with the following alternative rule:

1. (alternative) If the highest dice are tied, discard (only!) those two dice, and repeat from step 1.

Clearly, if one player would win under the original rule 2, they will also win under (sufficiently many iterations) of the alternative rule 2. Similarly, if the players' highest dice are tied, and get discarded under the original rule 3, it should be clear that applying the alternative rule sufficiently many times will accomplish the same result.

I think this will do it: http://anydice.com/program/627f

I have not implemented the tie breaker.

function: sign S:s {
if S>0 { result: 1 }
if S<0 { result: -1 }
result: 0
}

function: A:n beats B:n {
B_DICE: Bd6
A_MAX: [highest 1 of A_DICE]
B_MAX: [highest 1 of B_DICE]

WINS: [count B_MAX in A_DICE]-[count A_MAX in B_DICE]

result: [sign WINS]
}

loop A over {1..5} {
loop B over {1..5} {
output [A beats B] named "[A] beats [B]"
}
}

• I'm pretty sure this is wrong; it certainly doesn't give the same results as my code. I believe the main bug is that, in your code, A_DICEand B_DICE are dice instead of sequences: the reason this matters is because AnyDice will treat each use of those variables as a separate, independent Ad6 or Bd6 roll. See this program for a simple demonstration. Jul 29, 2015 at 17:11