2020-05-18 21:11:59 +02:00
|
|
|
package net.minestom.server.utils;
|
|
|
|
|
2020-08-03 10:35:46 +02:00
|
|
|
import it.unimi.dsi.fastutil.doubles.DoubleArrayList;
|
|
|
|
import it.unimi.dsi.fastutil.doubles.DoubleList;
|
|
|
|
|
2020-05-18 21:11:59 +02:00
|
|
|
import java.util.ArrayList;
|
|
|
|
import java.util.Collection;
|
|
|
|
import java.util.List;
|
|
|
|
import java.util.Random;
|
|
|
|
|
|
|
|
/**
|
2020-10-31 05:09:30 +01:00
|
|
|
* Produces a random element from a given set, with weights applied.
|
2020-08-03 10:35:46 +02:00
|
|
|
*
|
2020-05-18 21:11:59 +02:00
|
|
|
* @param <E>
|
|
|
|
*/
|
|
|
|
public class WeightedRandom<E extends WeightedRandomItem> {
|
|
|
|
|
|
|
|
private final List<E> entries;
|
2020-08-03 10:35:46 +02:00
|
|
|
private final DoubleList weightSums;
|
2020-05-18 21:11:59 +02:00
|
|
|
private final double totalWeight;
|
|
|
|
|
|
|
|
public WeightedRandom(Collection<E> items) {
|
2020-08-03 10:35:46 +02:00
|
|
|
if (items.isEmpty())
|
2020-05-18 21:11:59 +02:00
|
|
|
throw new IllegalArgumentException("items must not be empty");
|
|
|
|
this.entries = new ArrayList<>(items);
|
2020-08-03 10:35:46 +02:00
|
|
|
this.weightSums = new DoubleArrayList(items.size());
|
2020-05-18 21:11:59 +02:00
|
|
|
double sum = 0.0;
|
2020-08-03 10:35:46 +02:00
|
|
|
for (E item : items) {
|
2020-05-18 21:11:59 +02:00
|
|
|
sum += item.getWeight();
|
|
|
|
weightSums.add(sum);
|
|
|
|
}
|
|
|
|
this.totalWeight = sum;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-10-31 05:09:30 +01:00
|
|
|
* Gets a random element from this set.
|
2020-08-03 10:35:46 +02:00
|
|
|
*
|
2020-05-18 21:11:59 +02:00
|
|
|
* @param rng Random Number Generator to generate random numbers with
|
2020-08-07 09:14:50 +02:00
|
|
|
* @return a random element from this set
|
2020-05-18 21:11:59 +02:00
|
|
|
*/
|
|
|
|
public E get(Random rng) {
|
2020-08-03 10:35:46 +02:00
|
|
|
final double p = rng.nextDouble() * totalWeight;
|
2020-05-18 21:11:59 +02:00
|
|
|
for (int i = 0; i < entries.size(); i++) {
|
2020-08-19 01:24:51 +02:00
|
|
|
final double weightSum = weightSums.getDouble(i);
|
2020-08-03 10:35:46 +02:00
|
|
|
if (weightSum >= p) {
|
2020-05-18 21:11:59 +02:00
|
|
|
return entries.get(i);
|
|
|
|
}
|
|
|
|
}
|
2020-08-03 10:35:46 +02:00
|
|
|
return entries.get(entries.size() - 1);
|
2020-05-18 21:11:59 +02:00
|
|
|
}
|
|
|
|
}
|