2013-04-02 39 views
1

此問題是Java- Math.random(): Selecting an element of a 13 by 13 triangular array的擴展。我隨機選擇兩個數字(0-12包括),我希望這些值相等。但現在,由於這是一個乘法遊戲,我想要一種方法來偏向結果,以便更頻繁地出現某些組合(例如,如果玩家對12x8變得更糟,我希望它更頻繁地出現)。最終,我想偏向於91種組合中的任何一種,但是一旦我弄明白了,這應該不難。三角形陣列中的Java偏置隨機數

我的想法:將一些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剛找到的總和(即式是容易)。這會工作嗎?

編輯:使用弗洛里斯的想法:

在隨機數卷:

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; 
+0

爲什麼**你不**嘗試自己並驗證它是否有效? (O_o) – SudoRahul

+0

@ R.J嗯,我提出了一個問題並提出了一個可能的解決方案。如果它有效,那麼你只需將它作爲答案發布,你就會被接受。 – Justin

回答

3

你已經知道如何將數字轉換0和91之間,並把它變成一個卷(從答案到你以前的問題)。我建議你創建一個N元素數組,其中N >> 91。用0 ... 90填充前91個元素,並將計數器A設置爲91.現在選擇一個介於0和A之間的數字,選擇相應的元素,並轉換爲乘法問題。如果答案不正確,請將問題編號追加到數組末尾,並將A加1。

這將創建一個數組,其中採樣頻率將表示錯誤解決問題的次數 - 但如果問題在下次詢問時正確解決,它不會再次降低頻率。

另一種更好的解決方案,以及更接近你的一個(但不同)創建一個包含91個頻率的陣列 - 每個頻率初始設置爲1,並跟蹤總和(最初爲91)。但是現在,當你選擇一個隨機數(在0和總和之間)時,你遍歷數組,直到累積和大於你的隨機數 - 倉的數量就是你選擇的倉位,然後用前面推導的公式。如果答案錯誤,則增加容器並更新總和;如果它是正確的,你減少總和,但從不小於一個值,並更新總和。重複。

這應該給你準確的問題:給定91個數字(「bin」)的數組,隨機選擇一個bin,以便該bin的概率與其中的值成比例。返回bin的索引(可以使用之前的方法將它轉換爲數字的組合)。使用bin(頻率)數組作爲第一個參數調用此函數,第二個作爲累積和。你查找其中第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... 
} 
+0

我想我明白你在說什麼;我使用我認爲您推薦的代碼對您的帖子進行了編輯。不過,我認爲它應該是'int num2 = rollStore(int)(Math.sqrt(8 * num1 + 1)-1)/ 2'。這裏是我的理解:'int [] bias = {1,1,...,1,1}; // 91元素''roll = random.nextInt(sumOfBias());''int num1 = 0'對於(; roll> 0; num1 ++)roll - = bias [num1]'(在編輯中犯了一些錯誤) – Justin

+0

還有幾件事:爲偏移某個數字,我可以增加數組中的其他元素。 rollStore是不必要的;我可以 - 在rollStore創建的地方 - 創建num2並將其設置爲roll,然後執行'num2 - =(int)(Math.sqrt(8 * num1 + 1)-1)/ 2;' – Justin

+0

我很抱歉 - 看起來我是在編輯代碼的同時,我的編輯以某種方式覆蓋了你的......我將添加一些代碼來展示最後一個示例(我認爲這是最好的)會工作。 – Floris