Get Random Object with Probability – C# Script

Originally posted on my blog here.

Here is a free script that demonstrates how to get a random object based on probability. I’ve set up a scenario for a C# Console project for Visual Studio. I’ve put comments in the code to explain how the probabilities work, and it should be easy enough to swap and change for your own projects.

I used this method to create a custom brush for painting random tiles with Unity Tilemaps, which I’ve been using to build levels for Puzzledorf (example below) and you can see that script here.

Random brush example:

Which I used to make the randomly generated water, among other things, for this project here:

Setting Up A Console App in Visual Studio

If you haven’t set up a console app in visual studio before, this article here has quick instructions on how to do that.

C# Console Code Example

using System;
using System.Linq;

namespace RandomNameApp
{
    public class RandomNames
    {
        // Our class to store the random object, in this case names, and a probability to be assigned to each one
        public class NameToSpawn
        {
            public string name;
            public float probability;
        }

        // Here we manually create a list of names and assigh each one a probability.
        // We have based this on the concept of 100%, assigning each one a % so that they all add up to 100%.
        // You could assign any number, but this makes it easier to do the mental math and create the sort 
        // Of probability you are expecting.
        public static NameToSpawn[] listOfNames = new NameToSpawn[]
        {
            new NameToSpawn { name = "Bob", probability = 70f },
            new NameToSpawn { name = "Mo", probability = 10f },
            new NameToSpawn { name = "Sam", probability = 5f },
            new NameToSpawn { name = "Jake", probability = 1f },
            new NameToSpawn { name = "Sally", probability = 14f }
        };

        // CASE SCENARIO - PROBABILITIES:
        // Let's say we have 5 names, each with the following probabilities: Bob: 70, Mo: 10, Sam: 5, Jake: 1, Sally: 14.
        // Here's a step by step example with a random value of 81:
        // 1: INITIALIZATION
        //      A: Calculate the total probability: 70 + 10 + 5 + 1 + 14 = 100.
        //      B: The random value is 81.
        // 2: LOOP ITERATION 1
        //      A: Enter the loop and take the first nameInfo (Bob with a probability of 70).
        //      B: Subtract the probability of the current name from the random value: 81 - 70 = 11.
        //      C: The result (11) is not less than or equal to 0, so we move on.
        // 3: LOOP ITERATION 2
        //      A: Take the second nameInfo (Mo with a probability of 10).
        //      B: Subtract the probability of the current name from the updated random value: 11 - 10 = 1.
        //      C: The result (1) is not less than or equal to 0, so we proceed.
        // 4: LOOP ITERATION 3
        //      A: Take the third nameInfo (Sam with a probability of 5).
        //      B: Subtract the probability of the current name from the updated random value: 1 - 5 = -4.
        //      C: The result (-4) is less than 0, which means the random value has fallen within the range of this name's probability.
        // 5: NAME SELECTION
        //      A: The loop condition is met, and the method returns the nameInfo.name associated with the current nameInfo (Sam).

        // EXPLANATION
        // The higher the probability of a name, the more "chances" that it will be selected.
        // To ensure accurate probabilities, it's helpful to make sure that the sum of all names' probabilities
        // adds up to a total like 100, 1, or 1000.

        // The code works by:
        // - Adding the probabilities of all names together.
        // - Generating a random number between 0 and 1, which helps normalize our range of possibilities,
        //   then multiplying it by 100, ensuring we have a random number within the range of name probabilities.
        // - Looping over our list of random names, and each time we do, subtracting the probability of the current name
        //   from our random value. This subtraction process helps us select a name.
        // - If we reach 0 or less than 0, we select that name.
        // For a clearer understanding, refer to the Case Scenario above.


        private static string GetRandomName()
        {
            // Calculate the total probability of all available names, by adding them all together.
            // We then create a random number between 0 and 1, and multiply that by the total probabilities
            // to make sure our random value falls within the range of our probabilities
            // This new randomValue will be used to select a name based on its probability.
            float totalProbability = listOfNames.Sum(nameInfo => nameInfo.probability);
            double randomValue = new Random().NextDouble() * totalProbability;

            // Now loop over each name.
            // As we loop, we reduce 'randomValue' by the probability of each individual name's own probability
            // This step simulates the process of selecting a name. As the loop iterates,
            // it subtracts the probability of each name from the random value, moving closer to zero.
            // If the random value is <= 0, that indicates that the random value has fallen within the range of a specific name's probability.
            // In other words, we've reached our randomly selected name, so we then return the name
            foreach (var nameInfo in listOfNames)
            {
                randomValue -= nameInfo.probability;
                if (randomValue <= 0f)
                {
                    return nameInfo.name;
                }
            }

            return listOfNames[0].name; // Fallback if probabilities are not properly set
        }

        // This function is where the program starts, similar to the "Start"
        // function in a Unity script.
        static void Main(string[] args)
        {            
            // Flag to control the program loop
            bool runProgram = true;

            // Loop that allows running the program multiple times
            while (runProgram)
            {
                // Generate and print 10 random names
                for (int i = 0; i < 10; i++)
                {
                    string randomName = GetRandomName();
                    Console.WriteLine(randomName);
                }

                // Ask the user if they want to run the program again
                Console.Write("Do you want to run this program again? YES or NO: ");
                string response = Console.ReadLine().Trim().ToLower();

                // Check user's response
                if (response == "no")
                {
                    runProgram = false; // Stop the loop if user's response is "no"
                }
                else if (response != "yes")
                {
                    Console.WriteLine("Invalid response. Exiting the program.");
                    runProgram = false; // Stop the loop for any other response
                }
            }
        }
    }

Leave a comment

Blog at WordPress.com.

Up ↑