Random Java offset numbers in a triangular array

This question is an extension of Java-Math.random (): selecting an element from a triangular array of 13 by 13 . I select two numbers randomly (0-12 inclusive), and I wanted the values ​​to be equal.

But now, since this is a multiplication game, I want to avoid the results, so some combinations occur more often (for example, if a player does worse for 12x8, I want him to appear more often). In the end, I would like to move towards any of the 91 combinations, but as soon as I get this, it should not be difficult.

My thoughts: add int n to the triangular number and Random.nextInt(91 + n) to shift the results towards the combination.

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

When throwing random numbers:

 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. 

where sumOfArray just finds the sum (this formula is simple). Will this work?

Edit: Using Floris's idea:

Random number roll:

 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
source share
1 answer

You already know how to convert a number between 0 and 91 and turn it into a roll (from the answer to the previous question). I would suggest that you create an array of N elements, where N β†’ 91. Fill the first 91 elements with 0 ... 90 and set counter A to 91. Now select a number between 0 and A, select the corresponding element from the array and convert into the problem of multiplication. If the answer is incorrect, add the problem number to the end of the array and increase A by one.

This will create an array in which the sampling frequencies will be the number of errors that were not resolved correctly, but this will never reduce the frequency if the problem is resolved correctly on the next request.

An alternative and better solution, which is slightly closer to yours (but different), creates an array of 91 frequencies - each of which is initially set to 1 - and tracks the amount (initially 91). But now, when you select a random number (between 0 and the sum), you move the array until the sum of the cumulative sum is greater than your random number - the number of the bunker - the throw you selected, and you convert it with the formula obtained earlier, If the answer is incorrect, you increase the size of the bin and update the amount; if this is correct, you reduce the amount, but not by a value less than one, and update the amount. Repeat.

This should give you exactly what you are asking: a given array of 91 numbers ("bins") randomly selects a bunker so that the probability of this bin is proportional to its value. Return the bunker index (which can be converted to a combination of numbers using the method you had before). This function is called with the bin (frequency) array as the first parameter, and the total sum as the second. You look up, where the total sum of the first n elements first exceeds a random number, scalable by the sum of frequencies:

 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 bigger than fraction x of sum ii++; cs += freq[ii]; } return ii; } 

I confirmed that he gives me a histogram (blue bars), which looks exactly like the probability distribution that I gave him (red line): histogram

(note - this was built using the Matlab matrix, so X goes from 1 to 91, not from 0 to 90).

Here's another idea (this doesn't actually answer the question, but it is potentially even more interesting):

You can skew your likelihood of choosing a specific problem by taking something other than uniform distribution as a sample. For example, a square of uniformly discretized random deviations will contribute to smaller numbers. This gives us an interesting opportunity:

First shuffle your 91 digits in random order

Then select a number from the uneven distribution (which prefers smaller numbers). Since the numbers were randomly shuffled, they are essentially equally likely. But now here's the trick: if the problem (represented by the selected number) is solved correctly, you move the problem number β€œto the top of the stack”, where it is least likely to be selected again. If the player is mistaken, he moves to the bottom of the stack, where he will most likely be selected again. Over time, complex problems move to the bottom of the stack.

You can create random distributions with varying degrees of skew using variation

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

As A approaches 1, the function tends to lower numbers with an almost zero probability of higher numbers:

non uniform sampling example

I believe the following sections of code do what I described:

 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... } 
+3
source

All Articles