ChanceTable.cs 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using UnityEngine;
  5. namespace DunGen
  6. {
  7. #region Helper Class
  8. /// <summary>
  9. /// A value with a weight
  10. /// </summary>
  11. /// <typeparam name="T">The type of value to use</typeparam>
  12. [Serializable]
  13. public class Chance<T>
  14. {
  15. public T Value;
  16. public float Weight;
  17. public Chance()
  18. :this(default(T), 1)
  19. {
  20. }
  21. public Chance(T value)
  22. :this(value, 1)
  23. {
  24. }
  25. public Chance(T value, float weight)
  26. {
  27. Value = value;
  28. Weight = weight;
  29. }
  30. }
  31. #endregion
  32. /// <summary>
  33. /// A table containing weighted values to be picked at random
  34. /// </summary>
  35. /// <typeparam name="T">The type of object to be picked</typeparam>
  36. public class ChanceTable<T>
  37. {
  38. /// <summary>
  39. /// Values and their corresponding weights, which determine how likely a value is to be picked relative to others in the table
  40. /// </summary>
  41. [SerializeField]
  42. public List<Chance<T>> Weights = new List<Chance<T>>();
  43. /// <summary>
  44. /// Adds a value-weight pair to the table
  45. /// </summary>
  46. /// <param name="value">The value to add</param>
  47. /// <param name="weight">Its weight, representing the chance this value has of being picked, relative to the others in the table</param>
  48. public void Add(T value, float weight)
  49. {
  50. Weights.Add(new Chance<T>(value, weight));
  51. }
  52. /// <summary>
  53. /// Removes a value-weight pair from the table
  54. /// </summary>
  55. /// <param name="value">The value to remove</param>
  56. public void Remove(T value)
  57. {
  58. for (int i = 0; i < Weights.Count; i++)
  59. {
  60. if (Weights[i].Value.Equals(value))
  61. Weights.RemoveAt(i);
  62. }
  63. }
  64. /// <summary>
  65. /// Picks an object from the table at random, taking weights into account
  66. /// </summary>
  67. /// <param name="random">The random number generator to use</param>
  68. /// <returns>A random value</returns>
  69. public T GetRandom(RandomStream random)
  70. {
  71. float totalWeight = Weights.Select(x => x.Weight).Sum();
  72. float randomNumber = (float)(random.NextDouble() * totalWeight);
  73. foreach(var w in Weights)
  74. {
  75. if (randomNumber < w.Weight)
  76. return w.Value;
  77. randomNumber -= w.Weight;
  78. }
  79. return default(T);
  80. }
  81. /// <summary>
  82. /// Picks an object at random from a collection of tables, taking weights into account
  83. /// </summary>
  84. /// <param name="random">The random number generator to use</param>
  85. /// <param name="tables">A list of chance tables to pick from</param>
  86. /// <returns>A random value</returns>
  87. public static TVal GetCombinedRandom<TVal, TChance>(RandomStream random, params ChanceTable<TVal>[] tables)
  88. {
  89. float totalWeight = tables.SelectMany(x => x.Weights.Select(y => y.Weight)).Sum();
  90. float randomNumber = (float)(random.NextDouble() * totalWeight);
  91. foreach (var w in tables.SelectMany(x => x.Weights))
  92. {
  93. if (randomNumber < w.Weight)
  94. return w.Value;
  95. randomNumber -= w.Weight;
  96. }
  97. return default(TVal);
  98. }
  99. }
  100. }