浏览 248 次
|
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
|---|---|
| 作者 | 正文 |
|
时间:2008-05-17 关键字: 概率 几率 随机
众所周知计算机世界里没有绝对的随机函数 所谓的随机都是由特定方法计算的来的 也就是有规律的 那计算一组概率呢?
最近在做游戏的开发 遇到很多随机掉落的问题 一个npc身上掉落装备有很多件 每件的掉落都是有概率的 以便控制游戏的平衡 怎么样才能相对公平呢? 我想到了3种方案 和大家分享一下吧 也希望大家能给我一些更好的思路 getPersent1 这个是最基本的概率处理方法 百分之的几率 要么ture要么false 处理单一事件概率的都这么写 getPersent2 思路 处理一组事件的几率 根据不同事件设定的百分率返回 重要思路是递归 在所有给定的几率中伪随机得到一个 计算这个几率是否返回ture 如果true就认定这个概率得到一次 false则进行递归调用指导返回ture为止 优点: 几率相对平静的时候效率好 在调用频繁的时候效率好 执行伪随机调用测试少 缺点: 在极端情况下可能出现无法返回的情况例如1,1,1,1,1....这样的几率求解 getPersent3 思路 我引入了随机池的概念 按照给定的几率 随机设定100个数组成的随机数组 之后通过一个0-99的伪随机数得到返回 优点: 相对公平 非频繁调用效率好 缺点: 无法处理超过100个事件的几率问题 伪随机调用相对较多
import java.util.Arrays;
/**
* 本类主要包括3个静态方法,通过调用可以得到一个设定百分率产生的随即结果。
*
* @author 赵麟
* @version 1.0, 2008/04/26
*/
public class TestMain
{
private static int[] array = new int[100];
private static long count1 = 0;
private static long count2 = 0;
private static long count3 = 0;
public static void main(String[] args)
{
int loop = 1;
int[] persents = {20,10,30,40};
int[] result2 = new int[persents.length];
int[] result3 = new int[persents.length];
long beginTime = System.nanoTime();
// getPersent1 测试
System.out.println("getPersent1 测试开始 : ");
int trueNum=0,falseNum=0;
for (int i=0;i<loop;i++)
{
if (getPersent1(persents[0]))
{
trueNum++;
}
else
{
falseNum++;
}
}
System.out.println(persents[0]+"% -> "+trueNum+" , "+1.0d*trueNum/loop*100+"%\n"+(100-persents[0])+"% -> "+falseNum+" , "+1.0d*falseNum/loop*100+"%");
System.out.println("getPersent1执行"+loop+" 随机调用 : "+count1+" , 用时 : "+(System.nanoTime()-beginTime)/1000000.0d+"ms");
// 最差效率极限测试
// persents = new int[loop];
// result2 = new int[persents.length];
// result3 = new int[persents.length];
// for (int i=0;i<persents.length;i++)
// {
// persents[i] = 1;
// }
// getPersent2 测试
System.out.println("\ngetPersent2 测试开始 : ");
for (int i=0;i<loop;i++)
{
result2[getPersent2(persents)]++;
}
for (int i=0;i<result2.length;i++)
{
System.out.println(persents[i]+"% -> "+result2[i]+" , "+1.0d*result2[i]/loop*100+"%");
}
System.out.println("getPersent2执行"+loop+" 随机调用 : "+count2+" , 用时 : "+(System.nanoTime()-beginTime)/1000000.0d+"ms");
// getPersent3 测试
System.out.println("\ngetPersent3 测试开始");
for (int i=0;i<loop;i++)
{
result3[getPersent3(persents)]++;
}
for (int i=0;i<result3.length;i++)
{
System.out.println(persents[i]+"% -> "+result3[i]+" , "+1.0d*result3[i]/loop*100+"%");
}
System.out.println("getPersent3执行"+loop+" 随机调用 : "+count3+" , 用时 : "+(System.nanoTime()-beginTime)/10000000.0d+"ms");
}
/**
* 单百分率随机抽取计算处理
* @author CoolinZ
*
* @param int per 要计算的百分比
* @return bolean 选中返回ture,否则返回false
*/
private static boolean getPersent1(int per)
{
// 特殊情况判断
if (per==100)
{
return true;
}
else
{
if (per!=0)
{
// 纪录随机函数调用次数 效率检验用
count1++;
count2++;
count3++;
// 产生1至100之间的一个伪随机数整数
int random = (int)((Math.min(Math.random() + 0.01d,1.0d)) * 100);
return random<=per;
}
}
return false;
}
private static int getPersent2(int[] per) throws NumberFormatException
{
if (per==null)
{
throw new NullPointerException("参数为空。");
}
else
{
if (per.length==1)
{
throw new NumberFormatException("参数太少。");
//return getPersent1(per[0]);
}
else
{
// 纪录随机函数调用次数
count2 += 2;
int random = (int)((Math.random() + 1.0d) * per.length) % per.length;
return getPersent1(per[random])?random:getPersent2(per);
}
}
}
/**
* 通过创建随机池的方式 按照设定的多组百分率,随机抽取计算
* @author CoolinZ
*
* @param int[] per2 设定的百分比的数组
* @return 被选中的百分率在参数数组对应的下标数
* @throws NumberFormatException 参数蹿地个时不正确
*/
private static int getPersent3(int[] per2) throws NumberFormatException
{
// 参数null检测
if (per2==null)
{
throw new NullPointerException("参数为空");
}
else
{
int[] per = initArray(per2);
int random = 0;
for (int i=0;i<array.length;i++)
{
count3++;
random = (int)((Math.random() + 1.0d) * per.length) % per.length;
if (per[random]>0)
{
array[i] = random;
per[random]--;
}
else
{
for (int j=0;j<per.length;j++)
{
if (j!=random&&per[j]>0)
{
array[i] = j;
per[j]--;
break;
}
}
}
}
count3++;
return array[(int)((Math.random() + 1.0d) * array.length) % array.length];
}
}
/**
* 通过几率参数得到随机池
* @author CoolinZ
*
* @param int[] arr2 几率数组
* @return int[] 按照参数几率得到的含有100个数字的随机池数组
*/
private static int[] initArray(int[] arr2)
{
int[] arr = new int[arr2.length];
for(int i=0;i<arr.length;i++)
{
arr[i] = arr2[i];
}
// 初始化数组
Arrays.fill(array,-1);
int sum = 0;
for (int i : arr)
{
sum += i;
}
if (sum!=array.length&&sum!=0)
{
for (int i=0;i<arr.length;i++)
{
arr[i] = (int)(1.0d*arr[i]/sum*100);
}
sum = 0;
for (int i : arr)
{
sum += i;
}
if (sum!=array.length)
{
count3++;
int random = (int)((Math.random() + 1.0d) * arr.length) % arr.length;
arr[random] += array.length - sum;
if (arr[random]<0) arr[random]=0;
if (arr[random]>100) arr[random]=100;
}
}
return arr;
}
}
我分别测试了10,100,1000,10000,100000几种情况下的效率 结果如下 getPersent1 测试开始 : 20% -> 0 , 0.0% 80% -> 1 , 100.0% getPersent1执行1 随机调用 : 1 , 用时 : 1.370065ms getPersent2 测试开始 : 20% -> 0 , 0.0% 10% -> 0 , 0.0% 30% -> 0 , 0.0% 40% -> 1 , 100.0% getPersent2执行1 随机调用 : 4 , 用时 : 1.664772ms getPersent3 测试开始 20% -> 0 , 0.0% 10% -> 0 , 0.0% 30% -> 0 , 0.0% 40% -> 1 , 100.0% getPersent3执行1 随机调用 : 103 , 用时 : 0.2041043ms +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ getPersent1 测试开始 : 20% -> 2 , 20.0% 80% -> 8 , 80.0% getPersent1执行10 随机调用 : 10 , 用时 : 1.802515ms getPersent2 测试开始 : 20% -> 1 , 10.0% 10% -> 0 , 0.0% 30% -> 6 , 60.0% 40% -> 3 , 30.0% getPersent2执行10 随机调用 : 139 , 用时 : 2.30035ms getPersent3 测试开始 20% -> 1 , 10.0% 10% -> 0 , 0.0% 30% -> 4 , 40.0% 40% -> 5 , 50.0% getPersent3执行10 随机调用 : 1063 , 用时 : 0.3901289ms +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ getPersent1 测试开始 : 20% -> 28 , 28.000000000000004% 80% -> 72 , 72.0% getPersent1执行100 随机调用 : 100 , 用时 : 3.083059ms getPersent2 测试开始 : 20% -> 14 , 14.000000000000002% 10% -> 10 , 10.0% 30% -> 45 , 45.0% 40% -> 31 , 31.0% getPersent2执行100 随机调用 : 1252 , 用时 : 4.408793ms getPersent3 测试开始 20% -> 18 , 18.0% 10% -> 13 , 13.0% 30% -> 27 , 27.0% 40% -> 42 , 42.0% getPersent3执行100 随机调用 : 10584 , 用时 : 0.7471563ms +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ getPersent1 测试开始 : 20% -> 173 , 17.299999999999997% 80% -> 827 , 82.69999999999999% getPersent1执行1000 随机调用 : 1000 , 用时 : 2.504266ms getPersent2 测试开始 : 20% -> 204 , 20.4% 10% -> 86 , 8.6% 30% -> 287 , 28.7% 40% -> 423 , 42.3% getPersent2执行1000 随机调用 : 12796 , 用时 : 4.343045ms getPersent3 测试开始 20% -> 209 , 20.9% 10% -> 107 , 10.7% 30% -> 305 , 30.5% 40% -> 379 , 37.9% getPersent3执行1000 随机调用 : 105932 , 用时 : 1.4981965ms +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ getPersent1 测试开始 : 20% -> 2092 , 20.919999999999998% 80% -> 7908 , 79.08% getPersent1执行10000 随机调用 : 10000 , 用时 : 4.122348ms getPersent2 测试开始 : 20% -> 2006 , 20.06% 10% -> 1011 , 10.11% 30% -> 2896 , 28.96% 40% -> 4087 , 40.87% getPersent2执行10000 随机调用 : 128380 , 用时 : 11.95996ms getPersent3 测试开始 20% -> 2001 , 20.01% 10% -> 1036 , 10.36% 30% -> 2956 , 29.56% 40% -> 4007 , 40.07% getPersent3执行10000 随机调用 : 1059460 , 用时 : 11.7831945ms +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ getPersent1 测试开始 : 20% -> 20135 , 20.135% 80% -> 79865 , 79.865% getPersent1执行100000 随机调用 : 100000 , 用时 : 16.952833ms getPersent2 测试开始 : 20% -> 20138 , 20.138% 10% -> 9913 , 9.913% 30% -> 30030 , 30.03% 40% -> 39919 , 39.919% getPersent2执行100000 随机调用 : 1294279 , 用时 : 100.3098ms getPersent3 测试开始 20% -> 20094 , 20.094% 10% -> 10047 , 10.047% 30% -> 29960 , 29.959999999999997% 40% -> 39899 , 39.899% getPersent3执行100000 随机调用 : 10598093 , 用时 : 104.0197551ms 声明:JavaEye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
|
|
| 返回顶楼 | |
|
时间:2008-05-20
呵呵,我最近也在做游戏,正确也写了个哈哈哈哈,握手握手
int n1 = 0; int n2 = 0; public Random(int n1,int n2) { this.n1 = n1; this.n2 = n2; } public boolean getcaprandon() { if(getRandom(1,n1)<=n2) return true; else return false; } public static int getRandom(int min,int max) { return (int)((max+1-min)*Math.random()+min); } |
|
| 返回顶楼 | |
|
时间:2008-05-20
之前提交好像把getpersent1给弄丢了 加上它应该就完整了
|
|
| 返回顶楼 | |



