I'd like my character's attacks to on average 10 damage, but to vary anywhere from 0 to 20.

Instead of a linear spread, I would like a normal distribution, so most of their hits are between 10-15, but they can still hit between 0-20. How can I do this?

I am using PHP.


3 Answers 3


Second (harder) aproach. I used that in c# to get a gaussian distribution (link) i think you can easly traslate in php.

private double  nextGaussian(double mean,double variance ) {
            // https://stackoverflow.com/questions/218060/random-gaussian-variables

            //with mean = 0.5 and variance = 0.5 we get uniform distribution over [0..1]

            double u1 = r.NextDouble(); //these are uniform(0,1) random doubles
            double u2 = r.NextDouble();
            double randStdNormal = Math.Sqrt(-2.0 * Math.Log(u1)) *
                         Math.Sin(2.0 * Math.PI * u2); //random normal(0,1)
                         //Math.Sin( Math.PI * u2); //random normal(0,1)
            double randNormal =
                         mean + variance * randStdNormal; //random normal(mean,stdDev^2)

            return randNormal;


You can try

 damage = nextGaussian(0.5, 0.2) *MAXDAMAGE ;

and play with second parameter of nextGaussian (variance).

Here follow a test I made distributing points over x axe changing the variance : enter image description here


An easy way is roll 4 dice (6 faces) add them , then subtract 4. You get 0..20 with more distribution in the middle. Or 2 * 12 FACE dice - 2.

  • \$\begingroup\$ surely 5 * 4d rolls would be better due to no subtraction, and with a higher number of rolls (granted its only one) the distribution becomes more pronounced (less likely to get those extremes). 2 12d rolls would result in large variance in the numbers, whilst this still leans in favor of the median numbers, it would also allow the extremes to be more likely. I prefer your other answer as numbers, however this stands as a good visual representation \$\endgroup\$
    – nickson104
    Sep 8, 2015 at 10:04
  • 1
    \$\begingroup\$ you're right but with 5 * 4d you miss 0..3 values requested by Thomas in his question \$\endgroup\$ Sep 8, 2015 at 10:07
  • \$\begingroup\$ You are correct, using any dice system without subtraction would eliminate any number fewer than the number of dice, therefore the subtraction is a necessary stage in order to include those numbers \$\endgroup\$
    – nickson104
    Sep 8, 2015 at 10:40

Would personally suggest the following KISS technique to convert uniform distribution to slanted distribution:

Randomly (uniformly), draw a number x between 0 and 1. Now raise x by some const predetermined p value (likely) in the range between 1.1 to 7. The larger p is, the more slanted (and less likely to hit extreme results) it'll be. Lets call x by the power of p our offset coefficient. Now randomly pick a sign (i.e plus or minus [negative, positive]). OK, the center of your desired range is 10 == the max offset from the center.

// Essentially
// center +/- offset = min/max
// 10 - 10 = 0
// 10 + 10 = 20

//  So now, you simply do in pseudo code:
small_buffer = ~ 0.1 * range;
rand   = randomize_float_between(0, 1);
coefficient = pow(rand, p);
sign   = pick_one_of_these(-1, 1);
result = center + sign * coefficient * (offset + small_buffer);
result = max(0, min(result, 20)); // Keep it in range

This is the simplest way to get and tweak the effect you are looking for.

  • \$\begingroup\$ +1 Good alternative. A mathematically correct Gaussian distribution is difficult to tune right, expensive to calculate, and overkill for most games. \$\endgroup\$
    – Anko
    Sep 8, 2015 at 15:23
  • \$\begingroup\$ @Anko thanks, any monotonously increasing function from (0, 1) to (0, 1) should work (assuming it's starts with f(0) = 0 and ends with f(1) = 1). For instance, instead of x^p we could do (2^(x * 10) - 1) / 1023 for a possibly more extreme slant. \$\endgroup\$
    – AturSams
    Sep 8, 2015 at 15:37

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .