Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I appear to be awful at describing the question so I'll try and describe the problem.

I want to add a random amount of heads to my creatures but I want to be able to determine several things. a) The minimum number of possible heads b) The maximum number of possible heads c) The probability of the number being high/low within the above values.

So i could add heads like so: addHeads(5, 10, 0.5); // should produce creatures with "around" 7.5 heads but they could have anywhere from 5 to 10.

So random number generation isn't the problem, but controlling and actually using them in a game is. :D

share|improve this question
1  
you'll need to precisely define how the third parameter will affect the distribution, then when you have that (parameterized) function take the integral and invert it –  ratchet freak Apr 27 '13 at 0:59
    
This question: gamedev.stackexchange.com/questions/12638/… –  Nevermind Apr 27 '13 at 5:04

3 Answers 3

up vote 3 down vote accepted

One way to do it is to apply a power function. Start with a random number in [0, 1] and then raise it to the power of some positive number. Powers < 1 will bias upward, i.e. the numbers will be more likely to be higher than lower within [0, 1], and powers > 1 will bias downward. Then use multiplication and addition to shift the range of numbers from [0, 1] to your desired range. In pseudocode:

function random(low, high, bias)
{
    float r = rand01();    // random between 0 and 1
    r = pow(r, bias);
    return low + (high - low) * r;
}

// Examples:
random(5, 10, 1.0);  // between 5 and 10, average is 7.5
random(5, 10, 0.5);  // between 5 and 10, average is somewhere around 8.5
random(5, 10, 2.0);  // between 5 and 10, average is somewhere around 6.5

Here's a plot of the second example:

enter image description here

On the horizontal is the initial random number in [0, 1] and on the vertical is the output. You can see that something like 75% of the initial range is mapped to values higher than 7.5, and 25% of the initial range is mapped below 7.5. So the result is that numbers generated by this function are more likely to be higher.

share|improve this answer
1  
The only suggestion I'd say to this method is that, for whole, discrete results, especially in low numbers, the common sense mins and maxes result in a skew away from the min and max. Wanting, to use the example provided in the question, a small number for "number of heads", say 1-4, will result in greater frequency of 2 or 3 with traditional rounding. In this case, the max should be one higher with the result rounded down, lest an unintuitive 1:2:2:1 ratio form. –  Attackfarm Apr 27 '13 at 5:23
    
This answer makes the most sense to me. To clarify, to implement Attackfarm's fix, I want to increase the max by one before the the calculation and round the whole result down at the end? –  Caustic Apr 27 '13 at 6:08
    
Yes. There are other ways to do it, but that's the simplest. Though, I must say, Byte56's answer is definitely much more powerful (though slightly harder to implement, since this is just a single Math-library function), this would suit simpler needs fine. –  Attackfarm Apr 27 '13 at 6:42

I have a harvest system implemented in my game that utilizes rejection sampling. Each item has a weighted chance of being produced. It's easy to assign weights to certain items and get one randomly using that weighted chance. This is similar to your situation, except you don't have harvest items, you have number of heads. So, you'd first assign a weighted chance to each head count value for the values you want.

So we have # of heads : weighted chance

5 heads:2
6 heads:4
7 heads:3
8 heads:1
9 heads:2
10 heads:1

The weighted chance values don't have to add up to anything specific, but you should know that they are going to be relative to each other.

Then we go through and make a list of them all:

ArrayList<ProducedItemInfo> tmpList = new ArrayList<ProducedItemInfo>();
    int totalChance = 0;
    for (HeadWeightPair hwp: headWeightPairs) {
        if(conditionsMetFor(hwp)) {
            totalChance += hwp.weightedChance;
            tmpList.add(hwp);
        }
    } //add up the total weight and create a list of the available options
      // at this stage, you could have conditions that would preclude certain options
      // for example, you could check the size of the creature and
      // not allow high numbers of heads
      // if you'll never have conditions, just generate this list once and keep it
    //now we go through removing a random value from the totalChance
    // if one of the items is less than the total, we return that item
    if (totalChance > 0) {
        int rand = randomInt(totalChance);
        for (HeadWeightPair hwp: tmpList) {
            if (rand < hwp.weightedChance) { return hwp.headCount; }
            rand -= hwp.weightedChance;
        }
    }

It's log(n) if you have a pre-compiled list (if you don't have conditions you can do that).

share|improve this answer
    
This seems like a great way of doing it when you want to specify the chance individually and I may use it for another part of my project, so thank you. –  Caustic Apr 27 '13 at 6:15

The usual answer will be some code that can tweak the random number distribution to give you the properties you want. I'd suggest instead working backwards:

  1. first decide what distribution you actually want and draw it out
  2. calculate the “cumulative distribution” which is the sum of the function in step 1
  3. choose a random number from the cumulative distribution
  4. look up the number from the original distribution you drew

This way you don't ever actually need to find a function (like power or logarithm) that matches your desired behavior. You can directly model your desired behavior.

How do you implement this? You can approximate step 1 with a table. For step 2 you add the values in the table. For step 3 you pick a random number from 0 to the sum in the cumulative table. Then for step 4 you look for the corresponding entry in the cumulative table.

I don't yet have a great description of this technique, but I've written a little bit in the “Designing your own distribution” section of this page.

This approach probably won't work for everything but I mention it because tables are nice for designers to edit, and the designer is not limited to existing mathematical functions but instead can choose any arbitrary wacky shape. For example, if you decide that a prime number of heads should be unusually rare, that's easy to write in a table, but it might be harder to find a mathematical function that fits that shape.

share|improve this answer
    
This probably makes sense but not to me, I'm afraid. I can assume what a distribution is in this context but draw it out? What does this mean? I'm guessing you don't mean on paper.. –  Caustic Apr 27 '13 at 6:06
    
I do mean on paper :) … first you want to decide on what shape you want, because it's part of your game design. Only after you have a shape do you figure out the corresponding formulas or code. You're not limited to using a standard function like sqrt or pow. Don't limit yourself! :) You can use any arbitrary shape encoded in a table (“piecewise linear function”). –  amitp May 14 '13 at 17:33

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.