6
\$\begingroup\$

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.

\$\endgroup\$

2 Answers 2

3
+50
\$\begingroup\$

There's an even more efficient way to do this than Someone_Evil's solution. It's based on the observation that the result of each failed roll is uniformly distributed between 1 and \$L\$, where \$L\$ is highest roll that counts as a failure.

Thus, we can do the calculation in stages: first we figure out how many failures there are, and then we roll that many \$L\$-sided dice to represent the failed rolls, and sum the results. Or, in more detailed steps:

  1. Determine the probability of each single roll failing. This is simply \$L \mathbin/ 12\$ (for 12-sided dice); in AnyDice, this is most conveniently represented with the expression d12 <= L, which returns a die that rolls \$1\$ with probability \$L \mathbin/ 12\$ and \$0\$ otherwise.

  2. Determine the distribution of the number of failed rolls out of \$N\$, which is a binomial distribution with parameters \$n = N\$ and \$p = L \mathbin/ 12\$. In AnyDice, this distribution is conveniently obtained with the expression Nd(d12 <= L).

  3. Modify the distribution obtained in the previous step so that values greater than \$N - K\$ (corresponding to less than \$K\$ successes out of \$N\$) are replaced with \$0\$ (since we will sum no failed rolls in that case). In AnyDice, this can be easily done with a helper function like this:

    function: X:n if at most Y:n else Z:n { if X <= Y { result: X } else { result: Z } } X: [Nd(d12 <= L) if at most N-K else 0] 
  4. Output the sum of \$X\$ \$L\$-sided dice, where \$X\$ is distributed according to the modified binomial distribution from the previous step. In AnyDice, we can simply obtain this sum as XdL (or, writing out the definition of X from above, as [Nd(d12 <= L) if at most N-K else 0]dL).

Putting these all together, here's the full program:

N: 8 \ total number of dice in pool \ L: 7 \ highest failing roll \ K: 1 \ minimum number of successes needed \ function: X:n if at most Y:n else Z:n { if X <= Y { result: X } else { result: Z } } X: [Nd(d12 <= L) if at most N-K else 0] output XdL / 4 named "(sum of [N]d12 at most [L]) / 4 with at least [K] successes" 

Of course you can also wrap this code in a loop or even in a function.

\$\endgroup\$
1
  • \$\begingroup\$ That's very clever \$\endgroup\$ Commented Aug 8, 2020 at 20:29
6
\$\begingroup\$

Let's first recognize what we need to do with the dice pool:

  • We want to sum all the values <= 7

  • Count the number of values > 7

This means we only need the dice to include the 1 to 7 part, and can let the other entries be zero and count those. This means we don't need a loop with a test to sum, we can just let anydice use the built in sum which happens on artimetic operation on a sequence. We thus replace the d12 with {1..7, 0:5}. We can also test 0 very simply by using the boolean behaviour of sequences.

Implementation (Anydice link):

DIE: {1..7, 0:5} function: sum X:s with at least K successes { S: X = 0 if S >= K { result: X/4 } else { result: 0} } output [sum 8dDIE with at least 1 successes] named "8 die limit break 2 success" 

A downside to this method is that you need to set up the threshold in the die constructor, though it should be possible to create a constructor for it, if desirable.

\$\endgroup\$
1

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.