using System; using UnityEngine; public class WeightedSelection { [Serializable] public struct ChoiceInfo { public T value; public float weight; } [SerializeField] [HideInInspector] public ChoiceInfo[] choices; [HideInInspector] [SerializeField] private int _count; [SerializeField] [HideInInspector] private float totalWeight; private const int minCapacity = 8; public int Count { get { return _count; } private set { _count = value; } } public int Capacity { get { return choices.Length; } set { if (value < 8 || value < Count) { throw new ArgumentOutOfRangeException("value"); } ChoiceInfo[] sourceArray = choices; choices = new ChoiceInfo[value]; Array.Copy(sourceArray, choices, Count); } } public WeightedSelection(int capacity = 8) { choices = new ChoiceInfo[capacity]; } public void AddChoice(T value, float weight) { AddChoice(new ChoiceInfo { value = value, weight = weight }); } public void AddChoice(ChoiceInfo choice) { if (Count == Capacity) { Capacity *= 2; } choices[Count++] = choice; totalWeight += choice.weight; } public void RemoveChoice(int choiceIndex) { if (choiceIndex < 0 || Count <= choiceIndex) { throw new ArgumentOutOfRangeException("choiceIndex"); } int i = choiceIndex; for (int num = Count - 1; i < num; i++) { choices[i] = choices[i + 1]; } choices[--Count] = default(ChoiceInfo); RecalculateTotalWeight(); } public void ModifyChoiceWeight(int choiceIndex, float newWeight) { choices[choiceIndex].weight = newWeight; RecalculateTotalWeight(); } public void Clear() { for (int i = 0; i < Count; i++) { choices[i] = default(ChoiceInfo); } Count = 0; totalWeight = 0f; } private void RecalculateTotalWeight() { totalWeight = 0f; for (int i = 0; i < Count; i++) { totalWeight += choices[i].weight; } } public T Evaluate(float normalizedIndex) { int num = EvaluateToChoiceIndex(normalizedIndex); return choices[num].value; } public int EvaluateToChoiceIndex(float normalizedIndex) { return EvaluateToChoiceIndex(normalizedIndex, null); } public int EvaluateToChoiceIndex(float normalizedIndex, int[] ignoreIndices) { if (Count == 0) { throw new InvalidOperationException("Cannot call Evaluate without available choices."); } float num = totalWeight; if (ignoreIndices != null) { foreach (int num2 in ignoreIndices) { num -= choices[num2].weight; } } float num3 = normalizedIndex * num; float num4 = 0f; for (int j = 0; j < Count; j++) { if (ignoreIndices == null || Array.IndexOf(ignoreIndices, j) == -1) { num4 += choices[j].weight; if (num3 < num4) { return j; } } } return Count - 1; } public ChoiceInfo GetChoice(int i) { return choices[i]; } }