The random number

Random number is an important concept in the field of statistics, and it also has great significance for games. Using random numbers well can make your games more real, more human, and more attractive.

For example: in a target game, the position shown by the bullet hitting the collimation center every time is unscientific, and the jitter error will make the sense of reality more intense; Another example is the lottery big wheel program. Whenever the wheel stops rotating, the pointer just points to the middle point of the prize picture. People will feel that the wheel is very unnatural, pointing to a random position is much better.

As anyone who has learned JavaScript knows, applying random numbers is easy. Math.random() is all it takes to get a floating point number greater than or equal to 0 and less than 1. When selecting objects randomly from a collection, use the discretized result of a floating-point number as the index of the selection set:

var objects = [...] ; var randomIndex = Math.floor( objects.length * Math.random() ); var object = objects[ randomIndex ];Copy the code

Distribution of random numbers

The values of math.random () and randomIndex in the preceding code belong to “continuous distribution” and “discrete distribution” in the theory of “probability distribution”. Distribution is used to describe the probabilistic properties of random variables. Among them, uniform distribution is the most commonly used distribution type (none), whether continuous or discrete. In the case of the big wheel, even distribution can be used to determine “where the wheel stops” and “where the wheel stops”.

The uniform distribution is characterized by: the probability of all basic events is equal. The following is the histogram of the number of values of math.random () experiments in one million:

It can be seen that even with pseudo-random numbers, the distribution is impeccable, and if the sample size is large enough, the histogram above will present a straight line.

Consider the example of a shooting game, where jitter errors are “evenly distributed” at the locations indicated by the collimation, and see what happens after 2,000 trials:

People would think that the gun had terrible collimation, when in fact we expect the bullet to hit exactly where the collimation is most of the time. In other words, the bullet has the highest probability of hitting the collimation, and the probability decreases as the error distance increases.

In this case, we need to optimize the random function so that the spit value is more close to 0 and less than 1. A simple way to do this is to introduce a second random quantity and multiply it by it. The result of 2000 experiments is as follows:

Let’s take a look at the histogram of random numbers in these three situations (sample number of each graph is 1,000,000 times) :

Generates a random number that conforms to the specified probability model

Just as we do motion effects, easing operators can make animation more dynamic, and applying the right probability distribution can make the page/game more expressive. Different from the slow motion effect, the probability distribution requires a large enough sample set to reflect the effect, and all kinds of particles (fireworks, flame, dazzling light, smoke, floating catkins, etc.) commonly seen on Codepen are inseparable from the probability distribution.

The scenario described above may seem flashy, but the raffle requirement is much more useful. How could macBooks and portable power supplies be evenly distributed among all the prizes in the raffle? Setting different probabilities for each prize is a basic feature of any lottery platform.

Suppose a lucky draw, the prize probability is set as follows:

  • Climbing bag: 0.01
  • Luggage: 0.03
  • Mobile power supply: 0.06
  • Failure to win (also seen as a prize) : 0.9

That is, out of the expected 1,000 lucky draws, about 10 will hit the hiking bag, about 30 will hit the suitcase, about 60 will hit the mobile power supply, and about 900 will not win.

Create an updateRandom() function that returns a floating point number greater than or equal to 0 and less than 1. Divide the value between 0 and 1 into four segments, each corresponding to a prize, and determine which prize is hit based on the return value of the function. The return value of updateRandom() should be:

  • Return value period [0, 0.25), probability 0.01
  • Return value period [0.25, 0.5), probability 0.03
  • Return value period [0.5, 0.75), probability 0.06
  • Return value period [0.75, 1), probability 0.9

JavaScript implementation:

function updateRandom() {
  var p = Math.random(), n = Math.random() / 4;

  if(P < 0.01)return 0 + n;

  if(P < 0.04)return0.25 + n.if(P < 0.1)return0.5 + n.if( p < 1 )
    return 0.75 + n;
}
Copy the code

You can still use it in the most familiar way:

var objects = [ 'Hiking bag'.'Suitcase'.'Mobile power supply'.'Not winning' ];
var randomIndex = Math.floor( objects.length * updateRandom() ); 
var object = objects[ randomIndex ];
Copy the code

The value histogram of the 1 million updateRandom() experiment is as follows:

Configurability of probability

The previous code demonstrates how to generate random floating point numbers that conform to a given probability model. The limitation is that the model data is hardcoded in the body of the function and is difficult to maintain.

If you design a factory function, according to the input weight data to dynamically create a random function, it will bring great convenience to the practical application.

JavaScript implementation:

function randomInProbability( weights ){
  if( arguments.length > 1 ){ weights = [].slice.call( arguments ); } var total, current = 0, parts = [], i = 0, l = weights.length; // Simple compatibility of reduce methods total = selects.reduce? weights.reduce(function( a, b ){
    returna + b; }) :eval( weights.join( '+'));for(; i < l; i ++ ){ current += weights[ i ]; parts.push('if( p < ', current / total, ' ) return ', i / l, ' + n; ' );
  }

  return Function( 'var p = Math.random(), n = Math.random() / ' + l + '; ' + parts.join( ' ')); }Copy the code

This way, it’s easy to get random functions for any probability model. Again, it’s easy to create an updateRandom() function:

Var updateRandom = randomInProbability(0.01, 0.03, 0.06,.09);Copy the code

Now, let’s play a trick:

var model = [];

for( var i = 0; i < 100; i ++ ){
  model.push( 2 + sin( PI * 2 * i / 50 ) );
}

var randomInSin = randomInProbability( model );

Copy the code

Let’s see what the histogram of randomInSin() looks like a million times:

Fed.taobao.org/blog/2015/1…