Search Unity

Weighted Random

Discussion in 'Scripting' started by rainboww, Jun 12, 2019.

  1. rainboww

    rainboww

    Joined:
    Jan 5, 2017
    Posts:
    125
    I would like to have random numbers that gravitate to a certain number.

    As example:
    int minnumber=0;
    int maxnumber=1000;
    int weightedtowards=10;

    System.Random randmapgen = new System.Random();
    int finalnumber = randmapgen.Next(minnumber, maxnumber,weightedtowards);
    should get numbers between 0 and 1000 but 50% of the numbers should be between 0 and 20 or in an extra given area or with an extra value how strong it should be weighted.

    Any suggestion for an extension method for random Next?
     
  2. HarvesteR

    HarvesteR

    Joined:
    May 22, 2009
    Posts:
    531
    You could use an animation curve.

    Code (CSharp):
    1. [SerializeField]
    2. AnimationCurve distribution; // defined in inspector
    3.  
    4. public float WeightedRandom()
    5. {
    6.     float v = Random.Range(0f, 1f);
    7.     return distrubution.Evaluate(v);
    8. }
    That way you can remap the evenly distributed values from Random.Range on to a custom distribution curve. A linear distribution would be a straight diagonal. Anything else would bias the randomness.

    That method will give you a float value from 0-1, to get your int, just multiply your max by the random value (and cast to int), or Lerp it if you have a non-zero min.

    Cheers
     
    TaranisElsu and angrypenguin like this.
  3. Antistone

    Antistone

    Joined:
    Feb 22, 2014
    Posts:
    2,836
    You might find it more helpful to think of this as nested random distributions; that is, you decide randomly which of several random distributions to use.

    Your example could be expressed as:
    • 50% chance of a random number between 0 and 20
    • 50% chance of a random number between 21 and 1000
    Expressed that way, you can probably easily write a few lines of code that will compute that particular example.

    If you want to be able to write a single function that does all of those steps algorithmically just based on its input, then you're going to need to be more specific about how you want it to work; just saying "weighted towards 10" doesn't tell me "50% chance of being between 0 and 20".
     
    angrypenguin likes this.
  4. rainboww

    rainboww

    Joined:
    Jan 5, 2017
    Posts:
    125
    I have no ideas of animation curves and its too much work to get into it i think.

    Sounds like a good approach maybe a list of likelyhoods:

    40% of value between 0 and 20
    40% of value between 0 and 100
    20% of value between 0 and 1000
    So i think i could just iterate the list and run 2 randoms one to decide which of the three it is and one with that entrys.
    Guess thankyou thats a fair solution.
     
  5. rainboww

    rainboww

    Joined:
    Jan 5, 2017
    Posts:
    125
    I experimented with something complicated, but for the simple use I did this now:

    Code (CSharp):
    1.  
    2.  
    3.     public static int Next(
    4.         this System.Random random, int min,int max, int weightmin,int weightmax, float weightpower        )    {
    5.         var likelyhood = random.NextDouble(0, 1);
    6.         if (  weightpower > likelyhood)        {
    7.            return random.Next(weightmin, weightmax);
    8.         }
    9.  
     
    Last edited: Jun 12, 2019
  6. Qyubij

    Qyubij

    Joined:
    Aug 11, 2021
    Posts:
    2
    would you be able to give an example of what a graph that would gravitate towards the number in the middle; i'm struggling to visualise it