using Core.Annotations;
using Core.Models.Spt.Helper;
using ILogger = Core.Models.Utils.ILogger;
namespace Core.Helpers;
[Injectable]
public class WeightedRandomHelper
{
private readonly ILogger _logger;
public WeightedRandomHelper(
ILogger logger)
{
_logger = logger;
}
///
/// Choose an item from the passed in array based on the weightings of each
///
/// Items and weights to use
/// Chosen item from array
public T GetWeightedValue(Dictionary values) where T : notnull
{
var itemKeys = values.Keys.ToList();
var weights = values.Values.ToList();
var chosenItem = WeightedRandom(itemKeys, weights);
return chosenItem.Item;
// SORRY IF THIS BLEW UP, I DONT SEE A REASON ITS GENERIC - CWX
}
///
/// Picks the random item based on its weight.
/// The items with higher weight will be picked more often (with a higher probability).
///
/// For example:
/// - items = ['banana', 'orange', 'apple']
/// - weights = [0, 0.2, 0.8]
/// - weightedRandom(items, weights) in 80% of cases will return 'apple', in 20% of cases will return
/// 'orange' and it will never return 'banana' (because probability of picking the banana is 0%)
///
///
/// List of items
/// List of weights
/// Dictionary with item and index
public WeightedRandomResult WeightedRandom(List items, List weights)
{
if (items.Count == 0)
{
_logger.Error("Items must not be empty");
}
if (weights.Count == 0)
{
_logger.Error("Item weights must not be empty");
}
if (items.Count != weights.Count)
{
_logger.Error("Items and weight inputs must be of the same length");
}
// Preparing the cumulative weights list.
List cumulativeWeights = [];
for (var i = 0; i < weights.Count; i++)
{
cumulativeWeights.Add(weights[i] + (i > 0 ? cumulativeWeights[i - 1] : 0));
}
// Getting the random number in a range of [0...sum(weights)]
int maxCumulativeWeight = cumulativeWeights[cumulativeWeights.Count - 1];
double randomNumber = maxCumulativeWeight * new Random().NextDouble();
// Picking the random item based on its weight.
for (int itemIndex = 0; itemIndex < items.Count; itemIndex++)
{
if (cumulativeWeights[itemIndex] >= randomNumber)
{
return new WeightedRandomResult()
{
Item = items[itemIndex],
Index = itemIndex,
};
}
}
throw new InvalidOperationException("No item was picked.");
}
///
/// Find the greated common divisor of all weights and use it on the passed in dictionary
///
/// Values to reduce
public void ReduceWeightValues(Dictionary weightedDict)
{
throw new NotImplementedException();
}
protected double CommonDivisor(List numbers)
{
throw new NotImplementedException();
}
protected double Gcd(double a, double b)
{
throw new NotImplementedException();
}
}