More Heavily Weighted Random Numbers

One area where weighted random numbers come in to play is when doing a simulation. In a recent set of Exercises (May and June 2015), your mission was to craft a bowling game simulator. Like most simulations, the bowlings game simulator made use of random numbers. The problem in this situation is most decent bowlers don’t roll randomly.

In bowling, the first ball score skews toward all the pins knocked down, with 10 being the most common score, followed by 9, then 8, and so on. This information can be found on the Internet in various bowling blogs.

In Figure 1, I’ve copied a chart from a bowling website for the first ball pin distribution. As you can see from the chart, nearly a quarter of the time the first ball rolled is a strike.

Figure 1. Pins knocked down for the first ball in a frame.

Figure 1. Pins knocked down for the first ball in a frame.

The website from which I stole Figure 1 didn’t list discrete values, which is what I really need to create a weighted random number generator. So I used Excel to extrapolate the values as best i could. These are presented in Figure 2 as a percentage distribution chart:

Figure 2. Percentage distribution for first ball.

Figure 2. Percentage distribution for first ball.

To accurately simulate the first ball rolled in a frame, you need to weight the random numbers to reflect those presented in Figures 1 and 2. If I followed my cat state simulator examine from last week’s Lesson, I’d manually create an array with 100 elements and distribute values 0 through 10 among the elements as presented in Figure 2. That’s a lot of work.

Because computers are supposed to save time, a better solution must be at hand.

In Figure 3, I ranked the pins by percentage from highest-to-lowest. I also added the percentage values to create a ranking between 1 and 100. That way the code can generate values from 1 to 100 randomly and the results can be weighted based on the N values shown in Figure 3.

Figure 3. Ranking the pins knocked down from 0 to 100.

Figure 3. Ranking the pins knocked down from 0 to 100.

My solution is shown below. The weighted random numbers appear in the n[][] array in the ball() function. They’re ranked as shown in Figure 3 based on their percentage values.

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int ball(void)
{
    int n[10][2] = {
        { 10, 25 },
        { 9, 47 },
        { 8, 65 },
        { 7, 82 },
        { 6, 91 },
        { 5, 94 },
        { 3, 96 },
        { 0, 98 },
        { 4, 99 },
        { 5, 100 }
    };
    int b,x;

    b = (rand() % 100) + 1;
    for(x=0;x<10;x++)
    {
        if(b <= n[x][1])
            return(n[x][0]);
    }
    return(2);
}

int main()
{
    int x;

    srand((unsigned)time(NULL));
    for(x=0;x<100;x++)
        printf("%2d\t",ball());
    putchar('\n');

    return(0);
}

The code generates 100 random rolls. Here’s sample output:

 9	10	 8	10	 9	 7	 2	 7	 8	 7
 8	 9	 5	 7	 7	10	 3	 7	 8	 9	 9
10	 8	10	10	10	10	 7	 7	 8	 5	 8
10	 7	 9	 9	 7	 8	 7	 6	 7	 9	 9
 6	10	 2	10	 7	 5	 9	 9	 6	10	10
 7	 8	10	 0	10	 3	 7	 9	 7	10	10
 7	 8	10	 7	 8	 3	10	 9	10	 8	 7
 9	10	 7	 8	 7	 9	 3	 6	 7	10	 5
 8	 9	 8	 7	 9	10	 9	 7	10	10	 0
10	10

In the ball() function, variable b holds a random value from 1 to 100. The for loop at Line 22 fetches the percentage value from array n[][1]. If the value of b is less-than-or-equal-to that value, then the value from n[][0] is fetched — the weighted random result.

The for loop examines all the results up to 100. The value 2 is returned at Line 27 even though that part of the code should in theory never be reached. That’s okay because knocking down 2 pins is pretty much impossible according to the raw data.

Leave a Reply