有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

三角数组中随机数偏置的数学方法

这个问题是Java- Math.random(): Selecting an element of a 13 by 13 triangular array的延伸。我随机选择了两个数字(包括0-12),我希望这些值相等

但现在,由于这是一个乘法游戏,我想找到一种方法来偏向结果,以便某些组合出现得更频繁(比如如果玩家在12x8上表现更差,我希望它出现得更频繁)。最后,我想偏向91种组合中的任何一种,但一旦我把这一点记下来,那就不难了

我的想法是:在三角形数字上加上一些int n,然后Random.nextInt(91 + n)使结果偏向于一个组合

private int[] triLessThan(int x, int[] bias) { // I'm thinking a 91 element array, 0 for no bias, positive for bias towards
    int i = 0;
    int last = 0;
    while (true) {
                    int sum = 0;
                    for (int a = 0; a < i * (i + 2)/2; a++){
                        sum += bias[a]
                    }
        int triangle = i * (i + 1) / 2;
        if (triangle + sum > x){
            int[] toReturn = {last,i};
            return toReturn;
        }
        last = triangle;
        i++;
    }
}

在随机数字滚动时:

int sum = sumOfArray(bias); // bias is the array;
int roll = random.nextInt(91 + sum);
int[] triNum = triLessThan(roll);
int num1 = triNum[1];
int num2 = roll - triNum[0]; //now split into parts and make bias[] add chances to one number.

sumOfArray只找到和(这个公式很简单)。这样行吗

编辑:使用Floris的想法:

随机数字滚动:

int[] bias = {1,1,1,...,1,1,1} // 91 elements
int roll = random.nextInt(sumOfBias());
int num1 = roll;
int num2 = 0;
while (roll > 0){
    roll -= bias[num2];
    num2++;
}
num1 = (int) (Math.sqrt(8 * num2 + 1) - 1)/2;
num2 -= num1 * (num1 + 1) / 2;

共 (1) 个答案

  1. # 1 楼答案

    你已经知道如何将一个介于0和91之间的数字转换成一个滚动(从上一个问题的答案开始)。我建议您创建一个由N个元素组成的数组,其中N>>;91.用0填充前91个元素。。。90,并将计数器A设置为91。现在选择一个介于0和a之间的数字,从数组中选择相应的元素,并转换为乘法问题。如果答案是错误的,则将问题的编号附加到数组的末尾,并将A增加1

    这将创建一个数组,其中采样频率将表示错误解决问题的次数,但如果下次问题得到正确解决,则不会再次降低频率

    另一种更好的解决方案是,与您的解决方案更接近一点(但不同),它创建了一个91个频率的数组,每个频率最初设置为1,并跟踪总和(最初为91)。但是现在,当你选择一个随机数(介于0和和之间)时,你会遍历数组,直到累积和大于你的随机数——箱子的数量就是你选择的滚动,你可以用前面推导的公式来转换它。如果答案是错误的,则增加bin并更新总和;如果它是正确的,您可以减少总和,但决不能减少到小于1的值,并更新总和。重复一遍

    这应该给出你想要的东西:给定一个91个数字的数组(“箱子”),随机选择一个箱子,这样箱子的概率与里面的值成正比。返回bin的索引(可以使用之前的方法将其转换为数字的组合)。调用此函数时,bin(frequency)数组作为第一个参数,累积和作为第二个参数。查找前n个元素的累积和首先超过由频率之和缩放的随机数的位置:

    private int chooseBin(float[] freq, float fsum) {
    // given an array of frequencies (probabilities) freq
    // and the sum of this array, fsum
    // choose a random number between 0 and 90
    // such that if this function is called many times
    // the frequency with which each value is observed converges
    // on the frequencies in freq
        float x, cs=0; // x stores random value, cs is cumulative sum
        int ii=-1;     // variable that increments until random value is found
    
        x = Math.rand();
    
        while(cs < x*fsum && ii<90) { 
        // increment cumulative sum until it's bigger than fraction x of sum
            ii++;
            cs += freq[ii];
        }
    return ii;
    }
    

    我确认它给了我一个直方图(蓝色条),看起来和我输入的概率分布完全一样(红线): histogram

    (注意:这是用matlab绘制的,因此X从1到91,而不是从0到90)

    下面是另一个想法(这并不能真正回答这个问题,但可能更有趣):

    你可以通过抽样而不是均匀分布来改变你选择某个特定问题的概率。例如,均匀抽样随机变量的平方将有利于较小的数字。这给了我们一个有趣的可能性:

    首先,将91个数字随机排列

    接下来,从非均匀分布中选择一个数字(倾向于较小的数字)。由于这些数字是随机排列的,事实上,它们被选中的可能性是相同的。但现在有一个诀窍:如果问题(由选择的数字表示)得到了正确解决,则将问题编号“移动到堆栈顶部”,在该位置再次选择的可能性最小。如果玩家搞错了,它会被移动到堆栈的底部,在那里很可能再次被选中。随着时间的推移,困难的问题会转移到最底层

    可以使用以下变量创建具有不同倾斜度的随机分布:

    roll = (int)(91*(asin(Math.rand()*a)/asin(a)))
    

    a接近1时,函数倾向于支持较低的数字,而较高数字的概率几乎为零:

    non uniform sampling example

    我相信以下代码部分符合我的描述:

    private int[] chooseProblem(float bias, int[] currentShuffle) { 
    // if bias == 0, we choose from uniform distribution
    // for 0 < bias <= 1, we choose from increasingly biased distribution
    // for bias > 1, we choose from uniform distribution
    // array currentShuffle contains the numbers 0..90, initially in shuffled order
    // when a problem is solved correctly it is moved to the top of the pile
    // when it is wrong, it is moved to the bottom.
    // return value contains number1, number2, and the current position of the problem in the list
        int problem, problemIndex;
    
        if(bias < 0 || bias > 1) bias = 0;
    
        if(bias == 0) {
            problem = random.nextInt(91);
            problemIndex = problem;
        }
        else {
            float x = asin(Math.random()*bias)/asin(bias);
            problemIndex = Math.floor(91*x);
            problem = currentShuffle[problemIndex];
        }
    
        // now convert "problem number" into two numbers:
        int first, last;    
        first = (int)((Math.sqrt(8*problem + 1)-1)/2);
        last = problem - first * (first+1) / 2;
    
        // and return the result:
        return {first, last, problemIndex};
    }
    
    
    private void shuffleProblems(int[] currentShuffle, int upDown) {
    // when upDown==0, return a randomly shuffled array
    // when upDown < 0, (wrong answer) move element[-upDown] to zero
    // when upDown > 0, (correct answer) move element[upDown] to last position
    // note - if problem 0 is answered incorrectly, don't call this routine!
    
        int ii, temp, swap;
    
        if(upDown == 0) {
    
            // first an ordered list:
            for(ii=0;ii<91;ii++) {
                currentShuffle[ii]=ii;
            }
    
            // now shuffle it:
            for(ii=0;ii<91;ii++) {
                temp = currentShuffle[ii];
                swap = ii + random.nextInt(91-ii);
                currentShuffle[ii]=currentShuffle[swap];
                currentShuffle[swap]=temp;
            }
            return;
        }
    
        if(upDown < 0) {
            temp = currentShuffle[-upDown];
            for(ii = -upDown; ii>0; ii ) {
                currentShuffle[ii]=currentShuffle[ii-1];
            }
            currentShuffle[0] = temp;
        }
        else {
            temp = currentShuffle[upDown];
            for(ii = upDown; ii<90; ii++) { 
                currentShuffle[ii]=currentShuffle[ii+1];
            }
            currentShuffle[90] = temp;
        }
        return;
    }
    
    
    // main problem posing loop:
    
    int[] currentShuffle = new int[91];
    int[] newProblem;
    int keepGoing = 1;
    
    // initial shuffle:
    shuffleProblems( currentShuffle, 0); // initial shuffle
    
    while(keepGoing) {
        newProblem = chooseProblem(bias, currentShuffle);
        // pose the problem, get the answer
        if(wrong) {
            if(newProblem > 0) shuffleProblems( currentShuffle, -newProblem[2]);
        }
        else shuffleProblems( currentShuffle, newProblem[2]);
        // decide if you keep going...
    }