using GameKit.Dependencies.Utilities.Types;
using System.Collections.Generic;
using UnityEngine;
namespace GameKit.Dependencies.Utilities
{
public interface IWeighted
{
float GetWeight();
ByteRange GetQuantity();
}
public static class WeightedRandom
{
///
/// Gets random entries by weight.
///
/// Entries to pull from.
/// Number of entries to get.
/// Results of entries. Key is the entry, Value is the number of drops.
/// True to allow the same entry to be included within results more than once.
public static void GetEntries(List source, IntRange countRange, ref Dictionary results, bool allowRepeatingDrops = false) where T : IWeighted
{
if (source == null || source.Count == 0)
{
Debug.Log($"Source list of type {typeof(T).Name} cannot be null or empty.");
return;
}
int count = Ints.RandomInclusiveRange(countRange.Minimum, countRange.Maximum);
//If to not return any then exit early.
if (count == 0)
return;
//Number of times each item has dropped.
Dictionary dropCount = CollectionCaches.RetrieveDictionary();
//Get the total weight.
float totalWeight = 0f;
for (int i = 0; i < source.Count; i++)
totalWeight += source[i].GetWeight();
//Make a copy of source to not modify source.
List sourceCopy = CollectionCaches.RetrieveList();
foreach (T item in source)
sourceCopy.Add(item);
while (results.Count < count)
{
int startCount = results.Count;
/* Reset copy to totalWeight.
* totalWeight will be modified if
* a non-repeatable item is pulled. */
float tWeightCopy = totalWeight;
float rnd = UnityEngine.Random.Range(0f, totalWeight);
for (int i = 0; i < sourceCopy.Count; i++)
{
T item = sourceCopy[i];
float weight = item.GetWeight();
if (rnd <= weight)
{
//Try to get current count.
results.TryGetValueIL2CPP(item, out uint currentCount);
//Set new vlaue.
results[item] = (currentCount + 1);
/* If cannot stay in collection then remove it
* from copy and remove its weight
* from total. */
if (!allowRepeatingDrops)
{
sourceCopy.RemoveAt(i);
totalWeight -= weight;
}
break;
}
else
{
tWeightCopy -= weight;
}
}
/* If nothing was added to results then
* something went wrong. */
if (results.Count == startCount)
break;
}
CollectionCaches.Store(dropCount);
}
}
}