Selecting Distinct Values

Often, it's essential to ensure that each value you select from a set is unique. While selecting distinct values alters the inherent probabilities, this guide will walk you through a straightforward approach to achieving this using the Depletable Lists feature of RNGNeeds.


Selecting Unique Rewards

Imagine a scenario where you'd like to offer players three unique rewards upon completing a game level. Using the Depletable Lists feature is the ideal option here, as each picked reward will be automatically depleted, thus appearing in the result only once.

Firstly, let's establish a basic Reward class. This class will:

  • Contain details about the in-game currency.
  • Provide relevant information to the drawer through the info provider interface.

Basic Reward Class

using System;
using RNGNeeds;

[Serializable]
public class Reward : IProbabilityItemInfoProvider
{
    public string currency;
    public int value;
    public string ItemInfo => $"{currency} ({value.ToString()})";
}

Subsequently, we'll introduce a LevelCompletionRewards component that will be responsible for housing our range of potential rewards.

Add a ProbabilityList for Rewards

using UnityEngine;
using RNGNeeds;

public class LevelCompletionRewards : MonoBehaviour
{
    public ProbabilityList<Reward> rewards;
}

After attaching the component to a GameObject, you can begin shaping your array of rewards.

Distinct Selection - Depletable List

With the reward pool in place, it's time to set the list as Depletable. First, ensure the Advanced options are enabled:

  1. Activate Advanced Drawer Options Level: Navigate to the Preferences window and switch Drawer Options Level to Advanced. Activating this global setting will reveal advanced features across all your Probability List inspectors.

  2. Open the PICK section of the drawer and click the Depletable button. By default, each Probability Item is marked as Depletable with 1 / 1 available / maximum units.

  3. Turn on the Maintain Pick Count option and set the Pick Count of this list to 3.

  4. Enable the Visualize Units in the Stripe option to better display the remaining units for each item.

Distinct Selection - Depletable List Options

When you click the TEST button, it selects three distinct items from the list, taking into account the probability distributions and the units available. Since each item has only one unit available, each is selected just once. The remaining units are clearly displayed on the stripe, and the unit counts beside each item decrease accordingly. With repeated testing, the list is depleted until no items remain selectable.

Distinct Selection - Depletable List Result

Now that we've established our list of unique rewards and tested the outcomes, the final step involves implementing the code to select the rewards. Incorporate the following method into the LevelCompletionRewards component:

Add the PickRewards method

public List<Reward> PickRewards(int count)
{
    rewards.RefillItems();
    rewards.MaintainPickCountIfDisabled = true;
    return rewards.PickValues(count);
}

Before selecting values, the PickRewards method performs the following operations:

  • Refills the units of all items to their maximum, ensuring every reward is accessible in case they were depleted in the last pick.
  • Sets the MaintainPickCountIfDisabled property to true, assuming the list was not already configured this way in the inspector.

To see this in action, invoke the PickRewards method:

Test the distinct selection

var pickedRewards = PickRewards(rewardsToPick);

foreach (var reward in pickedRewards)
{
    Debug.Log(reward.ItemInfo);
}

// An example console output with three unique rewards could be:
// Gold (250)
// Diamonds (7)
// StarDust (50)

Alternative Approach

First, create the Reward and LevelCompletionRewards classes following the guide above.

After attaching the component to a GameObject, you can start shaping your array of rewards.

Distinct Selection - List

With the reward pool in place, it's time to introduce the logic ensuring that only distinct rewards are chosen. Incorporate the following segment into the LevelCompletionRewards component.

Add Distinct Selection Logic

using UnityEngine;
using RNGNeeds;
using System.Collections.Generic;

public class LevelCompletionRewards : MonoBehaviour
{
    public ProbabilityList<Reward> rewards;

    public List<Reward> PickRewards(int count)
    {
        rewards.SetAllItemsEnabled(true);
        rewards.MaintainPickCountIfDisabled = true;
        
        var pickedRewards = new List<Reward>();
        
        for (var i = 1; i <= count; i++)
        {
            if (!rewards.TryPickValueWithIndex(out var pickedReward, out var pickedIndex)) continue;
            pickedRewards.Add(pickedReward);
            rewards.SetItemEnabled(pickedIndex, false);
        }

        return pickedRewards;
    }
}

Let's break down the PickRewards method:

  • It initializes by ensuring every reward is accessible for selection using .SetAllItemsEnabled(true).
  • The MaintainPickCountIfDisabled property guarantees that each pick will be successful even if disabled items are present in the list.
  • For each desired reward, the method picks a reward, adds it to the list, and then immediately disables it to ensure uniqueness.

To see this in action, invoke the PickRewards method:

Test the distinct selection

var pickedRewards = PickRewards(rewardsToPick);

foreach (var reward in pickedRewards)
{
    Debug.Log(reward.ItemInfo);
}

// An example console output with three unique rewards could be:
// Gold (100)
// Diamonds (5)
// StarDust (75)

Post-testing, examining the list will reveal that chosen items have been disabled.

Distinct Selection - Pick

In conclusion, by momentarily disabling each item post-selection, this method efficiently curates a set of entirely unique items from the list.