Monday, May 4, 2020

How can I use a d20 in Dungeon World?

The basic die mechanic in Dungeon World involves rolling 2d6. A total result of 6 or less results in a failure, 7 through 9 in a partial success, and 10 or more in a success. (What each of these events entails is detailed by the Move that called for a roll.) What's the probability of each event?  We could compute them directly (or even count them), but because there are a couple of cases here (and because we're going to be doing more calculations shortly) it will be helpful to base our calculations on the cumulative distribution function (CDF) of the total result of rolling 2d6. This will make our initial calculation somewhat belabored, but will serve as a framework for subsequent calculations.

The CDF is a function associated with a random variable that tells us the probability of getting a certain number or less. It's usually notated as $F(x)$, or $F_X(x)$, where $X$ is the associated random variable, so we write it's definition as,
\begin{align}\label{eq:def:cdf}
F_X(x) = P(X \leq x).
\end{align}
We'll play a little loose with notation, in order to write our equations with a little more meaning, and write the CDF of the sum of rolling 2d6 as $F_\mathrm{2d6}(x)$. The probability of a failure is $P(\mathrm{2d6} \leq 6)$, which by definition of the CDF is $F_\mathrm{2d6}(6)$. The probability of a partial success is $P(6 <\mathrm{2d6} \leq 9)$. How can we write this in terms of the CDF?  Recall that the probability of disjoint, or mutually exclusive, events add. That means we can break up $P(\mathrm{2d6} \leq 9)$ as follows
\begin{align}
P(\mathrm{2d6} \leq 9) = P(\mathrm{2d6} \leq 6) + P(6<\mathrm{2d6} \leq 9).
\end{align}
Which we can rearrange as
\begin{align}
P(6<\mathrm{2d6} \leq 9) =  P(\mathrm{2d6} \leq 9) - P(\mathrm{2d6} \leq 6).
\end{align}
Substituting in our definition for the CDF, we have
\begin{align}
P(6<\mathrm{2d6} \leq 9) =  F_\mathrm{2d6}(9) - F_\mathrm{2d6}(6).
\end{align}
Similarly, we can find an equation for the probability of success in terms of the CDF.
\begin{align}
P(9<\mathrm{2d6} \leq 12) =  F_\mathrm{2d6}(12) - F_\mathrm{2d6}(9).
\end{align}
However, the maximum possible result of rolling 2d6 is 12. The probability of getting the maximum value or less is 1, so the value of the CDF at 12 is 1.
\begin{align}
F_\mathrm{2d6}(12) = P(\mathrm{2d6} \leq 12) = 1.
\end{align}
Thus, we can simplify the probability of a success as,
\begin{align}
P(9<\mathrm{2d6} \leq 12) =  1 - F_\mathrm{2d6}(9).
\end{align}
To summarize, the probabilities of our three events of interest are
\begin{align}
P(\mathrm{fail}) &= F_{\mathrm{2d6}}(6) \\
P(\mathrm{partial \ success}) &= F_{\mathrm{2d6}}(9) - F_{\mathrm{2d6}}(6) \\
P(\mathrm{success}) &= 1 - F_{\mathrm{2d6}}(9).
\end{align}

What does the CDF look like for our 2d6 roll?  It looks like Fig. 1.  We derived the result previously here.  Let's compare it to 1d20.

Fig. 1: Cumulative distribution function (CDF) of 2d6 and 1d20.

We can read off the values from the plot, or use the equations we derived.
\begin{align}
P(\mathrm{fail}) &= F_{\mathrm{2d6}}(6) \approx 0.417\\
P(\mathrm{partial \ success}) &= F_{\mathrm{2d6}}(9) - F_{\mathrm{2d6}}(6) \approx 0.833 - 0.417 = 0.416 \\
P(\mathrm{success}) &= 1 - F_{\mathrm{2d6}}(9) \approx 1 - 0.833 = 0.167
\end{align}
Note that our approximate values for failure and a partial success came out differently due to how we did the rounding, but they're really the same probability. You can trust me, or do the math yourself to confirm. I advise the latter.

There are two things that stand out about the differences in the CDF of 2d6 compared to 1d20. First, the ranges are different. We can fix this by applying a linear transform, which we'll do shortly. The second is that the shapes of the CDFs are different. Unfortunately, there's no getting around this. We'll just try to line them up as nicely as possible and see how it turns out.

There are a few different ways we could approach generating a mapping from the 1d20 result in order to emulate 2d6. Perhaps the simplest is to just line up the "end points''. They're not really end points, though, since the CDF is really defined over all real numbers. (Even though I haven't plotted it as such. I've neglected both to show the stair-casing and to show values beyond results that are actually possible to roll.)  Let's do this. Here we want to map 0 to 1 and 20 to 12. We can treat those as to $x$-$y$ pairs that define a line. So if we have mapping in the form $y = mx + b$, then
\begin{align}
12 &= m \cdot 20 + b \\
1 &= m \cdot 0 + b.
\end{align}
This works out to be easy to solve, and we don't even have to bother learning some basic linear algebra. From the second equation we see that $b=1$. Plugging that result into the first equation we find,
\begin{align}
12 &= m \cdot 20 + 1 \\
11 &= m \cdot 20 \\
m &= \frac{11}{12}.
\end{align}
So we can emulate 2d6 with a 1d20 by taking the result of the d20 and putting it through the following equation.
\begin{align}
X_\text{fake 2d6} = \frac{11}{20} \cdot X_\text{1d20} + 1
\end{align}
A comparison of a real 2d6 and our fake 2d6 CDF is shown in Fig. 2.

Fig. 2: Comparison of CDF of fake 2d6 and real 2d6.

Now that we've mapped the 1d20 roll onto the 2d6 roll, we can map the limits for failure, partial success, and success back onto the 1d20 directly, so that we don't have to do this awkward linear transform for each roll. We have to do a little invention, because when we map from 1d20 to 2d6 we got numbers in between the previous limits. For example, rolling a 10 on 1d20 maps to $\frac{11}{20}\cdot 10 + 1= 6.5$, which is exactly between the limits for failure and partial success. It's a design decision as to which direction to put the limit for 1d20. Let's put it into partial success. Similarly, rolling a 15 and 16 on 1d20 map to 9.25 and 9.8, respectively, on 2d6. While these are between the limits (9 and 10) for partial success success, they are more clearly on either side of the midpoint (9.5). Thus, we can define the limits as follows.
\begin{alignat}{2}
1 \leq &X_\text{1d20} \leq 9 &&\rightarrow \text{fail} \\
10 \leq &X_\text{1d20} \leq 15 &&\rightarrow \text{partial success} \\
16 \leq &X_\text{1d20} \leq 20 &&\rightarrow \text{success}.
\end{alignat}
We can compute the probabilities associated with this mapping as follows.
\begin{align}
P(\mathrm{fail}) &= F_{\mathrm{1d20}}(9) \\
&= 0.45 \\
P(\mathrm{partial \ success}) &= F_{\mathrm{1d20}}(15) - F_{\mathrm{1d20}}(9) \\
&= 0.3 \\
P(\mathrm{success}) &= 1 - F_{\mathrm{1d20}}(15) \\
&= 0.25 \\
\end{align}
These do sum to one, indicating we've done the math correctly. However, the probabilities are quite different than what we had when we started with 2d6. Failure is fairly close, but partial success is much less likely, and success is much more likely. This is likely to notably affect the game. So let's look at another approach.

One possible improvement would be to alter our mapping function. One way would be to calculate the so-called best-fit line. (I use "so-called'' because depending on what the criteria for best is in a particular case, there may be a better line than the best-fit line.) This is the line for which the mean-squared error is minimized.

Another approach would be to look at the points we really care about—at 6 and 9—and just do a fit based on those. Or, put it another way, let's look at the probabilities of the three results with 2d6, and find what thresholds best match those probabilities. For our 1d20, all outcomes have a probability which is a multiple of $1/20=0.05$, so if we just round our probabilities to the nearest multiple of 0.05, and then look at what thresholds give us those probabilities, we can find the transform. Actually, we'd be done, since what we really want is the thresholds. However, the transform will be useful for later.
\begin{align}
P(\mathrm{fail}) &\approx 0.417 \rightarrow 0.4\\
P(\mathrm{partial \ success}) &\approx 0.416 \rightarrow 0.4\\
P(\mathrm{success}) &\approx 0.167 \rightarrow 0.15
\end{align}
Unfortunately, when we round to the nearest 0.05, the resulting probabilities don't add up to 1. That is, $0.4+0.4+0.15=0.95$. Again, it's a design decision as to where to put this leftover 0.05 probability. Personally, I'd put it into partial success, since that's usually the most interesting result. (Indeed others who had done d20 hacks of Dungeon World agree with me—or, perhaps, I agree with them—and use this breakdown. Unfortunately, I can't find a working link right now.)
\begin{align}
P(\mathrm{fail}) &= 0.4\\
P(\mathrm{partial \ success}) &= 0.45\\
P(\mathrm{success}) &=0.15
\end{align}
To achieve these probabilities, we need to have a number of possible results on 1d20 correspond to each outcome equal to the probability of that outcome divided by 0.05. We'll keep them in order so that
\begin{alignat}{2}
1 \leq &X_\text{1d20} \leq 8 &&\rightarrow \text{fail} \\
9 \leq &X_\text{1d20} \leq 17 &&\rightarrow \text{partial success} \\
18 \leq &X_\text{1d20} \leq 20 &&\rightarrow \text{success}.
\end{alignat}
What complicates our situation is that sometimes there are modifiers to the roll. These modifiers can range from $-3$ to $+4$. The $+4$ comes from a stat giving a $+3$ and also having $+1$ from another effect. In Fig. 3 we see plots of the probabilities of the three outcomes in Dungeon World (using 2d6) with these modifiers. Thus, while we've got the thresholds for unmodified rolls, we still need to know how to map the modifiers to a 2d6 roll to modify the 1d20 roll.

Fig. 3: Probabilities of a roll in Dungeon World.

To address this, we'll do a mapping using these probabilities. Because of rounding, we have a little bit of wiggle room. Let's look at two lines that bound our possibilities. We could either map 8 to 6 or 9 to 7, and either 17 to 9 or 18 to 10. Each combination gives us two equations with two unknowns to solve for. Let's plot these four points. Let's consider the combination that gives us the largest slope.
\begin{align}
6 &= m \cdot 8 + b\\
10 &= m \cdot 18 + b
\end{align}
We can write this in matrix notation,
\begin{align}
\begin{bmatrix}
6 \\
10 \\
\end{bmatrix}
& =
\begin{bmatrix}
8 & 1 \\
18 & 1 \\
\end{bmatrix}
\cdot
\begin{bmatrix}
m \\
b \\
\end{bmatrix}
\end{align}
Now let's assign the matrices variables, so we can rearrange to solve for what we want.
\begin{align}
\mathbf{A} &=\mathbf{B} \cdot
\begin{bmatrix}
m \\
b \\
\end{bmatrix} \\
\mathbf{B}^{-1} \cdot \mathbf{A} &= \mathbf{B}^{-1} \cdot \mathbf{B} \cdot
\begin{bmatrix}
m \\
b \\
\end{bmatrix} \\
\begin{bmatrix}
m \\
b \\
\end{bmatrix}
&= \mathbf{B}^{-1} \cdot \mathbf{A} =
\begin{bmatrix}
0.4 \\
2.8 \\
\end{bmatrix}
\end{align}
Note that we have to be a bit careful with how we do operations with matrices. Matrix multiplication isn't commutative. That is, the order matters, which is why $\mathbf{B}^{-1}$ is the left-most term above. I've glossed over the details here, for which I'm somewhat sorry, because the matrices aren't our focus here. The above should compute easily enough in tools to handle such things (e.g. python). Or, you could solve the two equations manually.

Now let's consider a combination that gives us the smallest slope.
\begin{align}
7 &= m_2 \cdot 9 + b_2\\
9 &= m_2 \cdot 17 + b_2
\end{align}
Here, I'll elide even more of the steps and get to the result.
\begin{align}
\begin{bmatrix}
7 \\
9 \\
\end{bmatrix}
& =
\begin{bmatrix}
9 & 1 \\
17 & 1 \\
\end{bmatrix}
\cdot
\begin{bmatrix}
m_2 \\
b_b \\
\end{bmatrix} \\
\mathbf{A_2} &=\mathbf{B_2} \cdot
\begin{bmatrix}
m_2 \\
b_2 \\
\end{bmatrix} \\
\mathbf{B_2}^{-1} \cdot \mathbf{A_2} &=
\begin{bmatrix}
m_2 \\
b_2 \\
\end{bmatrix} \\
\begin{bmatrix}
m_2 \\
b_2 \\
\end{bmatrix}
&=
\begin{bmatrix}
0.25 \\
4.75 \\
\end{bmatrix}
\end{align}
These two lines are plotted on top of the mapped thresholds in Fig. 4. The corresponding probabilities are plotted in Fig. 5.

Fig. 4: Mapping thresholds.

Fig. 5: Mapping thresholds onto 2d6 CDF.

What really matters here is the slopes, which range from $1/m=1/0.4=2.5$ to $1/m_2=1/0.24=4$. This means that we can use the thresholds we computed, and then map each $+1$ modifier on 2d6 to somewhere between $+2.5$ to $+4$ on 1d20. Practically, we should limit this to integer values. Thus we can consider $+2$, $+3$, and $+4$ to 1d20 per $+1$ to 2d6. These three cases are plotted in the three figures below.

Fig. 6: Probabilities of a roll where $+1$ on 2d6 becomes $+2$ on 1d20.


Fig. 7: Probabilities of a roll where $+1$ on 2d6 becomes $+3$ on 1d20.


Fig. 8: Probabilities of a roll where $+1$ on 2d6 becomes $+4$ on 1d20.

Looking at these plots we can see that there's some level of trade off between them. It looks to be overall the best when we map $+1$ to $+3$, however there is one property that stands out. With even the minimum $-1$ penalty using a 2d6 becomes $-3$, which means that the probability of success becomes 0. To rectify this, we can invoke a rule from Dungeons and Dragons: rolling a natural 20 and 1 result in automatic success and failure, respectively. With this rule incorporated we see the probabilities plotted in the figure below, which does a nice job of matching the shapes, but also preserves a non-zero chance of both success and failure with small modifiers, as in Dungeon World using 2d6.

Fig. 9: Probabilities of a roll where $+1$ on 2d6 becomes $+3$ on 1d20 and special treatment of 1 and 20.

No comments:

Post a Comment