Skip to content

Instantly share code, notes, and snippets.

@Lachee
Last active January 30, 2019 05:37
Show Gist options
  • Save Lachee/6f1cc8885fb6e1001addb7adb055d065 to your computer and use it in GitHub Desktop.
Save Lachee/6f1cc8885fb6e1001addb7adb055d065 to your computer and use it in GitHub Desktop.
Randomised List
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace Lachee.Collections
{
/// <summary>
/// A randomised list. It will store a collection of values with specified weights and provide functionallity to select randomly from the list.
/// </summary>
/// <typeparam name="T">Type to store as the value.</typeparam>
public class Rist<T> : IEnumerable<WeightValuePair<T>>
{
private List<WeightValuePair<T>> _list;
private float _weight = 0;
/// <summary>
/// Number of elements currently in the table
/// </summary>
public int Count { get { return _list.Count; } }
/// <summary>
/// The total tally of the weights. Use RecalculateWeights(); to update this value.
/// </summary>
public float Weight { get { return _weight; } }
public Rist() { _list = new List<WeightValuePair<T>>(); }
public Rist(int capacity) { _list = new List<WeightValuePair<T>>(capacity); }
public Rist(List<WeightValuePair<T>> vwp)
{
_list = vwp;
foreach (var wp in vwp) _weight += wp.Weight;
}
/// <summary>
/// Clears the random table.
/// </summary>
public void Clear()
{
_list.Clear();
_weight = 0;
}
/// <summary>
/// Adds a new item with a specified weight to the table and increments the total weight.
/// </summary>
/// <param name="item">Item to add</param>
/// <param name="weight">WEight this item has</param>
public void Add(T item, float weight)
{
Add(new WeightValuePair<T>() { Value = item, Weight = weight });
}
/// <summary>
/// Adds a new value weight pair to the table and increments the total weight.
/// </summary>
/// <param name="pair">The item to be added</param>
public void Add(WeightValuePair<T> pair)
{
//We don't want to add anything that has no chance at all.
//if (pair.Weight <= 0) return;
_list.Add(pair);
_weight += pair.Weight;
}
/// <summary>
/// Attempts to pick a random element from the table based of weighting.
/// </summary>
/// <param name="random">A random value between 0 and 1. This is done so System.Random or Unity.Random can be used.</param>
/// <param name="result">The random element that was fetched.</param>
/// <returns>false if we are unable to find a random element.</returns>
public bool Randomise(float random, out WeightValuePair<T> result)
{
float rand = random * Weight;
for (int i = 0; i < _list.Count; i++)
{
rand -= _list[i].Weight;
if (rand < 0)
{
result = _list[i];
return true;
}
}
result = default(WeightValuePair<T>);
return false;
}
/// <summary>
/// Attempts to pick a random element from the table based of weighting.
/// </summary>
/// <param name="random">A random value between 0 and 1. This is done so System.Random or Unity.Random can be used.</param>
/// <param name="item">The random element that was fetched.</param>
/// <returns>false if we are unable to find a random element.</returns>
public bool Randomise(float random, out T item)
{
WeightValuePair<T> result;
if (!Randomise(random, out result))
{
item = default(T);
return false;
}
item = result.Value;
return true;
}
/// <summary>
/// Recalculates the total weights
/// </summary>
public void RecalculateWeights()
{
_weight = 0;
for (int i = 0; i < _list.Count; i++)
_weight += _list[i].Weight;
}
public IEnumerator<WeightValuePair<T>> GetEnumerator()
{
return _list.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return (IEnumerator)GetEnumerator();
}
}
public struct WeightValuePair<T>
{
public T Value { get; set; }
public float Weight { get; set; }
public WeightValuePair(T value, float weight)
{
Value = value;
Weight = weight;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment