I'm trying to check the probabilities of rolling 2d20, and dropping the farthest from ten using anydice. (i.e. "Most Average" weighted roll, similar to 5e advantage/disadvantage. Basically you'd always roll 2, and drop one based on adv/std/dis.) I'm having trouble with the syntax. I can lay out the nested if/then statements, I think but it's not working out, and I don't really understand it from the documentation.

Because I want to maintain the 5% ish criticals, I need to reconsider them, and I think they'll still work with Adv/Dis rolls. So I opted for pairs and 'opposites' between the two dice. (But not exactly, I'd use 21's but 20's are easier to calculate at a glance.)

For totals of 20 (19 + 1, etc.) it counts as a critical success. For pairs, (A = B) it counts as a critical failure. For double 20's it's a double critical. For double 1's it's a double fail. For double 10's it's a critical s/f. (Auto crit, not an auto S/F like the others, I just want it to tell me when it happens.) Otherwise, it will output the die closest to 10 and drop the other.

Can I get some help writing this out?

  • 1
    \$\begingroup\$ I think this would be easier to answer if you add a code block of what you have written so far, so that answerers experts can spot where an improvement can be made. \$\endgroup\$ Commented Aug 3, 2018 at 16:07
  • \$\begingroup\$ Dang. I lost it. I need to kill that cookie-deletion-on-exit preference I think. \$\endgroup\$ Commented Aug 3, 2018 at 16:56
  • 1
    \$\begingroup\$ Maybe try again, and if it works this time fine; if not, C&P to a text file so that you can present it here. \$\endgroup\$ Commented Aug 3, 2018 at 17:49

1 Answer 1


Does this code do what you want?

function: roll ROLL:s {
  \ we assume that ROLL always has exactly two dice; AnyDice sorts them in descending order \
  HI: 1@ROLL
  LO: 2@ROLL
  \ handle the special cases first \
  if LO = 10 & HI = 10 { result: -1 } \ double 10 = "crit success/fail" \
  if LO + HI = 20      { result: 20 } \ mirror pair = crit success \
  if LO = HI           { result:  0 } \ equal pair = crit failure \ 
  \ at this point, we know there's no equal or mirror pair \
  if [absolute LO - 10] < [absolute HI - 10] { result: LO } else { result: HI }

output [roll 2d20]

The output, summarized, looks like this:

Roll          | AnyDice result | Probability
Double 10     |       -1       |      0.25 %
Crit success  |       20       |      4.50 %
Crit fail     |        0       |      4.75 %
Normal N < 10 |        N       |   N - 0.5 %  
Normal N = 10 |        N       |       9.5 %
Normal N > 10 |        N       |  19.5 - N %

That is, except for the crits, you get the same kind of triangle-shaped probability distribution as for a normal 2d20 roll, except that in this case the range of normal rolls is only from 1 to 19 (since the only way the roll closest to 10 could be 20 is if you rolled a double 20, but that's a crit fail).

Also, you can see that if a double 10 was considered a critical success, then the probabilities of a crit fail and a crit success would both be exactly 4.75%, i.e. just slightly below the 5% chance of rolling a natural 1 or a nat 20 on 1d20. This symmetry may or may not be something you'd like to have.

In fact, the way I organized the code above, you can test the effects of this change simply by deleting the "double 10" line (since, if that line isn't there, the code will continue into the following "mirror pair" case). Of course, you can also easily enough test the effect of handling a double 10 in other ways (e.g. treating it as a crit fail, or just as a normal 10) simply by replacing the -1 result value in the code with any other number.

  • \$\begingroup\$ This is actually perfect. My main ideal was to add a non-flat probability curve, and second to try to keep a 5% crit probability. \$\endgroup\$ Commented Aug 3, 2018 at 18:44
  • \$\begingroup\$ You're welcome. BTW, one problem you may have had with your original code is that the ROLL parameter here really does need to be a sequence (i.e. marked with :s). That's what causes AnyDice to call the function for each possible (ordered) pair of 2d20 rolls and to collect the results into a "custom die" (i.e. a probability distribution over the integers). That's one quite essential feature of AnyDice that is unfortunately rather briefly documented. \$\endgroup\$ Commented Aug 3, 2018 at 18:53
  • \$\begingroup\$ How would you add the same doubling/canceling rules to advantage? I'd just assume replace the last function line with 'highest' but it doesn't like that. \$\endgroup\$ Commented Aug 3, 2018 at 18:58
  • \$\begingroup\$ Ah. NM, I got it. \$\endgroup\$ Commented Aug 3, 2018 at 19:01
  • \$\begingroup\$ @spicklesandwich: You'll have to decide how you want to actually handle advantage with your new rolling rules. One really basic way would be to just have the player roll 2d20 twice, apply the same closer-to-10 rule to both 2d20 rolls, and then take the higher one of the results. One way to implement that in AnyDice would be to save the output of the single closest-to-10 roll as a custom die, as in X: [roll 2d20], and then do output [highest 1 of 2dX]. \$\endgroup\$ Commented Aug 3, 2018 at 19:05

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .