using System; using System.Collections.Generic; using System.Linq; using RPGCoreCommon.Helpers.Exceptions; using UnityEngine; namespace RPGCoreCommon.Helpers { /// /// This utility class basses on Unity's which uses: /// /// public static class RandomHelper { /// /// /// Alias to Unity's . /// /// public static void InitState(int seed) { UnityEngine.Random.InitState(seed); } /// /// Returns float between min (inclusive) and max (inclusive). /// public static float RandomFloat(float min = 0f, float max = 1f) { return UnityEngine.Random.value * (max-min) + min; } /// /// Returns integer between minimum (inclusive) and maximum (inclusive). /// public static int RandomInt(int minInclusive = 0, int maxInclusive = 100) { return Mathf.RoundToInt(UnityEngine.Random.value * (maxInclusive-minInclusive)) + minInclusive; } /// /// Returns random key from given list. /// public static int RandomKey(IEnumerable enumerable) { var list = enumerable.ToList(); if (!list.Any()) throw new NotEnoughElementsForRandomPickException("List need at least one element."); return RandomInt(0, list.Count - 1); } /// /// Returns random element from given list. /// public static T RandomElement(IEnumerable enumerable) { return RandomElements(enumerable, 1).First(); } /// /// Returns new list with randomized elements.
/// List needs to have at least equal or more elements that given count! If repeatable then list needs to have at least 1 element.
///
/// When given list does not have enough elements to choose from. public static List RandomElements(IEnumerable enumerable, int count, bool repeatable = true) { var list = enumerable.ToList(); var neededCount = repeatable ? 1 : list.Count; if (list.Count < neededCount) throw new NotEnoughElementsForRandomPickException($"Not enough elements in list. Need={neededCount}, Provided={list.Count}"); if (!repeatable) return list.OrderBy(_ => RandomFloat()).Take(count).ToList(); return new T[count].Select(_ => list[RandomInt(0, list.Count - 1)]).ToList(); } /// /// Returns keys from given list by its weight. /// /// When given list does not have any elements to choose from. public static int RandomKeyByWeight(IEnumerable enumerable, Func weightGetter) { var list = enumerable.ToList(); if (!list.Any()) throw new NotEnoughElementsForRandomPickException("List need at least one element."); var maxWeight = list.Sum(weightGetter.Invoke); var randomWeight = RandomFloat(0, maxWeight); for (var i = 0; i < list.Count; i++) { randomWeight -= weightGetter.Invoke(list[i]); if (randomWeight <= 0) return i; } return 0; } /// /// Returns element from given list by its weight. /// /// When given list does not have any elements to choose from. public static T RandomElementByWeight(IEnumerable enumerable, Func weightGetter) { return RandomElementsByWeight(enumerable, weightGetter, 1).First(); } /// /// Returns elements from given list by its weight. /// /// When given list does not have enough elements to choose from. public static List RandomElementsByWeight(IEnumerable enumerable, Func weightGetter, int count, bool repeatable = true) { var list = enumerable.ToList(); var listResult = new List(); var neededCount = repeatable ? 1 : list.Count; if (list.Count < neededCount) throw new NotEnoughElementsForRandomPickException($"Not enough elements in list. Need={neededCount}, Provided={list.Count}"); for (var i = 0; i < count; i++) { var randomKey = RandomKeyByWeight(list, weightGetter); listResult.Add(list[randomKey]); if (!repeatable) list.RemoveAt(randomKey); } return listResult; } /// /// Percentage chance by given float. Simply checks if random float is smaller than given one. /// /// Chance to get true. 0.0f = 0%, 1.0f = 100% public static bool Chance(float chance) { return RandomFloat() < Mathf.Clamp01(chance); } } }