Intro
I have been looking into dice distributions within the context of rogue-like or D&D type games. I found this question.
In lots of these types of games you will be attacked by something with multiple attacks. In this case a die will be rolled (with some kind of probability of success) to see if your attack succeeds. On success a damage roll will be rolled. For each attack the same probability for success will be used to see if the attack is a 'hit' or a 'miss'.
For my simulation I used two attacks of one six sided die and three ten sided dice. The '3d10' dice are rolled together and summed for damage for a successful attack. Individually these give the pdf of:
Recipe for Simulation
- p = some pre-set probability of success
- sum = summed damage of one attack cycle
- for each attack cycle:
- reset sum
- for each attack roll against p:
- if attack succeeds roll damage dice and add to sum
- if at least one attack succeeds add to sample (we want the damage distribution as p will be changing between simulations)
- repeat attack cycle for N amount amount of trials
Using different levels of p for attack success I found some very distributions:
I would figure this would settle down into some kind of normal-ish distribution, since the p is invariant. But, what I found was very surprising : the p value dictates which dice damage dominates. I assumed that the probability density between the rolls should be about the same regardless of p.
I also tried a mean of means and it seems the CLT comes into play:
Setting p=1 will also produce the same kind normal distribution (although noisier.) You also might notice that the theoretical mean damage (where I have just added together the means of the dice) to the simulation mean damage (bottom left on the graphs) always are close and I would guess approach each other asymptotically.
Question
Why does the probability of success have a relationship to the probability of damage sums? (whatever p is for the simulation it is the same.)
I only took N trials (normalized for samples) to about 10^5 as the code is not very fast and I wanted to make sure it was correct and easy to read. The shape of the distributions do not seem to change with more N.
Code
This the inner code used generate the graphs:
import numpy as np
def simulate(dice, N, defense, sample_size):
rng = np.random.default_rng(12345) # set random number gen
# range() will create a weighted array of possible sums
attacks = [d.range() for d in dice]
sample = []
l = [] # internal counter
for n in range(N):
if not n % 10000:
sys.stderr.write('{:.2e}\n'.format(n))
# sum up all the attacks for each trial
s = 0
for attack in attacks:
if rng.random() >= defense: # check if we succeed
s += np.random.choice(attack) # pick a damage at random
l.append(s)
# if not the first and were on the sample_sizeTH
# (sample size might be one so we count everything)
if n and not n % sample_size:
avg = sum(l) / len(l)
sample.append(avg)
l = []
return sample
0 damage samples later thrown out. N differs so that the the kept samples will be about the same.