ID:1960024
 
Introduction
When designing games, there are two usual approaches to things like damage dealt or taken, items discovered, experience gained, or etc.: the result of these are either (a) pre-determined, so that if one were to going through a scenario and perform the same exact sequence of events, the results would be the same every time, or (b) probabilistic, so that no matter what is done there is always some sense of 'randomness' or uncertainty to the outcome.

What fits in a given game is typically a matter of style, but a rule of thumb is the greater the abstraction the more suitable probability. For example, a tabletop RPG like Dungeons and Dragons would be extremely boring if you knew for certain ahead of time that you would win or lose against a given enemy just based on its stats. On the other hand, a realistic shooter would feel arbitrary if a bullet in the same spot did wildly different damage for no other reason than 'just because'.

So, perhaps you've decided that probability fits your game. The question is, how should you implement it? If your character is swinging a sword, should they just do between 5 and 10 damage every time? I.e., should you just calculate their damage from rand(5,10) and call it a day?

The short answer is, maybe. The longer answer is, does it fit what you want for your game? To figure that out, you need two things: (1) to know what you want for your game, and (2) to know how to compute probability.

What is Probability?
But let's step back for a second. What even is probably? Most would be able to tell you that, for example, if you roll a (standard, fair) six-sided die, then your chance of getting any particular result is 1/6. But what does that mean? There are a lot of different interpretations, but perhaps the most easy to understand is that probability tells us about expectations. For example, when applied to a six-sided dice, the probably of 1/6 tells us that, after taking enough rolls, we would expect each particular side to show up about 1/6 of the time.

For example, for one sample of simulating rolling a six-sided die 100,000 times, we have the following result.
/*
Roll Amount Error
---- ------ -----
1 16675 0.008%
2 16796 0.129%
3 16516 0.150%
4 16730 0.063%
5 16741 0.074%
6 16542 0.124%

For simulation, see https://jsfiddle.net/oLzasyrb/
*/

where Amount is the number of time rolled (out of 100,000) and Error is how close it each result is to appearing 1/6 of the time. If you were to simulate rolling a six-sided die 1,000,000 the error would be even smaller, and 10,000,000 even smaller still.

Before we move on, an important point must be made, and that is to understand the logic behind the fallacy commonly known as the gambler's fallacy. Imagine you have a fair coin; then the probability of getting a heads is 1/2, and the probability of getting a tails is also 1/2. Say you flip the coin six times in a row and get a heads each of those six times. Then what is the probability the next coin flip is a heads? Much to many folk's consternation, it is still a 1/2 (once again, assuming the coin is unbiased, meaning no one has messed with it to make a heads more likely than a tails). Probability—under the interpretation given above—only tells us about long-term results, not short term ones.

For example, suppose that you flip a coin six times in a row and get Heads, Heads, Heads, Heads, Heads, Tails. The probability of getting five Heads in a row is relatively unlikely, with a probability of 1/25 = 1/32, but this is no more or less likely than any other sequence of Heads and Tails when you flip a coin five times, because Heads and Tails are equally-likely.

If you want to see this for yourself, run this a few times and you should see some long strings of "H" and "T". Simpler still, flip a coin twenty times and write down the result!

Basic Terminology
Before we move on to learning how to compute and apply theoretical knowledge to practical situations, we should discuss some important terminology. As we said in the above, if you roll a six-sided die the possibilities are 1, 2, 3, 4, 5, and 6, while the possibilities are flipping a coin are Heads and Tails. These are what is known as a sample space, a set of all possible outcomes of an experiment. An experiment is just a general term for some sort of procedure that can be repeated arbitrarily many times; in the above, "flipping a coin ten times and recording the result" is an experiment. An outcome is a possible result of an experiment (e.g., "Heads" is an outcome of flipping a coin). An event is a collection of outcomes. For example, one event could be "heads or tails" for the experiment "flip a coin" (an event with a 100% probability).

It's important to note that the sample space varies depending on the experiment. For example, let's say the experiment is "Flip a coin twice, and write down the result each time." Then the sample space is {(Heads, Heads), (Heads, Tails), (Tails, Heads), (Heads, Heads)}. This might seem insignificant, but if I say that you will get $5 if you flip (Tails, Heads), i.e. a Tails followed by a Heads, then getting a Heads followed by a Tails does not cut it!

A probability mass function is a function that takes an outcome and assigns a probability to it. Things like unbiased dice and coin flips have fairly-simple p.m.fs. For a six-sided die, it's just f(x) = 1/6 while for a coin it is f(x) = 1/2. The cumulative distribution function gives the probability a result is greater than or equal to a given value in the sample space. For a six-sided die it can be calculated with F(x) = x/6, and in general if a, b, ..., c <= x are all the values in the sample space less than or equal to x, F(x) = f(a) + f(b) + ... + f(x). One important note to keep in mind is that if you sum up a p.m.f. over the entire sample space, the result must be equal to one, which can be interpreted to mean that the probability of any valid outcome of an experiment is 100% (e.g., for a six-sided die we have f(1) + f(2) + f(3) + f(4) + f(5) + f(6) = 1/6 + 1/6 + 1/6 + 1/6 + 1/6 + 1/6 = 1).

A probability distribution is a sample space together with a p.m.f. In the examples of flipping a coin and rolling a fair die, the probability distributions are a special case called a uniform distribution, because the probability of any two outcomes is the same. That is, you're just as likely to roll a 1 as a 3.

Note that these are assuming the sample space is numeric, discrete, and finite. That is, we're considering only numbers (or something that can easily be mapped to numbers, for example by saying Heads = 1 and Tails = 2 or something), that there are "gaps" between the values (you can't roll part way between a 3 or a 4 on a six-sided die, usually), and that there are a limited number of possible outcomes (for a six-sided die, there are only six).

Calculating Probability
I will use the notation Pr(X = x) to denote the probability that a random variable is equal to x. While it can be hard to grasp what exactly a random variable is, one way to think of it is a "hypothetical experiment". That is, imagine you're going to roll a six-sided die. Then you can think of X as the result of a hypothetical dice roll, so that Pr(X = 4) can be interpreted as "the probability that we roll a die and it comes up as 4". From above, it follows Pr(X = x) = f(x) (where f is the p.m.f) and Pr(X <= x) = F(x) (where F is the c.d.f.).

Going back to the six-sided die, what is the probability of rolling either a 4 or a 5? Using our notation, we would write this as Pr(X = 4 or X = 5). A rule of thumb is that if two results are mutually exclusive (you can't roll both a 4 and a 5) and looking at "or" types of statements, you take the sum of the p.m.f. Therefore, Pr(X = 4 or X = 5) = f(4) + f(5) = 1/3. Therefore, on average you will expect to roll a 4 or 5 one third of the time.

What if you rolled one die twice in a row (we'll call these X for the first roll and Y for the second roll) and want to know the probability of rolling a 1 the first time and a 3 the second time? Then we have Pr(X = 1 and Y = 3) in this notation. Another rule of thumb is that if two outcomes are independent (the result of one experiment does not affect the result of the other) and you're looking at "and" types of statements, you take the product of the p.m.f. Thus, Pr(X = 1 and Y = 3) = f(1) * f(3) = 1/36, so that only 1 in 36 times, on average, will you roll a 1 and then a 3.

A quick aside: I used X and Y above because Pr(X = 1 and X = 3) would imply that we roll a 1 and a 3 on the same die, which is impossible on a standard six-sided die.

These two rules can be used together. Consider Pr[(X = 1 or X = 2) and (Y = 3 or Y = 4) ]. That is, the probability of rolling a 1 or 2 on the first die, and a 3 or 4 on the second. This is given by [f(1) + f(2)]*[f(3) + f(4)] = 1/3*1/3 = 1/9, a result backed up by this simulation.

Now, if your results are dependent or not mutually exclusive, things get a little more complicated. This is just an introductory primer, so I'm not gonna get that far into it.

Non-Uniform Distributions
As mentioned before, rolling a single, standard six-sided die has a uniform distribution. If you were to plot this distribution, you would get the following graph:



This is, depending on its use, kind of boring. For example, if you were doing damage based on this, it's equally-likely that you do very well (rolling a six) as it is you do very poor (rolling a 1). A slightly more interesting graph shows up if you do something like roll two die and take their sum. The graph of this distribution is:



With this distribution, you're suddenly much, much more likely to do "average" as you are to do very well or very poor. The exact p.m.f. is,

That is, you're six times more likely to roll a 7 than to roll either a 2 or a 12. As you can see, using a non-uniform distribution changes things a lot. Obviously the sample space is significantly different (there are twice as many outcomes, to start, and many are larger), but it's also a bit more interesting in my opinion.

Mean and Mode
The mean and mode of a distribution are important measures of "likely" rolls. The mode of a distribution is the most likely outcome (or outcomes) in terms of probability. For a d6—and uniform distributions in general—the mode is the entire sample space, as all outcomes are equally likely. In the 2d6 above (the sum of two six-sided die), the mode is 7.

The mean is the value you would expect the outcomes of an experiment to tend towards as you do arbitrarily many; for this reason, the mean is also often called the expected value. In a sense, it is the average of the values (albeit, a weighted average). It's typically denoted E(X), where X is a random variable. If your sample space is {a, b, ..., c}, then E(X) = a f(a) + b f(b) + ... + c f(c) where f is the p.m.f.

For example, the mean of a d6 distribution is f(1) + 2 f(2) + 3 f(3) + 4 f(4) + 5 f(5) + 6 f(6) = 1/2 + 2/6 + 3/6 + 4/6 + 5/6 + 6/6 = 7/2 = 3.5. Therefore, if you roll a d6 enough times, the average of the rolls would tend towards 3.5. If you do the same thing with a 2d6 distribution, the result is a mean of 7.

The mean and mode are useful measures, as they give you an idea of what sort of thing to expect of an experiment, one in the short term and one in the long term.

Bringing it All Together: Balancing a Fight
Let's say that you have an Ogre enemy who should be a reasonably-challenging boss for players around level (LVL) 10. By "reasonably-challenging", we'll say that it should take on average ten hits for a Player to kill the Ogre, but only three hits for the Ogre to kill the Player (and we're assuming the game is such that the Player can do hit-and-run style tactics, meaning it's up to the player to dodge).

First, let's decide what the player's attack (ATK) stat should be like. Let's say that ATK is distributed according to 2d6+LVL. That is, you take the 2d6 distribution above and add the player's LVL to each value (so a 2 maps to 10, a 3 maps to 13, and so on) but the probabilities otherwise remain the same. Then both the mode and the expected value of the Player's ATK become 17, and thus in order to kill the Ogre in ten hits (for a Player at LVL 10) he should have 170 health.

Before moving on, we should consider the best-case and worst-case scenarios. What if the player does the absolute maximum DAM with each hit? (i.e., 22 DAM) Then it would take 170/22 ~ 7.27 ~ 8 strikes to kill the Ogre. What is the probability of doing 8 strikes with 22 DAM? Since the results are independent, it's just f(22)8 = 1/368 ~ 0.000000000035% of the time. In other words, it's extremely unlikely.

The worse case scenario is doing 12 DAM per hit, requiring 170/12 ~ 14.16 ~ 15 hits. Likewise, this has a probability of f(12)15 = 1/3615 ~ 0.00000000000000000000045% of the time. Even less likely.

Now, let's assume that at LVL 10 the player has 50 health (HLTH). We want the Ogre to kill the player in an average of three hits at LVL 10, so what is the necessary DAM for the Ogre? 50/3 ~ 16.66 ~ 17, so we can actually use the same distribution as for the Player, with the Ogre's DAM ~ 2d6+10. The only difference between the Ogre and the Player is that the Ogre is a tank and can take a lot of hits before falling.

As above, we'll look at best and worst-case scenarios. In the best case, the Ogre does 22 DAM and kills the player in 50/22 ~= 2.27 ~ 3 hits, which is actually still within our threshold for the fight being "reasonably-challenging". This happens about 0.0021% of the time. This is rare, but likely enough that it could be an issue if he was one-hit KOing the players. Luckily, he's not, so no rebalancing is necessary.

In the worst-case scenario, he does 12 DAM and kills the player in 50/22 ~ 4.16 ~ 5 hits. This has a probability of occurring about 0.0000016% of the time, which is much more rare. Still, five hits is nevertheless pretty challenging.

Therefore, for the Ogre to be challenging to a LVL 10 Player, we have the following requirements:
/*
Player:
-------
At LVL 10,
DAM = 2d6+10
HLTH = 50

Ogre:
-----
For LVL 10 players,
DAM = 2d6+10
HLTH = 170
*/

With these, it should fit into our requirements.

Now obviously this is a very, very simple case. You could make it more interesting, for example by changing how damage is distributed for one or both of the Ogre and the Player, or change how damage is taken (perhaps there is a damage reduction stat that is also randomly distributed). Maybe you want to account for multiple players attacking it at once, and have to adjust its HLTH and DAM accordingly. Perhaps there are critical hits that do extra damage, or ways to attack the Ogre without risking it hitting you. All these can be modeled in various ways.

And the distributions can be much different as well. For example, say you roll 4 6-sided dice and after rolling them label then X1, X2, X3, X4 where X1 <= X2 <= X3 <= X4. Choosing any pair of these dice will give you a probability distribution with a sample space of {2, 3, ..., 11, 12}, but the distribution itself will now be much different. If you take the sum of the lowest and second lowest die (X1 + X2), you get the distribution

while if you take the sum of the lowest and second highest die (X1 + X3) you get,
.
Clearly, these are both very different from the regular 2d6 distribution.

In Summary
Probability is a powerful tool, if done right and applied sensibly and creatively. But, it can be a fickle thing if done wrong. Be sure to apply it well.

And maybe you ungracious asses here might finally learn something, but probably not.
Thinking about probability and random numbers, I have learned from using C's rand() that not all random number generators are perfect.

Reason for my statement on that is because I have seen certain numbers never get generated. I assume you already know the linear congruential generator Fizz? Known as one of the most unreliable random number generators in existence. Easy to use, but very unreliable.

For that reason, your post provides a great insight into probabilities.
Very informative read and bookmarked. This will make the balancing act that much simpler.
In response to Bandock
Bandock wrote:
I assume you already know the linear congruential generator Fizz? Known as one of the most unreliable random number generators in existence. Easy to use, but very unreliable.

I'm not an expert in PRNGs, but it looks like they're good so long as you know their limitations. E.g., they are not good for cryptography or simulations where long-term appearances of periodicity are bad, but if you're just simulating dice rolls for a game then it shouldn't be a problem.
In response to Popisfizzy
Popisfizzy wrote:
Bandock wrote:
I assume you already know the linear congruential generator Fizz? Known as one of the most unreliable random number generators in existence. Easy to use, but very unreliable.

I'm not an expert in PRNGs, but it looks like they're good so long as you know their limitations. E.g., they are not good for cryptography or simulations where long-term appearances of periodicity are bad, but if you're just simulating dice rolls for a game then it shouldn't be a problem.

Yep, good point. It does work great for dice rolls. Just not for very large numbers.
Like a Star-Nosed Mole on the hunt for Black Beard's treasure... I'm diggin' it.
BYOND now uses a Mersenne twister as its PRNG, which helps produce more "random" distributions than an LCG.

This was a great article, Pop. I loved your in-depth section on how to use probabilities to balance a game, which frankly is something a lot of game authors don't even think about.

One of the things I've mentioned before in terms of gameplay is that if your player is leveling up, you probably want to map out how long it will take them to reach the next level. E.g., how long would it take in casual play, how long if the player really went on a grind, etc. I think something like 10 minutes per current level to reach the next one is a good goal to shoot for when it comes to standard play, but the actual metric used is sort of beside the point. The important thing is to think in these terms. How long does it take to reach the next level? (That's good for calibrating XP.) How many hits should the player be able to take before dying against an opponent built for their level--assuming certain things about their equipment, stats, skills, etc.--and how many hits should they have to dish out?
It's nice to see that it's not so uncommon to balance games this way. I've been using base health as a standard balancing point for game design. It's only the most logical solution, after all. When a game is defined on combat, the only goal that really matters at the end of the day is reducing your opponent's HP to 0 before they can do that to you. By that logic, it's obviously best to use that core stat to balance the rest of your game from.
HP is itself a big abstraction of a whole bunch of things: size, physical ability to take a beating, combat experience, etc. Balancing tends to get weird when authors forget that and try to use HP in a classical way on top of providing bigger and better armor/weapons/etc. all the time.
In response to Lummox JR
I agree with that aspect in respect to realism, but then again, there are tons of games where the specific details of WHY someone's HP is the way it is isn't really that important. It's at that point where HP becomes little more than a number to determined isAlive()?TRUE:FALSE. Which tends to be the way I use it. I typically find it easier to balance when I'm not worried about all of the tiny details.
I've never really seen much need for realism in games.

Depth and complexity can be fun (see Dwarf fortress, cataclysm DDA), but I wouldn't call DF's complex surgery and wounding system realistic.

On the other hand, Zelda's heart system is completely fine even though it's highly unrealistic. It lends itself to a progression over time where the player finds that they have become stronger and more resilient through their course in the game. Meanwhile, it can also add an extra layer of challenge where the player can choose not to pick up extra heart pieces in order to make the game more difficult. (3 heart challenge).