首页 > 解决方案 > C++ 计算事件的概率

问题描述

我正在尝试模拟野生口袋妖怪遭遇。如公式中所述:

The rate of Pokémon encounter is determined from a simple mathematical formula:
1 in (187.5 / ( x )) per step.

Let x equal the a value which determines how rare the Pokémon is. The higher the encounter rate, 
the more common the Pokémon is.

Encounter-rate Table
Encounter type Encounter rate
Very common     10
Common          8.5
Semi-rare       6.75
Rare            3.33
Very rare       1.25

我想在每次按下按钮后运行这个概率。我该如何模拟rand()呢?

标签: c++visual-c++randomprobabilityweighted

解决方案


我会这样做

映射 rand()

rand() / (float)RAND_MAX

Rand()返回一个从 0 到的值,RAND_MAX所以这个公式映射0 -> RAND_MAX0 -> 1

(float) 用于制作RAND_MAX浮点数,因为返回的值rand()是 anint并且int / int在 c++ 中返回 anint

(rand() / (float)RAND_MAX) * 10 

如果将结果乘以 10,它将映射rand()0 -> 10

(rand() / (float)RAND_MAX) * 187.5

这将映射rand()0 -> 187.5

187.5 分之一

我们映射了rand()from的值0 -> 187.5

现在每次我们调用rand()它都会返回一个随机数0->187.5

为了简化假设我们rand()0 -> 200

将有 1/2 的机会rand()返回小于 100 的数字,因为 0 -> 200 之间的每个数字都有相同的返回机会(例如rand()可以返回 25.67 或 100.9 或 140.6)

( (rand() / (float)RAND_MAX) * 187.5 ) < 1

根据相同的原理,返回的数字小于 1 的概率为 1:187.5

最终解决方案

我们仍然缺少 187.5 / X中的 1

要实现遇到率,您只需将映射从0 -> 187.5To

0 -> 187.5 / X

我们可以看到,如果 X 大,则意味着遭遇率高,187.5 变小,返回的数字比 1 更小,但如果遭遇率低,X 变小,187.5 变大(更低小于 1) 的机会

最终代码

srand (time(NULL)); // Init rand() with a seed
bool encountered = ( (rand() /  (float)RAND_MAX) * (187.5 / x) ) < 1

优化

一位用户指出,使用最后一个代码,您需要为每个事件计算 5 个 rand(),但如果我们稍微调整一下公式,您只能计算 1rand()

通过使用简单的数学,您知道在 10 / 2 步中发生一次 (1) 的事件是在 10 步中在 (2) 中发生两次的事件

因此,在 187.5 / X 步中发生一次 (1) 的事件在 187.5 步中发生 (1 * X)

如果我们从 0 -> 187.5 映射 rand() 那么对于每个口袋妖怪,我们可以只使用一个 rand() 计算它的唯一值

float randomNumber      = (rand() / (float)RAND_MAX) * 187.5
bool encountedPokemon1  = randomNumber < 1 * encounter_rate_first_pokemon
bool encountedPokemon2  = randomNumber < 1 * encounter_rate_second_pokemon

推荐阅读