\( % shorthand \newcommand{\attack}{\mathrm{atk}} \newcommand{\total}{\mathrm{tot}} \newcommand{\thresh}{\mathrm{th}} \newcommand{\weighted}{\mathrm{wt}} \newcommand{\crit}{\mathrm{c}} \newcommand{\hit}{\mathrm{h}} \newcommand{\miss}{\mathrm{m}} \newcommand{\fail}{\mathrm{f}} \newcommand{\save}{\mathrm{s}} % creatures \newcommand{\CR}{\mathit{CR}} \newcommand{\LV}{\mathit{L}} %\newcommand{\PC}{\mathrm{PC}} %\newcommand{\NPC}{\mathrm{NPC}} \newcommand{\NPC}{\mathrm{n}} \newcommand{\NPCs}{\mathrm{n}} \newcommand{\PC}{\mathrm{p}} \newcommand{\PCs}{\mathrm{p}} % general \newcommand{\AC}{\mathit{AC}} \newcommand{\HP}{\mathit{HP}} \newcommand{\AB}{\mathit{AB}} \newcommand{\SB}{\mathit{SB}} \newcommand{\DC}{\mathit{DC}} \newcommand{\HD}{\mathit{HD}} \newcommand{\CON}{\mathit{CM}} \newcommand{\rounds}{\mathit{R}} % damage \newcommand{\DPR}{\mathit{DPR}} \newcommand{\DPRcrit}{\DPR_{\crit}} \newcommand{\DPRhit}{\DPR_{\hit}} \newcommand{\DPRfail}{\DPR_{\fail}} \newcommand{\DPRsave}{\DPR_{\save}} \newcommand{\Nattacks}{\mathit{N}_{\attack}} % experience \newcommand{\XP}{\mathit{XP}} \newcommand{\eAC}{\mathit{eAC}} \newcommand{\eDPR}{\mathit{eDPR}} \newcommand{\eHP}{\mathit{eHP}} % encounter multiplier \newcommand{\EM}{\mathit{EM}} \newcommand{\W}{\mathit{W}} \)
\( % probabilities \newcommand{\cdf}{\mathit{F}} \newcommand{\pdf}{\mathit{P}} \newcommand{\CV}{\mathit{CV}} % variables \newcommand{\nRolls}{n_{\mathrm{r}}} \newcommand{\pEncounter}{p_{\mathrm{e}}} \newcommand{\nEncounters}{n_{\mathrm{e}}} \newcommand{\aEncounters}{\mu_{\mathrm{e}}} \newcommand{\cvEncounters}{\CV_{\mathrm{e}}} \newcommand{\sEncounters}{\sigma_{\mathrm{e}}} \newcommand{\pNoEncounter}{p_{\mathrm{n}}} \newcommand{\nMin}{n_{0}} \newcommand{\nMax}{n_{1}} \)

Introduction

Random encounter tables are a common tool used by DMs in D&D as well as numerous other TTRPGs. The idea behind them is that, rather than the DM deciding when the adventurers will face an encounter, the DM rolls dice at specific intervals to determine what, if anything, the PCs will face. This can add a fun element of randomness to an adventure, but it can also be a point of frustration depending on how the dice roll and how the table is implemented and used.

In this post I look at a specific category of random encounter table where the odds of a roll resulting in a encounter are lower than the odds of no encounter occurring. I also show an alternative method for generating random encounters that is statistically similar to the traditional method while requiring fewer rolls. Finally, I show how this alternative method can be modified to improve its consistency in ways traditional encounter tables can’t.

Random encounter math

A random encounter table is, as its name suggests, a table of encounters that can be selected at random. This is generally done by rolling a die and then picking the encounter that corresponds to the resulting value. Often, one of the entries in the table will specify that no encounter takes place. If the table doesn’t have such an entry, a separate die is generally rolled first to determine if an encounter occurs, before rolling on the encounter table to see which encounter it is.

Regardless of the specifics, each time a random encounter is rolled for there is some probability, \(\pEncounter ,\) that an encounter will occur, and some probability, \(\pNoEncounter = 1 - \pEncounter ,\) that one won’t. So long as these probabilities don’t change over time, the probability that the PCs will face \(\nEncounters\) encounters after \(\nRolls\) rolls will follows the binomial distribution, \begin{align} \pdf( \nEncounters ) = \binom{ \nRolls }{ \nEncounters } \, \pEncounter ^{ \nEncounters } \left( 1 - \pEncounter \right)^{\nRolls - \nEncounters} , \label{eq:encounter-distribution} \end{align} where \(\binom{ \nRolls }{ \nEncounters }\) is the binomial coefficient, which represents the number of ways \(\nEncounters\) encounters can occur across \(\nRolls\) rolls, \begin{align} \binom{ \nRolls }{ \nEncounters } = \frac{ \nRolls! }{ \nEncounters! \left( \nRolls - \nEncounters \right) ! } . \nonumber \end{align}

The average number of encounters, \(\aEncounters,\) we expect to see after \(\nRolls\) rolls is simply the probability of an encounter multiplied by the number of rolls, \begin{align} \aEncounters = \nRolls \, \pEncounter . \label{eq:encounter-mean} \end{align} From this we can see that the average number of rolls it takes to get an encounter, \(\nRolls / \aEncounters = 1/\pEncounter,\) increases substantially when the probability of an encounter from a single roll is small.

In practice, the actual number of encounters a DM gets after \(\nRolls\) rolls will likely differ from \(\aEncounters\) by some amount. The typical size of this difference is characterized by the standard deviation of the number of encounters, \(\sEncounters,\) which for \(\nRolls\) rolls is \begin{align} \sEncounters = \sqrt{ \nRolls \pEncounter \left( 1 - \pEncounter \right) } . \label{eq:encounter-sigma} \end{align}

This can be put into relative terms by calculating the coefficient of variation for the number of encounters, \begin{align} \cvEncounters \equiv \frac{ \sEncounters }{ \aEncounters } = \sqrt{ \frac{ 1 - \pEncounter }{ \nRolls \pEncounter } } , \label{eq:encounter-cv} \end{align} which tells us how large a typical difference might be relative to the average.

Note that \(\cvEncounters\) gets smaller as the number of rolls increases, and gets larger when the probability of an encounter from a single roll is low. This second point can be seen more clearly in Fig. \figref{fig:cv-scaling} (below), which plots Eqn. \eqref{eq:encounter-cv} across a range of \(\pEncounter\) values for \(\nRolls = 1\).

Shows how the coefficient of variation for the number of encounters, \(\cvEncounters,\) depends on the probability of a single roll resulting in an encounter, \(\pEncounter,\) when \(\nRolls = 1.\)

Example

To put this into perspective, lets look at an example random encounter table taken from the “Horns of the Beast” example adventure in chapter 4 of the 2024 Dungeon Master’s Guide.

Encounter table

1d20 Encounter
1-14 No encounter
15 An Indifferent Giant Ape protects its territory; its primary concern is getting the party to leave.
16 A Hostile Tyrannosaurus Rex is on the hunt and tries to eat the characters.
17 Three Allosauruses are hunting in the jungle; they are Hostile and treat the party as prey.
18 Two Ankylosauruses tromp through the forest nearby. They are territorial and aggressive but Indifferent, and they won’t pursue a fleeing party.
19 A band of humans, including a Veteran Warrior and eight Infantry Warriors, watch the party. They are Indifferent; they live in the jungle and aren’t used to seeing other people.
20 Four Minotaurs of Baphomet prowl the jungle looking for Humanoids they can capture and bring back to the temple.

If we ignore the specifics of the individual encounter options, the probability of getting an encounter from a single roll is only \(30\%\), i.e., \(\pEncounter = 0.3,\) which means we should expect to see one encounter every \(3.33\) rolls on average.

Since a DM is likely to roll on the table eight times over the course of the adventure, the average number of encounters from the table, calculated using Eqn. \eqref{eq:encounter-mean}, should be close to \(\aEncounters \approx 2.4\) and, using Eqn. \eqref{eq:encounter-sigma}, the standard deviation should be roughly \(\sEncounters \approx 1.3.\) Combined, these give a coefficient of variation of around \(0.54,\) which is fairly mediocre.

Shows the probability of a party experiencing \(n\) encounters after rolling eight times on the example random encounter table.

Figure \figref{fig:example-encounter-distribution} (above) shows the full probability distribution, calculated using Eqn. \eqref{eq:encounter-distribution}, for the number of encounters after eight rolls. What’s interesting to note here is that, while the most likely outcomes are for the PCs to face \(2-3\) encounters, as one would expect, those outcomes only account for \(55\%\) of all outcomes. That’s just a little more than half.

The distribution also shows there’s a decently high chance of either no encounters occurring or more than double the average occurring, each with probabilities around \(5.8\%.\) That means a bit more than one in ten groups who run this adventure are going to have a significantly different experience than one might expect using just the average for this part of the adventure.

This behavior isn’t inherently good or bad, but it is something worth considering when using this kind of random encounter table in an adventure. In the next section, I discuss an alternative way of running this kind of encounter table that follows the same statistics and can reduce the number of rolls a DM needs to make.

Alternative approach

As mentioned earlier, a DM using the example table in the previous section would need to roll \(3.33\) times on average before getting an encounter. If the table had a lower chance of each roll resulting in an encounter, this average would be even higher. That’s potentially a lot of time spent rolling!

In this section I’ll show how we can reduce the number of rolls needed to just two per encounter, regardless of the encounter probability, by borrowing a method used in computational physics known at kinetic Monte Carlo.

Note. The use of kinetic Monte Carlo in computational physics follows a similar motivation. However, the probabilities are generally much lower, requiring several orders of magnitude more “rolls” to simulate using a more conventional approach.

The basic approach here is this, rather than rolling at set intervals to see if a random encounter occurs, we roll once to determine how long it takes to get our next random encounter (i.e., how many rolls it would have taken), and then once to determine which random encounter the PCs face. This guarantees we only ever have to roll twice per random encounter.

To do this, we need a way of translating the probability of a random encounter occurring from a single roll into a new table that tells us how many rolls would be needed before the next random encounter. For that we need to calculate the probability, \(\pdf,\) that the next random encounter occurs after exactly \(n\) rolls on our original random encounter table.

If the probability of a single roll resulting in an encounter is \(\pEncounter,\) then the probability the next random encounter occurring after just one roll must be the same, i.e., \(\pdf(1) = \pEncounter.\) In order for the next encounter to occur on the second roll, the first roll must have resulted in no encounter, which occurs with probability \(\pNoEncounter = 1 - \pEncounter,\) and the second roll must have resulted in an encounter, which again occurs with probability \(\pEncounter,\) for a total probability of \(\pdf(2) = \pEncounter \, \pNoEncounter.\)

We can extend this to a general equation by noting that each additional roll it takes to get to the next encounter adds an extra factor of \(\pNoEncounter.\) Thus, \begin{eqnarray} \pdf(n) &=& \pEncounter \, \pNoEncounter^{n - 1} , \label{eq:rolls-needed-pdf} \end{eqnarray} the results of which are shown in Fig. \figref{fig:example-rolls-before-encounter} (below) for the case where \(\pEncounter = 0.3.\)

Shows the probability of the next encounter occurring after exactly \(n\) rolls on the example random encounter table when the probability of an encounter from each roll is \(30\%.\)

Now that we have these probabilities, we need a way of mapping them onto the range of possible values that can result from rolling whatever standard die we plan on using for our table. Since we know a random encounter has to happen eventually, given sufficiently large \(n,\) the total probability across all values of \(n\) must be equal to one, \begin{align} 1 &= \sum_{i = 1}^{\infty} \pdf(i). \end{align}

If we truncate this summation at \(n\) instead of infinity, we’re left with the cumulative distribution function of an encounter occurring on or before the \(n\mathrm{-th}\) roll, \begin{align} \cdf(n) &= \sum_{i = 1}^{n} \pdf(i) \nonumber \\ %&= \sum_{i=1}^{n} \pEncounter \left( 1 - \pEncounter \right)^{i - 1} \nonumber \\ %&= 1 - \left( 1 - \pEncounter \right)^{n}. &= \sum_{i=1}^{n} \pEncounter \, \pNoEncounter^{i - 1} \nonumber \\ &= 1 - \pNoEncounter^{n}. \label{eq:rolls-needed-cdf} \end{align}

In computational physics, the next step in this process would be to generate a random number \(r\) between 0 and 1, and then finding the value of \(n\) such that \(\cdf(n-1) \lt r \le \cdf(n).\) This works because \(\pdf(n) = \cdf(n) - \cdf(n-1)\) and because \(r\) can take on an extremely large range of values between 0 and 1.

When using a standard \(D-\mathrm{sided}\) die, this second point no longer holds true since there are only \(D\) possible values the die can generate. So, rather than thinking of each side of our die as mapping to a distinct value between 0 and 1, it’s better to think of it as representing a range of value covering a width of \(1/D.\) For example, the value of 1 on a d4 would represent probability values between 0 and 0.25.

If we assign each side, \(d,\) on our die as covering a range from \(\left(d - 1\right)/D\) to \(d/D\) then we can use the midpoint of that range, \(\left(d - 0.5\right)/D,\) to determine the value of \(n\) it corresponds to using following formula, \begin{align} %n &= \left\lceil \frac{ \log \left( 1 - \frac{ d - 0.5 }{ D } \right) }{ \log \left(1 - \pEncounter \right) } \right\rceil , n &= \left\lceil \frac{ \log \left( 1 - \frac{ d - 0.5 }{ D } \right) }{ \log \left( \pNoEncounter \right) } \right\rceil , \label{eq:roll-value-converter} \end{align} where \(\lceil x \rceil\) is the ceiling function, which rounds \(x\) up to the nearest integer value.

Note. Using the midpoint to determine \(n\) reduces the accuracy of this approach somewhat. There are more accurate approaches that we could use instead, but they are also more complicated and the improvements in accuracy are rather small.

Example revisited

Applying this method to our previous example, the number of days between encounters can be mapped to a d20 as shown in the encounter timing table (below). When determining when the next random encounter will occur, the DM rolls a d20 and then consults the table to determine the day of the encounter. If that day happens after the PCs have left the area the table applies to then no encounter occurs.

Encounter timing table

1d20 Days
1-6 1
7-10 2
11-13 3
14-15 4
16-17 5
18 6
19 8
20 11

For example, if the DM rolled a 5 then the encounter would occur on the first day. If the PCs were just starting their journey this would be the first day of their travels. Alternatively, if the party had just had an encounter, this would be on the first day after that encounter.

After rolling to determine when the next encounter occurs, the DM would then roll a d6 to determine which of the six random encounters the PCs would face, using the alternative encounter table (below).

Alternative encounter table

1d6 Encounter
1 An Indifferent Giant Ape protects its territory; its primary concern is getting the party to leave.
2 A Hostile Tyrannosaurus Rex is on the hunt and tries to eat the characters.
3 Three Allosauruses are hunting in the jungle; they are Hostile and treat the party as prey.
4 Two Ankylosauruses tromp through the forest nearby. They are territorial and aggressive but Indifferent, and they won’t pursue a fleeing party.
5 A band of humans, including a Veteran Warrior and eight Infantry Warriors, watch the party. They are Indifferent; they live in the jungle and aren’t used to seeing other people.
6 Four Minotaurs of Baphomet prowl the jungle looking for Humanoids they can capture and bring back to the temple.

We can check how accurately this reproduces the results of the original table by calculating the probability distribution for the number of encounters the PCs are likely to face during the eight day journey in the example adventure. The results of this are shown in Fig. \figref{fig:example-d20-encounter-distribution} (below).

Shows the probability of a party experiencing \(n\) encounters using the original table or our approximate d20 table.

While not perfect, the probability distribution created by the encounter timing table closely matches of the original’s. If we were to use a larger die, like a d100, instead of a d20 then the difference would be even smaller.

Tightening the distribution

Before closing, there is one other aspect of this alternative encounter table presentation worth exploring, and that’s how the low and high numbers of encounters are generated from it.

The probability of the PCs experiencing zero encounters in Fig. \figref{fig:example-d20-encounter-distribution} is around \(5\%\) for both methods. Using the original table this comes from rolling a d20 value between \(1-14\) eight times. We can adjust the size of this range to alter the chance of no encounters occurring, but the only way to reduce it to zero would be for an encounter to occur on each roll. In comparison, using the alternative table this can only happen if the very first d20 roll is a \(20,\) putting the next encounter on day 11, after the PCs have concluded their travels.

Similarly, the only way the alternative table can produce five or more encounters during the adventure is if at least one of the d20 rolls is between \(1-6\), causing the next encounter to occur on the next day. In both cases, removing these rows from the alternative table eliminates the possibility of the PCs facing no encounters or five or more encounters. This results in a tighter distribution for the number of encounters the PCs might face during this portion of the adventure, while still allowing for some randomness on the number of days between encounters.

These adjustments certainly could be done by hand, i.e., by actually eliminating rows from the previously generated alternative table. However, that would change the size of the die needed by the table, which could make using it a bit more difficult. For a more systematic approach, this can be accomplished by limiting the maximum and minimum number of days between encounters when constructing the table, and then renormalizing the results so the total probability of an encounter occurring within that range is still equal to one.

Taking this approach, the cumulative distribution function of an encounter occurring described by Eqn. \eqref{eq:rolls-needed-cdf} becomes \begin{align} \cdf(n) %&= \frac{ 1 - \left( 1 - \pEncounter \right)^{n - \nMin + 1} }{ 1 - \left( 1 - \pEncounter \right)^{\nMax - \nMin + 1} } %&= \frac{ 1 - \pNoEncounter^{n - \nMin + 1} }{ 1 - \pNoEncounter^{\nMax - \nMin + 1} } , &= \frac{ 1 - \pNoEncounter^{n - \nMin^\prime} }{ 1 - \pNoEncounter^{\nMax - \nMin^\prime} } , \label{eq:adj-rolls-needed-cdf} \end{align} where \(\nMax\) is the maximum number of days allowed between encounters, \(\nMin\) is the minimum number of days between encounters and \(\nMin^\prime \equiv \nMin - 1.\)

Applying these changes to Eqn. \eqref{eq:roll-value-converter}, the new equation for mapping die value to the number of rolls between encounters is \begin{align} %n &= \nMin - 1 + \left\lceil \frac{ \log \left( 1 - \left( \frac{ d - 0.5 }{ D } \right) \left( 1 - \left(1 - \pEncounter \right)^{\nMax - \nMin + 1} \right) \right) }{ \log \left(1 - \pEncounter \right) } \right\rceil , %n &= \nMin - 1 + \left\lceil \frac{ \log \left( 1 - \left( \frac{ d - 0.5 }{ D } \right) \left( 1 - \pNoEncounter^{\nMax - \nMin + 1} \right) \right) }{ \log \left( \pNoEncounter \right) } \right\rceil , n &= \nMin^\prime + \left\lceil \frac{ \log \left( 1 - \left( \frac{ d - 0.5 }{ D } \right) \left( 1 - \pNoEncounter^{\nMax - \nMin^\prime} \right) \right) }{ \log \left( \pNoEncounter \right) } \right\rceil , \label{eq:adj-roll-value-converter} \end{align} where, again, \(d\) is a face value on the \(D\mathrm{-sided}\) die used by the alternate table, and \(\lceil x \rceil\) is the ceiling function, which rounds \(x\) up to the nearest integer value.

Example truncated

Applying this method to our original example and limiting the days between encounters to between \(2-8\), the number of days between encounters can be mapped to a d20 as shown in the modified timing table (below).

Modified timing table

1d20 Days
1-7 2
8-11 3
12-14 4
15-17 5
18 6
19 7
20 8

The effect this has on the probability distribution for the number of encounters across eight days of travel is shown in Fig. \figref{fig:truncated-d20-encounter-distribution} (below). The results show much more consistent outcomes that given by the original example table while still allowing for a bit of randomness.

Shows the probability of a party experiencing \(n\) encounters using the original table or our approximate d20 table.

Conclusion

Generating random encounters by rolling for the time between encounters, rather than whether or not an encounter occurs at fixed intervals, can reduce the number of rolls a DM has to make. These timing tables can also be easily modified to better control the overall range of possible encounters the PCs experience during an adventure. These are both benefits worth considering when using random encounters.

This approach isn’t without its drawbacks, though. The mathematical process for generating these timing tables is a bit involved, which can be a big hurdle for DMs and adventure designers. A simpler approach, in practice, would be to skip all the math and just create a table for the time between encounter by hand. DMs will also need to learn to use these alternative encounter tables and become comfortable doing so.

Finally, I think it’s worth pointing out that the method shown here can also be applied to other mechanics within the game. For example, when running combat with large numbers of monsters a similar table could be used to determine the number of monsters that need to attack before a hit occurs. This would allow for some randomness in the process without forcing the DM to roll for each individual monster.