statistics – How to make Anydice see if two values are the same among 3 dice and keep them?

Anydice is unfortunately a bit tricky in that it only allows us to return a single number from a function, so we have to use these workarounds if you want to get more information out of a single roll. But that’s entirely doable, in this case, since the introspection you want to do isn’t very complicated.

Here’s a program which implements your mechanic:

function: critical POOL:s {
  if 1@POOL = 3@POOL { result: 2@POOL }
  if 1@POOL = 2@POOL { result: 20 + 2@POOL }
  if 2@POOL = 3@POOL { result: 2@POOL - 20 }
  result: 2@POOL
}

output [critical 3d20]

We invoke the function critical with a 3d20 roll, which is cast to a sequence in descending order. Stepping through the function:

  1. If the highest die and the lowest die are equal, we must have a triple, which I assume cancels out and we just take the value of the middle die.
  2. If the highest die equals the middle die, we have a positive critical and we add 20 to the result to indicate that.
  3. If the middle die equals the lowest die, we have a negative critical and we subtract 20 from the result to indicate that.
  4. Otherwise, we just take the value of the middle die.

The resulting output shows the probability curve you’d expect for taking the middle die of a 3d20 roll, but with a couple of wings either side that represent the critical rolls. Note that there is zero probability of getting a result of 0 or 21, because it’s impossible to get a negative crit if the middle die is a 20 and impossible to get a positive crit if the middle die was a 1.

Anydice graph of expected results.

statistics – Is it possible to model these probabilities in AnyDice?

Do it? Sure. Do it well? Not so much

The easiest way to do mixed dice pools in AnyDice is to cast them as seperate sequence inputs into a function, and then stitch the sequences together. Note that you’ll have to build the function with a maximum different dice possible, but it is possible to give a 0 or {} if the function has more inputs than you pool.

We can find the maximum by sorting it (putting the highest first in default mode) and taking the first. We can then find the number of values in the other pool higher than it by comparing that number to that sequence. The resulting function is fairly short:

function: highest of pool A:s B:s C:s vs X:s Y:s Z:s{
  result: {X, Y, Z} > 1@(sort {A, B, C})
}

output (highest of pool 2d6 1d8 0 vs 2d6 1d8 0)

The problem we’re running into is that AnyDice has runtime limited to 5 seconds and so this times out with more than 6 dice in the pools total. Given the examples, you’re probably better off using a different tool (with higher efficiency/allowed runtime) at least for the larger pools. (Unless of coarse there is some, more efficient AnyDice method I’m unaware of.)

statistics – ANYDICE – Help with a dice pool showing success against a range of target numbers

I’m having a hard time coding an anydice script to show what I want.

Let me contextualize the mechanic I’m trying to simulate:

You roll a POOL of d10 against a TARGET number. If at least one die from the POOL is equal to or higher than the TARGET, the roll is a success. The count of such dice is the degree of success, but that isn’t my focus at the moment.

I’d like to have a graph for the chances of success of various POOLs of different sizes up to 10 (1d10, 2d10, 3d10…10d10) against different TARGETs from 2 to 10 (2, 3, 4… 10).

The caveat is: I’d like the graph to be layed out in such a way that:

  • the x axis represents the TARGETs;
  • the y axis represents the chances of at least 1 success;
  • each line represents a POOL,

so I can see the chances that each POOL has to succeed against a whole range of TARGETs.

Can any anydice wizard help me with this, please?

anydice – How can I calculate the distribution of 3d6, keep and rerolling any 1s and 2s, once?

You can do it like this, using the helper function from this answer:

function: ROLL:n replace FILTER:s with REROLL:d {
  if ROLL = FILTER { result: REROLL }
  result: ROLL
}

X: [d6 replace {1,2} with d6]
output 3dX named "3d6, reroll 1 and 2 once" 

Note that I’m first defining a custom die X that represents a single d6 with 1s and 2s rerolled once, and then rolling three of these custom dice. Especially with large pools of dice this is significantly more efficient than rolling the whole pool at once and feeding the results into a custom function as sequences, since in that case AnyDice isn’t smart enough to realize that the individual dice in the pool cannot affect each other.

anydice – My any-dice program times out, when calculating large limit break checks

Someone in chat helped write an anydice program to calculate limit breaks in an RPG I’m developing, but after making some changes, it times out for dicepools > 7.

The system I have in mind, is that if any of the dice you roll is below a threshold, you can bank the sum of all failed rolls for later use, by converting it into a limit break token (currently, at an exchange rate of 1:4). I’m toying with requiring a certain number of successes before you can convert failed, which may or may not be slowing down the program.

function: sum X:s less than L with at least K successes {
  R: 0
  S: 0
  loop I over X {
     if I <= L { R: R + I }
     if I > L { S: S + 1 }
  }
  if S >= K { result: R/4 }
  if S < K { result: 0 }

}

Is there a more efficient way of running this program? Initially before my tweaks, the same helpful person suggested this as an alternative to the function: output 3d{1..6, 0:6} named "Alt dice" but I can’t figure a way of running that, which is probably less likely to time out, and still check for a minimum number of successes.

Here is the code that causes the time out:

output (sum 1d12 less than 7 with at least 0 successes) named "1 die limit break"
output (sum 2d12 less than 7 with at least 1 successes) named "2 die limit break"
output (sum 3d12 less than 7 with at least 1 successes) named "3 die limit break"
output (sum 4d12 less than 7 with at least 1 successes) named "4 die limit break"
output (sum 5d12 less than 7 with at least 1 successes) named "5 die limit break"
output (sum 6d12 less than 7 with at least 1 successes) named "6 die limit break"
Times out around here
output (sum 7d12 less than 7 with at least 1 successes) named "7 die limit break"
output (sum 8d12 less than 7 with at least 2 successes) named "7 die limit break"
output (sum 9d12 less than 7 with at least 2 successes) named "7 die limit break"
output (sum 10d12 less than 7 with at least 2 successes) named "7 die limit break"

I found the timeout point by running each line individually.

AnyDice — efficiency of code calculating rolls hitting a target with mixed pools; hitting the 5 second barrier

I have some code that is hitting the 5 second barrier;

function: target N:n of A:s B:s C:s {
    result: (count {1..N, 1..(N/2)} in (sort {A, B, C}))
}
output (target 7 of 4d12 0d20 0d8)
output (target 7 of 4d12 2d20 0d8)
output (target 7 of 4d12 4d20 0d8)

Even if I remove the final output line, it still fails.

I believe the code does what I want it to – calculate the number of dice rolling at or under the target from mixed pools (it runs when using other pools: d20s seem to be a problem).

Is there anyway I can improve it so that at least the first two of these output lines will run (or better yet, all three of them)?

N.b. from my perspective these were some of the simplest pools I wanted to look at.

cryptomancer – Another syntax for Anydice mechanic question

I’m trying to build a function to model not just a roll of the dice, but to have boolean operators to toggle using various powers that effect the dice. I’ve gotten everything to work except for one thing; looking at the result of the roll, seeing if a ‘1’ was rolled and then changing that ‘1’, but only once.

The dice mechanic is for Cryptomancer, and it works by taking your rank in a skill which is 1 to 5 and rolling that many d10’s plus a number of d6’s that total to 5 dice. For d10s, 1’s are always botches (-1), numbers under the target number are 0’s and numbers equal to or greater the target are successes (+1). On the d6’s 1s are botches, 6s are success and everything else is 0.

I’ve been using custom die for my rolls, but set the function up to build the roll off just a skill number and challenge number. Here’s what I got so far:

function: sb B:n sp P:n skill SKILL:n vs CHALLENGE:n{
if P=1{
   ROLL: SKILLd{-1,0:(CHALLENGE-2),1:(10-CHALLENGE),2}+(5-SKILL)d{-1,0:4,1}
   }
else {
   ROLL: SKILLd{-1,0:(CHALLENGE-2),1:(11-CHALLENGE)}+(5-SKILL)d{-1,0:4,1}
   }
if B=1{
   if 5@ROLL=-1{
      ROLL:ROLL+2
      }
   }
result:ROLL 
}

The goal is that you can toggle things by entering a 1 or 0 for the values B and P to turn them on or off. P=1 makes all ’10s’ rolled be worth +2 success instead of +1. B=1 is suppose to check the last value of the roll, and if a -1 is present add 2 to the whole total, there by turning one and only one botch into a success, even if there are multiple botches in the roll.

Everything works till I turn on B. then I get an error that the boolean operation if can only be used on numbers. Turns out 5@ROLL isn’t giving me the lowest roll of 5 dice but the probability of what that roll will be.
How do I fix this? How can I convert ROLL:d into ROLL:s?

Subtracting opposed dice in Anydice

It turns out that for any die D = dN, the formula D' = dN - (N + 1) creates a die D' that is the result of subtracting such a die. Sure, for for example a d6, rolls of 6 are treated as 1, 5 as 2, 4 as 3, this does not actually change the probabilities at all, and such a black box communicating the result would be indistinguishable (the numbers are inverted).

So to subtract 2 identical dice (using d6es as an example) the result would just be to roll 2d6 - 7. For a d20 example, the result would be 2d20 - 21