Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 14 Next capture
2021 2022 2023
2 captures
12 Jun 22 - 14 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
1
Question by tablazonsimon · Feb 26, 2019 at 01:19 PM · arrayarraysstringrandom.rangerandomization

How to make certain elements in an array rarer when using random selection?

I think it'd be easier if explain this in bullet form.

  • I got a string array of "worlds".

  • I want it to be able to choose a random "world" every time.

  • However, I want some to be rarer than others.

  • And then, if that world has already been previously chosen, it can't be chosen again. (I think this could be accomplished by making bools?)

Is there any possible way to do that with this current code? Or does it need a completely different construct?

 string [] worlds {"thisworld","thatworld","etc"};

 public void changeWorld () { currentWorld = worlds [Random.Range (0, worlds.Length)];}
 
 
Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

4 Replies

· Add your reply
  • Sort: 
avatar image
1

Answer by tormentoarmagedoom · Feb 26, 2019 at 03:18 PM

Good day.

IT's simple.

As you have all the worlds in a array, you can do something like this:

 string[] worlds  // As you have now
 int[] worldsRarity  // Number from 0 (common) to 99 (extra rare) of each world, in the same order as the string array
 bool[] worldsUsed // bool variable for each world. Once one world is chosen, change its bool to "true"

So now only need to:

A method that does this:

 create random number (lets call it Rand) from 0 to worlds.length
 
 Check worldsUsed[Rand], if its true, make "return;" and call this methid again. If false:
 
 do this to see if it can be selected for rarity issues:
 
 if (Random.Range (0,100) >= worldsRarity[Rand])  //if its true, then load the world[Rand] and change worldsUsed[Rand] to true
 
 if it was false, restart the method again.

So, you have a method that selects random worlds only once and is more probably that selects a common worlds than a rare world.

Bye!

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image
1

Answer by Ymrasu · Feb 26, 2019 at 04:01 PM

Doing a random range from 0 to length of the array, is saying that each entry has the same probability of being selected.

An example:

 world1 - Probability 1
 world2 - Probability 1
 world3 - Probability 1

So with a total of 3 probability, they each have a 1 in 3 chance of being picked.

What you want is something more like this:

 world1 - Probability 10
 world2 - Probability 5
 world3 - Probability 1

With a total probability of 16, the first world has a 10 in 16 change of being pick, the second is 5 in 16 and third is 1 in 16.

To accomplish this in code, you'll need to track the world's probability, so as with another array with matching indexes. You'd add up the probabilities then do a random range from using that total. Then check if that number lands within a probability.

     string[] worlds;
     int[] prob;
     bool[] chosen;
 
     private void Start()
     {
         worlds = new string[] { "thisworld", "thatworld", "someworld", "otherworld" };
         prob = new int[] { 10, 10, 5, 1 };
         chosen = new bool[worlds.Length];
     }
 
     public void changeWorld()
     {
         int totalvalue = 0;
         int runningvalue = 0;
 
         // get sum of probability of world that can be picked
         for (int i = 0; i < worlds.Length; i++) {
             // if not already chosen before
             if (!chosen[i]) {
                 totalvalue += prob[i];
             }
         }
 
         // choose a random number with the total
         int hitvalue = Random.Range(1, totalvalue + 1); // adjust for exclusive max with ints
 
         // run through checking for hits
         for (int i = 0; i < worlds.Length; i++) {
             // if not already chosen before
             if (!chosen[i]) {
                 runningvalue += prob[i];
                 if (hitvalue < runningvalue) {
                     // probability hit
                     currentWorld = worlds[i];
                     chosen[i] = true;
                 }
             }
         }
     
     }

Let me know if you have issues with this or have further questions on this topic.

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image
1

Answer by Hellium · Feb 26, 2019 at 04:12 PM

 private string[] worlds = new string[]
 {
     "thisworld",
     "thatworld",
     "etc"
 };
 
 // This array does not represent real "probabilities", it represents weights, meaning
 // Given two worlds whose indices are i and j,
 // If worldWeights[i] == 2 and worldWeights[j] == 1,
 // The world i as **twice** chances to be chosen comparing to world j
 // Instead of two arrays, you could use an array of structs{ public string world, public float weight }
 private float[] worldWeights = new float[]
 {
     80f,
     15f,
     5f
 };
 
 public void ChangeWorld()
 {
     if( worlds.Length != worldWeights.Length )
         throw new System.InvalidOperationException("The number of weights does not match the number of worlds");
 
     currentWorld = GetWorld();
 }
 
 private string GetWorld()
 {
     float worldWeightsSum = GetWorldWeightsSum();
     float random = Random.Range(0, worldWeightsSum);
     float weightsSum = 0 ;
     for( int i = 0 ; i < worlds.Length ; ++i )
     {
         if( weightsSum <= worldWeights[i] )
         {
             weightsSum += worldWeights[i] ;
             // Reset the weight to 0
             // in order to prevent the world from being picked the next time
             // you call ChangeWorld()
             worldWeights[i] = 0 ;
             return worlds[i];
         }
     }
 }
 
 private float GetWorldWeightsSum()
 {
     float sum = 0 ;
     for( int i = 0 ; i < worldWeights.Length ; ++i )
         sum += worldWeights[i];
     return sum ;
 }
Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image
1

Answer by KDevS · Feb 26, 2019 at 05:16 PM

The simplest way to achieve that with your current structure would be to simply create another list/array which would contain the name of the worlds in the frequency set for them. Then the probability of randomly selecting an item is directly proportional to how many times that item appears in this list.

For example, something like this (Haven't tested the code much but you will get the idea):

 public class Main : MonoBehaviour 
     {
         #region Public Fields
         // Array of choices
         public string[] Worlds = new string[3] { "thisworld", "thatworld", "etc" };
         // Array of rarity values. Lower = More rare
         public int[] Rarity = new int[3] { 20, 10, 1 };
         #endregion
         //
         #region Protected Fields
         #endregion
         //
         #region Private Fields
         // The list from which the worlds will be randomly picked up
         private List<string> m_Worlds = new List<string>();
         #endregion
 
         #region Unity Methods
         // Use this for initialization
         private void Start ()
         {
             for (int i = 0; i < Worlds.Length; i++)
             {
                 if (Rarity.Length > i)
                 {
                     for (int j = 0; j < Rarity[i]; j++)
                     {
                         m_Worlds.Add(Worlds[i]);
                     }
                 }    
             }
         }
 
         // Update is called once every frame
         private void Update()
         {
             if (Input.GetKeyDown(KeyCode.Space))
             {
                 Debug.Log("Next World :: " + GetWorld());
             }
         }
         
         #endregion
 
         #region Public Methods
         public string GetWorld()
         {
             if (m_Worlds.Count > 0)
             {
               // get a random item from the list
               string world = m_Worlds[UnityEngine.Random.Range(0, m_Worlds.Count)];
               // remove all occurances of that item from the list
               m_Worlds.RemoveAll(item => item == world);
               // return the value to the calling function
               return world;
             }

             return null;
         }
         #endregion
Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

118 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Using Random.Range in an array only gives a random output once 2 Answers

Referencing private string for array name 2 Answers

pick a random int with the value of 1 from an array 2 Answers

How do you get different random numbers for each object array? 1 Answer

How to put Random.range in float array? 3 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges