Вероятность события, используя проценты
Допустим у меня есть кнопка и 5 событий.
Мне нужно сделать, чтобы при нажатии на кнопку появлялось одно из событий с определенным шансом: обычное 70%, редкое 20%, эпическое 10%, легендарное 1% и мистическое 0.05%
Как это реализовать? И куда закидывать скрипт
Ответы (1 шт):
Автор решения: Alex Rudenko
→ Ссылка
- Создаём enum, в котором прописываем названия событий и их допустимые вероятности
public enum ProbableEvent {
REGULAR(70),
RARE(20),
EPIC(10),
LEGENDARY(1),
MYSTICAL(0.05);
private final double probability;
private ProbableEvent(double percent) {
this.probability = percent;
}
public double getProbability() {
return this.probability;
}
}
- Также пишем статический метод для расчёта суммарной вероятности, чтобы можно было корректно рассчитать частоту генерации событий, кэшируем расчёт суммы.
private static double total = -1;
private static double total() {
if (total < 0) {
total = Arrays.stream(ProbableEvent.values())
.mapToDouble(ProbableEvent::getProbability)
.sum();
}
return total;
}
- Пишем статический метод, возвращающий рандомное событие с заданной приведенной вероятностью (например 70% / 1.01005 = 69.3035%, и т.д.)
private static final Random RANDOM = ThreadLocalRandom.current();
public static ProbableEvent getRandom() {
int range = (int)(total() * 100);
double x = RANDOM.nextInt(range) / 100.0;
double limit = 0.0;
for (ProbableEvent pe : ProbableEvent.values()) {
limit += pe.probability;
if (x < limit) {
return pe;
}
}
return ProbableEvent.MYSTICAL;
}
Тест: вызываем метод ProbableEvent::getRandom 100_000 раз, строим и выводим карту частот:
int runs = 100_000;
Map<ProbableEvent, Integer> freq = Stream
.generate(ProbableEvent::getRandom)
.limit(runs)
.collect(Collectors.groupingBy(
x -> x,
Collectors.summingInt(x -> 1)
));
freq.entrySet()
.stream()
.sorted(Map.Entry.<ProbableEvent, Integer>comparingByValue().reversed())
.forEach(e -> System.out.printf("%-10s count = %6d %% = %6.3f%n",
e.getKey().name(), e.getValue(), 100.0 * e.getValue() / runs
));
Вывод:
REGULAR count = 69082 % = 69.082
RARE count = 19829 % = 19.829
EPIC count = 10053 % = 10.053
LEGENDARY count = 994 % = 0.994
MYSTICAL count = 42 % = 0.042