Search code examples
c++randommersenne-twister

Mersenne Twister & receiving Semantic Issue in the algorithm.h


I’m very new to programming, and hope this question isn't burdensome. As a part of a video tutorial series I am using via YouTube that uses a series of challenges for students to use the portions of the language up to that point to solve a predefined problem. In this case, its making a simple Humans Vs Skeleton “1D Combat Simulator” (LINK: https://youtu.be/TH7plF4UT_E?list=PLSPw4ASQYyynKPY0I-QFHK0iJTjnvNUys)

The tutor, Ben, originally uses default_random_engine, but in his annoyed note of the video states that this is a bad implementation and mt19937 is a better choice. (LINK: https://youtu.be/JGwSEbnJGR0?list=PLSPw4ASQYyynKPY0I-QFHK0iJTjnvNUys&t=138).

I have searched through Stack Overflow as well as cplusplus.com, and other sites, etc.

I could not find helpful hints in either of these. Most Mersenne Twister questions seemed to be issues with it’s use, not with problems in any header or library files. : Issues with c++ 11 mersenne_twister_engine class : How to run Mersenne Twister inside a function? : mt19937 and uniform_real_distribution : Why do I get the same sequence for every run with std::random_device with mingw gcc4.8.1?

I decided to go the rout of mt19937 for a more accurate random generation with more entropy, as I understand it. It may be overkill for the small project I am working on, and am open to better solutions.

I often become bored with most C++ tutorials (videos or books) as they teach the syntax & vocabulary, but rarely teach problem solving with the language. So, I skip around and toy with things, even when I don’t understand them, so that I can try to understand them better. My understanding of functions, in terms of their anatomy and best use, is weak. The same goes with classes. Nonetheless, I have implemented met19937 into a function so I could create various polyhedral die simulations. (d4, d6, d8, d10).

My source code doesn’t have any errors, however, the algorithm.h file has two errors of the same type, as follows.

Type ‘std::__1::mersenne_twister_engine (long)’ cannot be used prior to ‘::’ because it has no members

When I go into the algorithm.h file (as if I knew what I were doing), these are the lines of code that the errors are found in.

private:
typedef typename _Engine::result_type _Engine_result_type;
typedef typename conditional
    <

and

tatic _LIBCPP_CONSTEXPR const _Working_result_type _Rp = _Engine::max() - _Engine::min()
                                                  + _Working_result_type(1);

(respectively on lines 2844 & 2866 of the file.)

This is my source code, I have commented out a lot of items, as I am trying to get one thing working before toying around with the rest:

#include <iostream>
#include <string>
#include <random>
//#include <chrono>
//#include <ctime>

using namespace std;

/*
  // Simple Attack and Defense Attributes.
 int Agility = 40;
 int Attack =52;

 int MyAgility = 45;
 int MyAttack = 64;
*/

//Globals
mt19937 randomGenerator(time_t);
//default_random_engine randomGenerator(time_t);

//Function Protypes
void d4();
void d6();
void d8();
void d10();
void SuccessCheck();


int main()
{

    //Variables
    int MyWarriors;
    //int WarriorsAvailable = NULL;
    //int Skeletons = NULL;
    //int CharacterCount;

    /*
    int Attack;
    int Defense;
    int AxeDMG = 1;
    int SwordDMG = 2;
    int ShieldDEF = 1;

    //String Variables
    //Too Many Soldiers Requested
    char str1[150] = "I'm sorry Sire, we just don't have that many troops available.";
    char str2[150] = "No sir! We just can't manage that.";
    char str3[150] = "Oh! Our woes would not be so terrible, should we only have that many in our guard.";
    char str4[150] = "Have you been listening to my counsel? We just can't raise an army that size in such a short time.";
    char str5[150] = "Very well Sir, I suppose we'll perish until you can't give me a real answer.";

    //A Valid Amount of Soldiers Requested
    char str6[150] = "Great! I'll send them through the gates immediately!";
    char str7[150] = "YES! Through the forest, they'll ut down our foes!";
    char str8[150] = "By the Lord Almighty, they shall be vanquished!";
    char str9[150] = "They won't stand a chance!";
    char str10[150] = "No man or beast will rise against you again!";

    //Maybe Not Enough Soldiers Requested
    char str11[150] = "You may need a tad more men, Sire.";
    char str12[150] = "Perhaps, you'd like to join your men, just in case they need help?";
    char str13[150] = "I think we have a few more men you could send, Sire.";
    char str14[150] = "Oh yea, you'll have them quaking in their boots. Much like kittens and babies would. Perhaps you could spare a few more?";
    char str15[150] = "You can't say that I didn't warn you. Maybe send a few more men.";
    */


    //Random number of Skeletons!
    uniform_int_distribution<int> Skeletons (1, 3000);

    //Random number of Skeletons!
    uniform_int_distribution<int> WarriorsAvailable (1, 3000);

    //Invalid MySoldier Selection
    uniform_int_distribution<int> TooManySoldiers (1, 5);

    //Random number of Skeletons!
    uniform_int_distribution<int> RightNumSoldiers (6, 10);

    //Random number of Skeletons!
    uniform_int_distribution<int> ATadMoreSoldiers (11, 15);

    cout << "Sire! There are " << Skeletons(randomGenerator) << " marching toward the castle!" << endl << "We should send out our troops!" << endl;
    cout << "Our registry indicates that we have " << WarriorsAvailable << " who are combat ready!";
    cout << "How many warriors do wich to send out to battle?" << endl;
    cin >> MyWarriors;


    /*
    do {
        <#statements#>
    } while (<#condition#>); (MyWarriors > WarriorsAvailable)
        cout <<  << endl << "How many warriors woudl you like to send in to combat?";


    cout << "Yes, Sire! I will rally " << MyWarriors << " to do battle with our enemy, at once!" << endl << endl;


    */

    return 0;

}


//Dice Functions: Many of these functions cam from a Stack Overflow answer I found weeks prior to joining
void d4(){//function prints a randomly generated number
    //mt19937 randomGenerator(time_t);
    //auto seed = chrono::high_resolution_clock::now().time_since_epoch().count();
    uniform_int_distribution<int> d4Die (1, 4);
    int d4Roll = d4Die(randomGenerator); //the generated number is then set equal to an integer for functionality
    cout << d4Roll; //finally, the integer is printed to the screen
}


void d6(){//function prints a randomly generated number
    //mt19937 randomGenerator(time_t);
    uniform_int_distribution<int> d6Die (1, 6);
    int d6Roll = d6Die(randomGenerator); //the generated number is then set equal to an integer for functionality
    cout << d6Roll; //finally, the integer is printed to the screen
}

void d8(){//function prints a randomly generated number
    //mt19937 randomGenerator(time_t);
    uniform_int_distribution<int> d8Die (1, 8);
//the generated number is then set equal to an integer for functionality
    int d8Roll = d8Die(randomGenerator);
    cout << d8Roll; //finally, the integer is printed to the screen
}

void d10(){//function prints a randomly generated number
    //mt19937 randomGenerator(time_t);
    uniform_int_distribution<int> d10Die (1, 10);
    //the generated number is then set  equal to an integer for functionality
    int d10Roll = d10Die(randomGenerator); 
    cout << d10Roll; //finally, the integer is printed to the screen
}

void SuccessCheck(){//function prints a randomly generated number
    //mt19937 randomGenerator(time_t);
     //Success Check based on a percentile roll of (2d10) yielding a 1 - 100%
    uniform_int_distribution<int> SCDie (1, 100);
    //the generated number is then set equal to an integer for functionality
    int SCRoll = SCDie(randomGenerator); 
    cout << SCRoll; //finally, the integer is printed to the screen

}

//Combat Skill Modifier
uniform_int_distribution<int> CmbSklMod (1, 3);

//uniform_real_distribution<float> SucessCheck(0.0f, 1.0f);

Solution

  • Your problem is that

    mt19937 randomGenerator(time_t);
    

    Is not creating a random numnber generator. It declares a function named randomGenerator that takes a time_t and returns a mt19937.

    What you need to do is use something like

    std::random_device rd
    std::mt19937 randomGenerator{rd()};
    

    This will create the PRNG and seed it with the initial value from rd. If you want a better seed then you can use

    std::random_device rd;
    std::seed_seq seed{rd(), rd(), rd(), rd(), rd(), rd(), rd(), rd()};
    std::mt19937 randomGenerator(seed);
    

    The above technique comes from bames53 in this answer