123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200 |
- using Island.StandardLib.Storage;
- using System;
- namespace Island.StandardLib.Math
- {
- /// <summary>
- /// 表示一个总和为1的平衡容器
- /// </summary>
- public class Percentage : IStorable
- {
- StorableFixedArray<Key> percentages;
- public int KeyLength => percentages.Length;
- public float Maxium
- {
- get
- {
- float maxium = percentages[0].Value;
- for (int i = 1; i < percentages.Count; i++)
- if (percentages[i].Value > maxium) maxium = percentages[i].Value;
- return maxium;
- }
- }
- public int MaxiumId
- {
- get
- {
- float maxium = percentages[0].Value;
- int id = 0;
- for (int i = 1; i < percentages.Count; i++)
- if (percentages[i].Value > maxium)
- {
- maxium = percentages[i].Value;
- id = i;
- }
- return id;
- }
- }
- public float Minium
- {
- get
- {
- float minium = percentages[0].Value;
- for (int i = 1; i < percentages.Count; i++)
- if (percentages[i].Value < minium) minium = percentages[i].Value;
- return minium;
- }
- }
- public int MiniumId
- {
- get
- {
- float minium = percentages[0].Value;
- int id = 0;
- for (int i = 1; i < percentages.Count; i++)
- if (percentages[i].Value < minium)
- {
- minium = percentages[i].Value;
- id = i;
- }
- return id;
- }
- }
- public Percentage() { }
- /// <summary>
- /// 初始化容器
- /// </summary>
- /// <param name="sourceValue">初始数据</param>
- public Percentage(params float[] sourceValue)
- {
- percentages = new StorableFixedArray<Key>();
- if (sourceValue.Length == 0) throw new Exception();
- float val = 0;
- for (int i = 0; i < sourceValue.Length; i++)
- {
- val += sourceValue[i];
- percentages.Add(new Key(sourceValue[i]));
- }
- if (val != 1f)
- AdjustBalance();
- }
- /// <summary>
- /// 获取和设置数据。其中,设置数据后会自动按比例平衡容器,保证容器总和为1
- /// </summary>
- /// <param name="index">数据序号</param>
- /// <returns></returns>
- public float this[int index]
- {
- get => percentages[index].Value;
- set => AdjustKeep(index, value);
- }
- public float[] SelectBalance(params int[] selectedIndex)
- {
- float[] values = new float[selectedIndex.Length];
- for (int i = 0; i < selectedIndex.Length; i++)
- values[i] = percentages[selectedIndex[i]].Value;
- float total = 0f;
- for (int i = 0; i < values.Length; i++)
- total += values[i];
- float px = 1 / total;
- for (int i = 0; i < values.Length; i++)
- values[i] *= px;
- return values;
- }
- public int Random(int seed = 0)
- {
- Random rd = seed == 0 ? new Random() : new Random(seed);
- double select = rd.NextDouble();
- float thisMin = 0f;
- for (int i = 0; i < KeyLength; i++)
- {
- float thisMax = thisMin + this[i];
- if (select >= thisMin && select < thisMax)
- return i;
- thisMin = thisMax;
- }
- return -1;
- }
- public long Total(int index, long totalValue)
- {
- return (long)(this[index] * totalValue);
- }
- void AdjustBalance()
- {
- float total = 0f;
- for (int i = 0; i < KeyLength; i++)
- total += this[i];
- float px = 1 / total;
- for (int i = 0; i < KeyLength; i++)
- percentages[i].Value *= px;
- }
- void AdjustKeep(int keepIndex, float newValue)
- {
- AdjustBalance();
- float distance = this[keepIndex] - newValue;
- percentages[keepIndex].Value = newValue;
- float[] gains = new float[KeyLength - 1];
- int g = 0;
- for (int i = 0; i < KeyLength; i++)
- {
- if (keepIndex == i)
- continue;
- gains[g] = this[i]; g++;
- }
- Percentage p = new Percentage(gains);
- g = 0;
- for (int i = 0; i < KeyLength; i++)
- {
- if (keepIndex == i)
- continue;
- percentages[i].Value += p[g] * distance; g++;
- }
- }
- public override string ToString()
- {
- string s = "Percentage [";
- float total = 0f;
- for (int i = 0; i < KeyLength; i++)
- {
- total += this[i];
- if (i == KeyLength - 1)
- s += this[i].ToString("P");
- else s += this[i].ToString("P") + ", ";
- }
- return s + "]";
- }
- public void ReadFromData(DataStorage data)
- {
- data.Read(out percentages);
- }
- public void WriteToData(DataStorage data)
- {
- data.Write(percentages);
- }
- class Key : IStorable
- {
- public float Value;
- public Key() => Value = 0f;
- public Key(float sourceValue) => Value = sourceValue;
- public void ReadFromData(DataStorage data) => data.Read(out Value);
- public void WriteToData(DataStorage data) => data.Write(Value);
- }
- }
- }
|