├── WeightAlgorithm.cs ├── AbstractRandomProvider.cs ├── WeightAlgorithm.cs.meta ├── WeightedRandom.cs.meta ├── SystemRandomProvider.cs.meta ├── AbstractRandomProvider.cs.meta ├── UnityEngineRandomProvider.cs.meta ├── UnityMathematicsRandomProvider.cs.meta ├── UnityEngineRandomProvider.cs ├── UnityMathematicsRandomProvider.cs ├── SystemRandomProvider.cs ├── README.md └── WeightedRandom.cs /WeightAlgorithm.cs: -------------------------------------------------------------------------------- 1 | namespace Subtegral.WeightedRandom 2 | { 3 | public enum WeightAlgorithm 4 | { 5 | FairBiased, 6 | UnfairBiased 7 | } 8 | } -------------------------------------------------------------------------------- /AbstractRandomProvider.cs: -------------------------------------------------------------------------------- 1 | namespace Subtegral.WeightedRandom 2 | { 3 | public abstract class AbstractRandomProvider 4 | { 5 | protected AbstractRandomProvider() { Construct(); } 6 | public abstract void Construct(); 7 | public abstract double GetRandom(); 8 | 9 | } 10 | } -------------------------------------------------------------------------------- /WeightAlgorithm.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6f0ac854e4231e24cb30f361a18358b8 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /WeightedRandom.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4550d6e9c58edfc4a9343516bf2dceac 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /SystemRandomProvider.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: cde3ede59bcac2e47bf9315e9ee180f6 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /AbstractRandomProvider.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2b7563a6173be0943abfcc7b96d66e04 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /UnityEngineRandomProvider.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a7949e73aa06b844bb6aac516195d17a 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /UnityMathematicsRandomProvider.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b317a5fa185a95a47aff8d76bc48f6c7 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /UnityEngineRandomProvider.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | namespace Subtegral.WeightedRandom 5 | { 6 | public class UnityEngineRandomProvider : AbstractRandomProvider 7 | { 8 | public override void Construct() { } 9 | 10 | public override double GetRandom() 11 | { 12 | return Random.Range(0f, 1f); 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /UnityMathematicsRandomProvider.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using Unity.Mathematics; 4 | namespace Subtegral.WeightedRandom 5 | { 6 | /// 7 | /// Uses SIMD Instructions to calculate 8 | /// 9 | public class UnityMathematicsRandomProvider : AbstractRandomProvider 10 | { 11 | private Random randomCache; 12 | public override void Construct() 13 | { 14 | randomCache = new Random(); 15 | } 16 | 17 | public override double GetRandom() 18 | { 19 | return randomCache.NextDouble(); 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /SystemRandomProvider.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using System; 4 | 5 | namespace Subtegral.WeightedRandom 6 | { 7 | public class SystemRandomProvider : AbstractRandomProvider 8 | { 9 | private Random randomCache; 10 | public override void Construct() 11 | { 12 | randomCache = new Random(); 13 | } 14 | 15 | public override double GetRandom() 16 | { 17 | return randomCache.NextDouble(); 18 | } 19 | 20 | public static SystemRandomProvider GetInstance() 21 | { 22 | return new SystemRandomProvider(); 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Weighted Randomizer for Unity 2 | Allows you to get generic biased random selections depending on provided weight. 3 | 4 | **Best part of this randomizer is, it doesn't require to provide 100% total. 5 | It auto-calculates weights regarding to your weights.** 6 | 7 | So you can pass _Add->80%-Tremors _Add->70%-Zombies_ in the same total. 8 | 9 | ## Usage 10 | Simple example: 11 | ```c# 12 | WeightedRandom rnd = new WeightedRandom(); 13 | rnd.Add(new Ghost(),0.5f); 14 | rnd.Add(new Zombie(),0.3f); 15 | 16 | rnd.Next(); //This will return a biased random result. 17 | ``` 18 | 19 | ## Alternative parameters 20 | WeightedRandom uses _System.Random_ and _FairBiased_ algorithm *by default.* 21 | 22 | **You can choose custom options on the constructor.** 23 | 24 | ### WeightAlgorithm 25 | There are two algorithms right now. 26 | - *UnfairBiased:* Provides a larger probability scale but results can be less predictable. 27 | - *FairBiased:* Provides a steady bias and therefor more predictable results. 28 | 29 | ### Weight Providers 30 | Weight providers are basically random api's which have provided by Unity and C#(System) libraries. 31 | - *SystemRandomProvider:* Uses System.Random implementation 32 | - *UnityEngineRandomProvider:* Uses UnityEngine.Random.Range implementation 33 | - *UnityMathematicsRandomProvider:* Uses Unity's new SIMD math library with Unity.Random implementation 34 | 35 | ## TO-DO 36 | - AddRange for multiple queries at once. 37 | - GetInstance() implementation on other providers with _T where:class_ 38 | -------------------------------------------------------------------------------- /WeightedRandom.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using System; 4 | namespace Subtegral.WeightedRandom 5 | { 6 | public sealed class WeightedRandom 7 | { 8 | private Dictionary probabiltyTable = new Dictionary(); 9 | private List> sortedPair; 10 | private WeightAlgorithm algorithm; 11 | private AbstractRandomProvider randomProvider; 12 | 13 | #region Constructors 14 | public WeightedRandom() : this(new SystemRandomProvider(), WeightAlgorithm.FairBiased) { } 15 | public WeightedRandom(WeightAlgorithm algorithm) 16 | { 17 | randomProvider = new SystemRandomProvider(); 18 | this.algorithm = algorithm; 19 | } 20 | public WeightedRandom(AbstractRandomProvider provider) : this(WeightAlgorithm.FairBiased) 21 | { 22 | randomProvider = provider ?? throw new Exception("Random provider is not instantiated."); 23 | } 24 | public WeightedRandom(AbstractRandomProvider provider, WeightAlgorithm algorithm) 25 | { 26 | randomProvider = provider ?? throw new Exception("Random provider is not instantiated."); 27 | this.algorithm = algorithm; 28 | } 29 | #endregion 30 | 31 | public void Add(T val, float probability) 32 | { 33 | probabiltyTable.Add(val, probability); 34 | sortedPair = probabiltyTable.OrderBy(i => i.Value).ToList(); 35 | } 36 | 37 | public T Next() 38 | { 39 | if (sortedPair == null || sortedPair.Count == 0) 40 | throw new Exception("No elements added to probability calculation!"); 41 | 42 | float totalProbability = sortedPair.Sum(x => x.Value); 43 | double randomValue = randomProvider.GetRandom() * totalProbability; 44 | for (var i = 0; i < sortedPair.Count; i++) 45 | { 46 | //TO-DO:Implement an algorithm factory and decouple it from here. 47 | if (algorithm == WeightAlgorithm.FairBiased) 48 | { 49 | 50 | randomValue -= sortedPair[i].Value; 51 | if (randomValue <= 0) 52 | return sortedPair[i].Key; 53 | } 54 | else 55 | { 56 | if (randomValue < sortedPair[i].Value) 57 | return sortedPair[i].Key; 58 | 59 | randomValue -= sortedPair[i].Value; 60 | } 61 | 62 | } 63 | return default; //Replace with random pick; 64 | } 65 | 66 | } 67 | } 68 | --------------------------------------------------------------------------------