using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace DunGen
{
#region Helper Class
///
/// A value with a weight
///
/// The type of value to use
[Serializable]
public class Chance
{
public T Value;
public float Weight;
public Chance()
:this(default(T), 1)
{
}
public Chance(T value)
:this(value, 1)
{
}
public Chance(T value, float weight)
{
Value = value;
Weight = weight;
}
}
#endregion
///
/// A table containing weighted values to be picked at random
///
/// The type of object to be picked
public class ChanceTable
{
///
/// Values and their corresponding weights, which determine how likely a value is to be picked relative to others in the table
///
[SerializeField]
public List> Weights = new List>();
///
/// Adds a value-weight pair to the table
///
/// The value to add
/// Its weight, representing the chance this value has of being picked, relative to the others in the table
public void Add(T value, float weight)
{
Weights.Add(new Chance(value, weight));
}
///
/// Removes a value-weight pair from the table
///
/// The value to remove
public void Remove(T value)
{
for (int i = 0; i < Weights.Count; i++)
{
if (Weights[i].Value.Equals(value))
Weights.RemoveAt(i);
}
}
///
/// Picks an object from the table at random, taking weights into account
///
/// The random number generator to use
/// A random value
public T GetRandom(RandomStream random)
{
float totalWeight = Weights.Select(x => x.Weight).Sum();
float randomNumber = (float)(random.NextDouble() * totalWeight);
foreach(var w in Weights)
{
if (randomNumber < w.Weight)
return w.Value;
randomNumber -= w.Weight;
}
return default(T);
}
///
/// Picks an object at random from a collection of tables, taking weights into account
///
/// The random number generator to use
/// A list of chance tables to pick from
/// A random value
public static TVal GetCombinedRandom(RandomStream random, params ChanceTable[] tables)
{
float totalWeight = tables.SelectMany(x => x.Weights.Select(y => y.Weight)).Sum();
float randomNumber = (float)(random.NextDouble() * totalWeight);
foreach (var w in tables.SelectMany(x => x.Weights))
{
if (randomNumber < w.Weight)
return w.Value;
randomNumber -= w.Weight;
}
return default(TVal);
}
}
}