底部重随机数

时间:2014-02-23 23:11:37

标签: java

现在,我正在尝试为小游戏制作一个Item drop table。

在这个游戏中,我希望您比其他人更常接收某些物品,其中一些物品被挑选的可能性很小。

我尝试过使用以下内容:

Random rand = new Random();
int chance = rand.nextInt(100) + 1;
if(chance > 2){
     //give common item;
}
else if(chance == 1){
     //give rare item
}

但是,当您在50多个项目的范围内执行此操作时,创建,修改变得非常繁琐,并且代码需要很长时间才能执行。

那么,是否会出现一些底部随机的随机数,会产生大量的低数字(1,2,等等)和极少数高数字(50年代,60年代等)?

3 个答案:

答案 0 :(得分:5)

使用Random.nextDouble()生成[0,1]中的数字,然后您可以使用Math.pow()为其提供非线性偏差并将其向上扩展以覆盖您的范围,例如:

 int randomBiased (int max, float bias) {
     float v = Math.pow(random.nextDouble(), bias); 
     return (int)(v * max);
 }

或者如果你喜欢单行:

 int value = (int)(100 * Math.pow(random.nextDouble(), bias));

这很有用,因为您可以调整bias来调整稀有项目的“稀有性”。 <偏差> 1将有利于较低的数字,&lt; 1将支持更高的数字,1将是统一的。

例如,randomBiased(100, 2.0)将提供与Tim B的答案相同的结果分布。


另请注意,您可以使用任何映射[0,1)到[0,1)的函数来修改偏差;例如,您可以使用立方体将所有结果偏离中心(请参阅the graph):

int randomFavorEdges (int max) {
    float v = random.nextDouble();
    v = 3*v*v - 2*v*v*v;
    return (int)(v * max);
}

另一个例子是,您可以使用Math.abs(random.nextGaussian())来获得高斯分布的一半(参见Christian的回答)。需要注意的是,你必须继续尝试,直到你得到一个小于1的数字(它可以超出范围[-1,1])。但是,您可以通过添加可以调整的缩放参数来利用大范围:

int randomGaussian (int max, float scale) { 
    double v;
    do {
        v = Math.abs(random.nextGaussian() / scale);
    } while (v >= 1.0);
    return (int)(v * max);
}

说实话,看看下面的测试结果,我个人喜欢具有更高比例值的高斯分布 - 稀有项目变得更加罕见,但没有像指数分布那样强烈地偏向普通项目。


更新:我在ideone上创建了一个项目,演示了上面列出的方法。以下是包含30个值的10000个样本的示例:

Name :  Uniform  Pow(0.5)  Pow(2.0) Pow(10.0)    G(1.0)    G(3.5)     Cubic 
0    :      337        11      1872      7118       365       946      1126 
1    :      359        33       744       511       406       939       517 
2    :      327        60       589       328       360       876       407 
3    :      330       101       458       224       370       846       307 
4    :      347       103       445       170       395       817       310 
5    :      344       131       366       141       374       727       257 
6    :      326       148       358       147       416       691       275 
7    :      326       180       309       106       373       645       254 
8    :      314       195       295       129       335       575       282 
9    :      331       227       311        79       356       506       219 
10   :      329       245       325        84       376       458       258 
11   :      340       241       230        75       370       366       228 
12   :      367       290       251        75       366       320       215 
13   :      343       294       264        70       345       243       237 
14   :      313       317       256        60       344       211       224 
15   :      346       331       240        66       358       186       210 
16   :      353       363       204        48       338       131       226 
17   :      329       373       213        55       344       157       193 
18   :      323       417       200        57       327        86       230 
19   :      323       446       219        56       354        75       208 
20   :      321       466       211        43       296        56       209 
21   :      339       496       205        40       297        34       267 
22   :      338       484       192        48       278        37       237 
23   :      335       523       168        46       290        19       306 
24   :      327       571       162        31       251        18       279 
25   :      322       573       216        49       263         7       302 
26   :      323       580       152        35       277        11       311 
27   :      333       596       209        41       268         9       354 
28   :      316       590       158        38       250         6       495 
29   :      339       615       178        30       258         2      1057 

请注意,对于Math.pow()方法,高偏差值或高斯方法的高比例值,您实际上可以使罕见物体罕见。这也显示了立方S曲线偏离中心的偏差。

答案 1 :(得分:3)

是的,基本上你需要改变概率分布。有几种方法可以做到这一点,但最简单的方法之一就是在前后使用非线性比例因子。

即。而不是

int i = random.nextInt(100);
你这样做:

int i = Math.sqrt(random.nextInt(100*100));

随机数会在范围内给出均匀分布,但是平方根会在您上升时将数字压缩在一起 - 因此更高的数字更有可能。你可以随时做100-i然后再回到更低的数字,你可以改变曲线的陡度来调整你想要的概率。

*

另一种方法(并且更容易控制)是使用随机数的组合。基本上不是从0到100做一个数字,而是从0到50做两个数字并将它们加在一起,或三个数字,或四个数字。你做的单独的卷越多,曲线就越陡峭。

这会增加朝向桌子中心的几率,0和100变得同样不太可能,50变得可能。您可以使用它并在两端放置不太可能的东西,或者您可以生成超过所需范围两倍的数字,然后如果它超出范围则翻转它。

int i = random.nextInt(100)+random.nextInt(100);
if (i > 100) {
   i = 200-i;
}

答案 2 :(得分:2)

您可以尝试使用normal distribution(或高斯分布):

Random rand = new Random();
chance = rand.nextGaussian();

注意:正如@JasonC所提到的,此方法也提供了否定数字,因此您可能希望使用Math.abs()

chance = Math.abs(rand.nextGaussian());