Last active
September 8, 2020 16:40
-
-
Save xyberviri/3b35c4ee441c624d6cc19645940d9bdb to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
CC BY-SA 2.0 James Ray Velasquez Xyberviri/Dabnician | |
CSDPicker<String> chanceBucket = new CSDPicker<String>(); | |
chanceBucket.AddChance("Epic", 0.005); | |
chanceBucket.AddChance("Legendary", 0.02); | |
chanceBucket.AddChance("Rare", 0.125); | |
chanceBucket.AddChance("UnCommon", 0.25); | |
chanceBucket.AddChance("Common", 0.6); | |
Random random = new Random(); | |
for (int i = 0; i < 100; i++) | |
{ | |
chanceBucket.GetRandom(random.NextDouble()); | |
} | |
*/ | |
/// <summary> | |
/// Cumulative sum distribution random object picker | |
/// </summary> | |
class CSDPicker<T> | |
{ | |
private List<CsdObject<T>> pickerList = new List<CsdObject<T>>(); | |
/// <summary> | |
/// Return full list of objects. | |
/// </summary> | |
/// <returns></returns> | |
public IEnumerable<T> GetList() | |
{ | |
return pickerList.Select(x => x.GetObject()); | |
} | |
/// <summary> | |
/// return the total sum of chances. | |
/// </summary> | |
/// <returns></returns> | |
public double GetBaseChance() | |
{ | |
return pickerList.Sum(chance => chance.GetBaseChance()); | |
} | |
/// <summary> | |
/// This should return 1.0 unless something is broken. | |
/// </summary> | |
/// <returns></returns> | |
public double GetAdjustedChance() | |
{ | |
return pickerList.Sum(chance => chance.GetChance()); | |
} | |
/// <summary> | |
/// Pass in a double between 0.0 and 1.0 | |
/// </summary> | |
/// <param name="diceRoll"></param> | |
/// <returns></returns> | |
public T GetRandom(double diceRoll) | |
{ | |
double cumulative = 0.0; | |
T selectedElement = default(T); | |
for (int i = 0; i < pickerList.Count(); i++) | |
{ | |
cumulative += pickerList[i].GetChance(); | |
if (diceRoll < cumulative) | |
{ | |
selectedElement = pickerList[i].GetObject(); | |
break; | |
} | |
} | |
return selectedElement; | |
} | |
/// <summary> | |
/// Adds a new item to the picker list, allows for chaining methods. | |
/// </summary> | |
/// <param name="item">the item you want returned when this is picked using <see cref="GetRandom(double)"/></param> | |
/// <param name="chance">Ideally this should be between 0.0 and 1.0 but values over 1.0 'should' be accounted for..</param> | |
/// <returns>returns this instance of <see cref="CSDPicker{T}"/></returns> | |
public CSDPicker<T> AddChance(T item, double chance) | |
{ | |
pickerList.Add(new CsdObject<T>(item, chance)); | |
double total = pickerList.Sum(x => x.GetBaseChance()); | |
foreach (CsdObject<T> pick in pickerList) | |
{ | |
pick.RecalculateChance(total); | |
} | |
pickerList = pickerList.OrderByDescending(o => o.GetBaseChance()).ToList(); | |
return this; | |
} | |
private static int OrderByDescending(CsdObject<T> x, CsdObject<T> y) | |
{ | |
if (x == null) | |
{ | |
if (y == null) | |
{ | |
// If x is null and y is null, they're | |
// equal. | |
return 0; | |
} | |
else | |
{ | |
// If x is null and y is not null, y | |
// is greater. | |
return -1; | |
} | |
} | |
else | |
{ | |
// If x is not null... | |
// | |
if (y == null) | |
// ...and y is null, x is greater. | |
{ | |
return 1; | |
} | |
else | |
{ | |
// ...and y is not null, compare the | |
// lengths of the two strings. | |
// | |
int retval = x.GetHashCode().CompareTo(y.GetHashCode()); | |
if (retval != 0) | |
{ | |
// If the strings are not of equal length, | |
// the longer string is greater. | |
// | |
return retval; | |
} | |
else | |
{ | |
// If the strings are of equal length, | |
// sort them with ordinary string comparison. | |
// | |
return x.GetChance().CompareTo(y.GetChance()); | |
} | |
} | |
} | |
} | |
internal class CsdObject<Ti> | |
{ | |
private readonly Ti csdObject; | |
private readonly double baseChance; | |
private double adjustedChance; | |
public CsdObject(Ti csdObject, double baseChance) | |
{ | |
this.csdObject = csdObject; | |
this.baseChance = baseChance; | |
this.adjustedChance = baseChance; | |
} | |
public void RecalculateChance(double cumulativeSum) | |
{ | |
this.adjustedChance = baseChance / cumulativeSum; | |
} | |
public double GetChance() | |
{ | |
return this.adjustedChance; | |
} | |
public double GetBaseChance() | |
{ | |
return this.baseChance; | |
} | |
public Ti GetObject() | |
{ | |
return csdObject; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment