168 lines
2.8 KiB
C#
168 lines
2.8 KiB
C#
using System;
|
|
using UnityEngine;
|
|
|
|
public class WeightedSelection<T>
|
|
{
|
|
[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];
|
|
}
|
|
}
|