From efaf2e947af135101337db14c73e299cfdbfc34b Mon Sep 17 00:00:00 2001
From: Kamron Batman <3953314+kamronbatman@users.noreply.github.com>
Date: Tue, 22 Nov 2022 19:53:20 -0800
Subject: [PATCH] feat: Adds weighted values (#1265)
---
Projects/Server/Random/WeightedValue.cs | 34 +++++++++
Projects/Server/Utilities/Utility.cs | 96 +++++++++++++++++++++++++
2 files changed, 130 insertions(+)
create mode 100644 Projects/Server/Random/WeightedValue.cs
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)
{