-1

I have created a simple random number program that takes 5 inputs and outputs different random numbers.

A user can enter 5 vowels irrespective of case and the function calculates a random number based on the input.

Possible Incomes: a A a A e

Possible Outcomes: 1 2 3 19 25

Problem: I do not get different numbers when I enter the same vowel more than once, but this is not the same when I put a breakpoint and run my code in debugger mode

Following is my code

#include <iostream>
#include <ctime>
#include <cstdlib>
#include <iomanip>

using namespace std;

int createRandomFromChar(char inputChar);

int main()
{
    char answer;
   
    char inputOne, inputTwo, inputThree, inputFour, inputFive;

    cout << endl <<
        "This program plays a simple random number guessing game." << endl;

    do
    {
        cout << endl << "Enter 5 vowel characters (a,e,i,o,u or A,E,I,O,U) separated by spaces: ";
        cin >> inputOne >> inputTwo >> inputThree >> inputFour >> inputFive;
        cin.ignore();
       
        int randomNumberOne = createRandomFromChar(inputOne);
        int randomNumberTwo = createRandomFromChar(inputTwo);
        int randomNumberThree = createRandomFromChar(inputThree);
        int randomNumberFour = createRandomFromChar(inputFour);
        int randomNumberFive = createRandomFromChar(inputFive);
        

        cout << "The random numbers are " << left << 
            setw(3) << randomNumberOne << left <<
            setw(3) << randomNumberTwo << left <<
            setw(3) << randomNumberThree << left << setw(3) << randomNumberFour 
            << left << setw(3) << randomNumberFive;

       

        cout << endl << "Do you want to continue playing? Enter 'Y' or 'y' to continue playing: "
            << endl;
        
       
        answer = cin.get();

        cin.ignore();
    }
    while ((answer == 'y') || (answer == 'Y'));

}

int createRandomFromChar(char inputChar)
{
    srand(time(0));

    int n1 = 1 + (rand() % 20);
    int n2 = 21 + (rand() % 20);
    int n3 = 41 + (rand() % 20);
    int n4 = 61 + (rand() % 20);
    int n5 = 81 + (rand() % 20);

    if ((inputChar == 'a') || (inputChar == 'A'))
    {
        return n1;

    }
    else if ((inputChar == 'e') || (inputChar == 'E'))
    {
        return n2;

    }
    else if ((inputChar == 'i') || (inputChar == 'I'))
    {
        return n3;

    }
    else if ((inputChar == 'o') || (inputChar == 'O'))
    {
        return n4;

    }
    else if ((inputChar == 'u') || (inputChar == 'U'))
    {
        return n5;

    }
    else
    {
        return 0;
    }
    
}
 
syed zain
  • 1
  • 1
  • 4
    Does this answer your question? [srand() — why call it only once?](https://stackoverflow.com/questions/7343833/srand-why-call-it-only-once) – Yunnosch Jun 10 '22 at 06:16
  • 2
    `time(0)` returns time in seconds. Calling it several times in a second will yield the same seed and so the same random sequence. When you put a breakpoint you force the increase of the time interval and so you'll get different seeds. Bottom line: you should put `srand(time(0));` in `main()` before the calls to `createRandomFromChar`. – wohlstad Jun 10 '22 at 06:22
  • 1
    Even better than fixing `srand` - in C++ it's recomended to use the utilities. See: https://en.cppreference.com/w/cpp/numeric/random. – wohlstad Jun 10 '22 at 06:26

1 Answers1

0

I do not get different numbers when I enter the same vowel more than once, but this is not the same when I put a breakpoint and run my code in debugger mode

It's because of this:

int createRandomFromChar(char inputChar)
{
    srand(time(0));  // <- the culprit

Every time you call createRandomFromChar you reseed (restart) the pseudo random number generator with the value returned from time(0). If you run the program without stepping through the debugger it will run through the program in a few microseconds and time(0) will return the same value every time - so, you will get the same sequence of numbers from rand() afterwards. When you step through the debugger, you will likely take your time and therefore time(0) will return different values which will result in different number sequences coming from rand().

The solution is to only call std::srand(std::time(nullptr)); once during the whole program run. You can do it in the beginning of main and then never again.



Another option is to use one of the better pseudo random number generators, like std::mt19937, that was added to C++ in C++11 and one of the distributions that tagged along with them, like std::uniform_int_distribution. These generators are pretty fast and have portable statistical properties which rand() doesn't have. Note: You should only seed these once per program run too.

Example usage:

#include <array>
#include <cctype>
#include <iomanip>
#include <iostream>
#include <random>
#include <string_view>

// A better pseudo random number generator than using rand() (+ srand()). 
// This is here seeded by a call to an instance of `std::random_device`:
static std::mt19937 prng(std::random_device{}());

int createRandomFromChar(char inputChar) {
    // a string_view over the valid characters:
    static std::string_view chars{"aeiou"};

    // a distribution to turn random numbers into the range [1,20]:
    static std::uniform_int_distribution<int> dist(1, 20);

    // turn inputChar into lowercase:
    inputChar = static_cast<char>(std::tolower(static_cast<unsigned char>(inputChar)));

    // find the position of the inputChar in the string_view:
    if(auto pos = chars.find(inputChar); pos != std::string_view::npos) {
        // multiply the position in the string_view with
        // (dist.max() - dist.min() + 1) which is 20, so
        //  'a' becomes 0 * 20 => 0
        //  'e' becomes 1 * 20 => 20
        //  'i' becomes 2 * 20 => 40  etc...
        int letter_start = static_cast<int>(pos) * (dist.max() - dist.min() + 1);

        // get a random number in the range [1,20]:
        int randomNumber = dist(prng);

        // return the result:
        return letter_start + randomNumber;
    }

    // inputChar was not found in the string_view, return 0:
    return 0;
}

You could also simplify your main a bit by using arrays instead of separate variables:

int main() {
    char inputs[5]; // all inputs

    std::cout
        << "Enter " << std::size(inputs)
        << " vowel characters (a,e,i,o,u or A,E,I,O,U) separated by spaces: ";

    // extract one char at a time:
    for(char& inp : inputs) {
        if(!(std::cin >> inp)) {
            std::cerr << "error in input, bye bye.\n";
            return 1;
        }
    }

    // all results:
    int rndNumbers[std::size(inputs)];

    for(size_t i = 0; i < std::size(inputs); ++i) {
        rndNumbers[i] = createRandomFromChar(inputs[i]);
    }

    std::cout << "The random numbers are ";
    for(int num : rndNumbers) {
        std::cout << std::left << std::setw(3) << num;
    }
    std::cout << '\n';
}
Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108
  • Thanks a lot Ted. Based on your explanation I just moved the srand(time(0)); to the main() function and it works absolutely fine now – syed zain Jun 10 '22 at 21:15