抽選したいクラスに interface を継承させて LotteryUtil.Lot
を呼び出せば抽選してくれる
private class Food : LotteryUtil.IWeight { public string Name; public int Weight; public int GetWeight() => Weight; }
コード
using System; using System.Collections.Generic; using System.Linq; using UnityEngine; public static class LotteryUtil { public static T Lot<T>(IList<T> weightTable) where T : IWeight { if (weightTable == null || weightTable.Count < 1) throw new Exception("Table is empty"); if (weightTable.Count == 1) return weightTable[0]; var totalWeight = weightTable.Sum(t => t.GetWeight()); var value = Random.Range(1, totalWeight + 1); var index = 0; for (var i = 0; i < weightTable.Count; ++i) { if (weightTable[i].GetWeight() == 0) continue; if (weightTable[i].GetWeight() >= value) { return weightTable[i]; } value -= weightTable[i].GetWeight(); } throw new Exception("Invalid Calc"); } public interface IWeight { int GetWeight(); } }
動作検証
10000回ほどループさせて重みがあってるのか検証
近しい割合になってるっぽいので多分大丈夫
using System.Collections.Generic; public class SampleMonoBehaviour : MonoBehaviour { private class Food : LotteryUtil.IWeight { public string Name; public int Weight; public int GetWeight() => Weight; } private void Awake() { var dic = new Dictionary<string, int>(); var foods = new [] { new Food { Name = "Apple", Weight = 50, }, new Food { Name = "Orange", Weight = 25, }, new Food { Name = "Banana", Weight = 15, }, new Food { Name = "Strawberry", Weight = 10, } }; for (var i = 0; i < 10000; i++) { var result = LotteryUtil.Lot(foods); if (!dic.ContainsKey(result.Name)) dic.Add(result.Name, 0); dic[result.Name]++; } foreach (var pair in dic) Debug.Log($"{pair.Key}:{pair.Value}"); } }