diff --git a/Projects/Server/Random/WeightedValue.cs b/Projects/Server/Random/WeightedValue.cs new file mode 100644 index 000000000..5295d5095 --- /dev/null +++ b/Projects/Server/Random/WeightedValue.cs @@ -0,0 +1,34 @@ +/************************************************************************* + * ModernUO * + * Copyright 2019-2022 - ModernUO Development Team * + * Email: hi@modernuo.com * + * File: WeightedValue.cs * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + *************************************************************************/ + +using System; + +namespace Server.Random; + +public struct WeightedValue +{ + public T Value { get; } + public int Weight { get; } + + public WeightedValue(int weight, T value) + { + Value = value; + Weight = weight; + } + + public bool IsValid => Weight > 0; + + public static implicit operator WeightedValue(ValueTuple pair) => new(pair.Item1, pair.Item2); +} diff --git a/Projects/Server/Utilities/Utility.cs b/Projects/Server/Utilities/Utility.cs index 92eb76035..9effa3b73 100644 --- a/Projects/Server/Utilities/Utility.cs +++ b/Projects/Server/Utilities/Utility.cs @@ -1042,6 +1042,102 @@ public static class Utility [MethodImpl(MethodImplOptions.AggressiveInlining)] public static T RandomElement(this IList list) => list.RandomElement(default); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static WeightedValue RandomWeightedElement(this IList> weightedValues) + { + var totalWeight = 0; + for (var i = 0; i < weightedValues.Count; i++) + { + totalWeight += weightedValues[i].Weight; + } + + return RandomWeightedElement(weightedValues, totalWeight); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static WeightedValue RandomWeightedElement(this ReadOnlySpan> weightedValues, int totalWeight) + { + var random = Random(totalWeight); + + for (var i = 0; i < weightedValues.Length; i++) + { + var weightedValue = weightedValues[i]; + random -= weightedValue.Weight; + + if (random <= 0) + { + return weightedValue; + } + } + + return default; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static WeightedValue RandomWeightedElement(this ReadOnlySpan> weightedValues) + { + var totalWeight = 0; + for (var i = 0; i < weightedValues.Length; i++) + { + totalWeight += weightedValues[i].Weight; + } + + return RandomWeightedElement(weightedValues, totalWeight); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static WeightedValue RandomWeightedElement(this IList> weightedValues, int totalWeight) + { + var random = Random(totalWeight); + + for (var i = 0; i < weightedValues.Count; i++) + { + var weightedValue = weightedValues[i]; + random -= weightedValue.Weight; + + if (random <= 0) + { + return weightedValue; + } + } + + return default; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static WeightedValue RandomWeightedElement(this PooledRefList> weightedValues) + { + var totalWeight = 0; + for (var i = 0; i < weightedValues.Count; i++) + { + totalWeight += weightedValues[i].Weight; + } + + return RandomWeightedElement(weightedValues, totalWeight); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static WeightedValue RandomWeightedElement( + this PooledRefList> weightedValues, + int totalWeight + ) + { + var random = Random(totalWeight); + + for (var i = 0; i < weightedValues.Count; i++) + { + var weightedValue = weightedValues[i]; + random -= weightedValue.Weight; + + if (random <= 0) + { + return weightedValue; + } + } + + return default; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static T TakeRandomElement(this IList list) {