Krythic

Roulette System

Oct 20th, 2021
836
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using VoidwalkerEngine.Framework.DataTypes;
  5. using VoidwalkerEngine.Framework.Utilities;
  6.  
  7. namespace VoidwalkerEngine.Framework.Collections
  8. {
  9.     public class Roulette<T>
  10.     {
  11.         private Dictionary<T, Probability> _items;
  12.         private List<KeyValuePair<T, Probability>> _sortedItems;
  13.         private VoidwalkerRandom _random;
  14.         private bool _isRebuildNeeded;
  15.         public double TotalFitness { get; private set; }
  16.  
  17.         public int Count
  18.         {
  19.             get
  20.             {
  21.                 return _items.Count;
  22.             }
  23.         }
  24.  
  25.         public Roulette()
  26.         {
  27.             _random = new VoidwalkerRandom();
  28.             _items = new Dictionary<T, Probability>();
  29.         }
  30.  
  31.         public void Add(T item, int numerator, int denominator)
  32.         {
  33.             Add(item, new Probability(numerator, denominator));
  34.         }
  35.  
  36.         public void Add(T item, Probability probability)
  37.         {
  38.             if (this._items.ContainsKey(item))
  39.             {
  40.                 throw new Exception("Roulette Item already exists!");
  41.             }
  42.             this._items.Add(item, probability);
  43.             this._isRebuildNeeded = true;
  44.         }
  45.  
  46.         public bool IsEmpty
  47.         {
  48.             get
  49.             {
  50.                 return this._items.Count == 0;
  51.             }
  52.         }
  53.  
  54.         public void Clear()
  55.         {
  56.             this._items.Clear();
  57.             _isRebuildNeeded = true;
  58.         }
  59.  
  60.         public void Remove(T obj)
  61.         {
  62.             if (this._items.ContainsKey(obj))
  63.             {
  64.                 this._items.Remove(obj);
  65.                 _isRebuildNeeded = true;
  66.             }
  67.         }
  68.  
  69.         public T Next()
  70.         {
  71.             if (this._items.Count == 0)
  72.             {
  73.                 throw new Exception("Roulette items cannot be null or empty!");
  74.             }
  75.             if (_isRebuildNeeded || this._sortedItems == null)
  76.             {
  77.                 this.TotalFitness = 0;
  78.                 _sortedItems = new List<KeyValuePair<T, Probability>>();
  79.                 foreach (KeyValuePair<T, Probability> item in this._items)
  80.                 {
  81.                     _sortedItems.Add(item);
  82.                     TotalFitness += item.Value.ToPercentage();
  83.                 }
  84.                 _sortedItems.OrderBy(obj => obj.Value.ToPercentage() / this.TotalFitness).Reverse().ToList();
  85.                 _isRebuildNeeded = false;
  86.             }
  87.             double sample = _random.NextDouble();
  88.             foreach (KeyValuePair<T, Probability> candidate in this._sortedItems)
  89.             {
  90.                 double candidateSpawnChance = candidate.Value.ToPercentage();
  91.                 double fitness = candidateSpawnChance / this.TotalFitness;
  92.                 if (sample < fitness)
  93.                 {
  94.                     return candidate.Key;
  95.                 }
  96.                 sample -= fitness;
  97.             }
  98.             throw new Exception("This shouldn't be happening...");
  99.         }
  100.  
  101.         public T[] Next(int count)
  102.         {
  103.             T[] results = new T[count];
  104.             for (int i = 0; i < count; i++)
  105.             {
  106.                 results[i] = Next();
  107.             }
  108.             return results;
  109.         }
  110.     }
  111. }
  112.  
RAW Paste Data