[c++] How to generate a random number in C++?

Generate a different random number each time, not the same one six times in a row.

Use case scenario

I likened Predictability's problem to a bag of six bits of paper, each with a value from 0 to 5 written on it. A piece of paper is drawn from the bag each time a new value is required. If the bag is empty, then the numbers are put back into the bag.

...from this, I can create an algorithm of sorts.

Algorithm

A bag is usually a Collection. I chose a bool[] (otherwise known as a boolean array, bit plane or bit map) to take the role of the bag.

The reason I chose a bool[] is because the index of each item is already the value of each piece of paper. If the papers required anything else written on them then I would have used a Dictionary<string, bool> in its place. The boolean value is used to keep track of whether the number has been drawn yet or not.

A counter called RemainingNumberCount is initialised to 5 that counts down as a random number is chosen. This saves us from having to count how many pieces of paper are left each time we wish to draw a new number.

To select the next random value I'm using a for..loop to scan through the bag of indexes, and a counter to count off when an index is false called NumberOfMoves.

NumberOfMoves is used to choose the next available number. NumberOfMoves is first set to be a random value between 0 and 5, because there are 0..5 available steps we can make through the bag. On the next iteration NumberOfMoves is set to be a random value between 0 and 4, because there are now 0..4 steps we can make through the bag. As the numbers are used, the available numbers reduce so we instead use rand() % (RemainingNumberCount + 1) to calculate the next value for NumberOfMoves.

When the NumberOfMoves counter reaches zero, the for..loop should as follows:

  1. Set the current Value to be the same as for..loop's index.
  2. Set all the numbers in the bag to false.
  3. Break from the for..loop.

Code

The code for the above solution is as follows:

(put the following three blocks into the main .cpp file one after the other)

#include "stdafx.h"
#include <ctime> 
#include <iostream>
#include <string>

class RandomBag {
public:
    int Value = -1;

    RandomBag() {
        ResetBag();

    }

    void NextValue() {
        int BagOfNumbersLength = sizeof(BagOfNumbers) / sizeof(*BagOfNumbers);

        int NumberOfMoves = rand() % (RemainingNumberCount + 1);

        for (int i = 0; i < BagOfNumbersLength; i++)            
            if (BagOfNumbers[i] == 0) {
                NumberOfMoves--;

                if (NumberOfMoves == -1)
                {
                    Value = i;

                    BagOfNumbers[i] = 1;

                    break;

                }

            }



        if (RemainingNumberCount == 0) {
            RemainingNumberCount = 5;

            ResetBag();

        }
        else            
            RemainingNumberCount--; 

    }

    std::string ToString() {
        return std::to_string(Value);

    }

private:
    bool BagOfNumbers[6]; 

    int RemainingNumberCount;

    int NumberOfMoves;

    void ResetBag() {
        RemainingNumberCount = 5;

        NumberOfMoves = rand() % 6;

        int BagOfNumbersLength = sizeof(BagOfNumbers) / sizeof(*BagOfNumbers);

        for (int i = 0; i < BagOfNumbersLength; i++)            
            BagOfNumbers[i] = 0;

    }

};

A Console class

I create this Console class because it makes it easy to redirect output.

Below in the code...

Console::WriteLine("The next value is " + randomBag.ToString());

...can be replaced by...

std::cout << "The next value is " + randomBag.ToString() << std::endl; 

...and then this Console class can be deleted if desired.

class Console {
public:
    static void WriteLine(std::string s) {
        std::cout << s << std::endl;

    }

};

Main method

Example usage as follows:

int main() {
    srand((unsigned)time(0)); // Initialise random seed based on current time

    RandomBag randomBag;

    Console::WriteLine("First set of six...\n");

    randomBag.NextValue();

    Console::WriteLine("The next value is " + randomBag.ToString());

    randomBag.NextValue();

    Console::WriteLine("The next value is " + randomBag.ToString());

    randomBag.NextValue();

    Console::WriteLine("The next value is " + randomBag.ToString());

    randomBag.NextValue();

    Console::WriteLine("The next value is " + randomBag.ToString());

    randomBag.NextValue();

    Console::WriteLine("The next value is " + randomBag.ToString());

    randomBag.NextValue();

    Console::WriteLine("The next value is " + randomBag.ToString());

    Console::WriteLine("\nSecond set of six...\n");

    randomBag.NextValue();

    Console::WriteLine("The next value is " + randomBag.ToString());

    randomBag.NextValue();

    Console::WriteLine("The next value is " + randomBag.ToString());

    randomBag.NextValue();

    Console::WriteLine("The next value is " + randomBag.ToString());

    randomBag.NextValue();

    Console::WriteLine("The next value is " + randomBag.ToString());

    randomBag.NextValue();

    Console::WriteLine("The next value is " + randomBag.ToString());

    randomBag.NextValue();

    Console::WriteLine("The next value is " + randomBag.ToString());

    Console::WriteLine("\nThird set of six...\n");

    randomBag.NextValue();

    Console::WriteLine("The next value is " + randomBag.ToString());

    randomBag.NextValue();

    Console::WriteLine("The next value is " + randomBag.ToString());

    randomBag.NextValue();

    Console::WriteLine("The next value is " + randomBag.ToString());

    randomBag.NextValue();

    Console::WriteLine("The next value is " + randomBag.ToString());

    randomBag.NextValue();

    Console::WriteLine("The next value is " + randomBag.ToString());

    randomBag.NextValue();

    Console::WriteLine("The next value is " + randomBag.ToString());

    Console::WriteLine("\nProcess complete.\n");

    system("pause");

}

Example output

When I ran the program, I got the following output:

First set of six...

The next value is 2
The next value is 3
The next value is 4
The next value is 5
The next value is 0
The next value is 1

Second set of six...

The next value is 3
The next value is 4
The next value is 2
The next value is 0
The next value is 1
The next value is 5

Third set of six...

The next value is 4
The next value is 5
The next value is 2
The next value is 0
The next value is 3
The next value is 1

Process complete.

Press any key to continue . . .

Closing statement

This program was written using Visual Studio 2017, and I chose to make it a Visual C++ Windows Console Application project using .Net 4.6.1.

I'm not doing anything particularly special here, so the code should work on earlier versions of Visual Studio too.