private WeightedItem <T> ChooseRandomWeightedItem() { int lookupWeight = random.Next(1, totalWeight); int currentWeight = 0; WeightedItem <T> item = null; foreach (WeightedItem <T> weightedItem in pool) { currentWeight += weightedItem.Weight; if (currentWeight >= lookupWeight) { item = weightedItem; break; } } if (item == null) { throw new InvalidOperationException("The random lookup was greater than the total weight"); } return(item); }
private void Remove(WeightedItem <T> item) { if (item != null && pool.Remove(item)) { totalWeight -= item.Weight; } }
/// <summary> /// Take an item at random from the pool, keeping weights into consideration. /// The item will be removed from the pool. /// </summary> /// <returns>An item of type T from the WeightedPool</returns> /// <exception cref="InvalidOperationException">Thrown when the pool is empty</exception> /// <exception cref="InvalidOperationException">Thrown when the random lookup is greater than the total weight. Could only happen if a bad implementation of IRandom were provided</exception> public T Draw() { if (Count <= 0 || totalWeight <= 0) { throw new InvalidOperationException("Add items to the pool before attempting to draw one"); } WeightedItem <T> item = ChooseRandomWeightedItem(); Remove(item); return(item.Item); }
/// <summary> /// Choose an item at random from the pool, keeping weights into consideration. /// The item itself will remain in the pool and a clone of the item selected will be returned. /// </summary> /// <returns>A clone of the item of type T from the WeightedPool</returns> /// <exception cref="InvalidOperationException">Thrown when a clone function was not defined when the pool was constructed</exception> /// <exception cref="InvalidOperationException">Thrown when the pool is empty</exception> /// <exception cref="InvalidOperationException">Thrown when the random lookup is greater than the total weight. Could only happen if a bad implementation of IRandom were provided</exception> public T Choose() { if (cloneFunc == null) { throw new InvalidOperationException("A clone function was not defined when this pool was constructed"); } if (Count <= 0 || totalWeight <= 0) { throw new InvalidOperationException("Add items to the pool before attempting to choose one"); } WeightedItem <T> item = ChooseRandomWeightedItem(); return(cloneFunc(item.Item)); }
/// <summary> /// Add an item of type T to the WeightedPool with the given weight /// </summary> /// <param name="item">The item to add to the WeightedPool</param> /// <param name="weight"> /// The chance that the item will be picked at random from the pool when weighted against all other items. /// Higher weights mean it is more likely to be picked. /// </param> /// <exception cref="ArgumentNullException">Thrown when provided "item" argument is null</exception> /// <exception cref="ArgumentException">Thrown when provided "weight" argument is not greater than 0</exception> /// <exception cref="OverflowException">Thrown when adding the weight of the new item to the pool exceeds Int32.MaxValue</exception> public void Add(T item, int weight) { if (item == null) { throw new ArgumentNullException(nameof(item), "Can not add null item to the pool"); } if (weight <= 0) { throw new ArgumentException("Weight must be greater than 0", nameof(weight)); } WeightedItem <T> weightedItem = new WeightedItem <T>(item, weight); pool.Add(weightedItem); if (int.MaxValue - weight < totalWeight) { throw new OverflowException("The weight of items in the pool would be over Int32.MaxValue"); } totalWeight += weight; }