现在,我正在尝试为小游戏制作一个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年代等)?
答案 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());