Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use random_engine and mt19937 in for loops

Tags:

c++

I'm creating a simple ASCII game that is supposed to place 3 snakes on the screen. I tried to use a for loop to print all 3 snakes:

#include <iostream>
#include <conio.h>
#include <string>
#include <cstdlib>
#include <random>
#include <ctime>

using namespace std;

int main() {

    char _levelTwo[20][20];

    int minSizeRand = 1;
    int maxSizeRand = 19;

    //Random Enemie 1 Placement Engine
    static random_device xSeed;
    static mt19937 randGen(xSeed());
    uniform_int_distribution<int> enemieX(minSizeRand, maxSizeRand);

    static random_device ySeed;
    static mt19937 randGen1(ySeed());
    uniform_int_distribution<int> enemieY(minSizeRand, maxSizeRand);

    int snakeRows = enemieX(xSeed);
    int snakeCols = enemieY(ySeed);

    //Tries to Print 3 Snakes
    for (int i = 0; i < 3; i++) {

        cout << "Snake x: " << snakeRows << endl;
        cout << "Snake y: " << snakeCols << endl;

        _levelTwo[snakeRows][snakeCols] = 'S';
    }
cin.get();
return 0;
}

When The code above is called, it only prints one snake. I've tried a non-static engine and it still gives the same output. Is this because the engine needs to be reseeded? I've also printed 2 snakes by creating 2 different engines, but that seems like it wastes a lot of space and if I wanted 10 snakes I would need 10 different engines. How do you get different outputs from the same random_engine and mt19937 when using a for loop?

#include <iostream>
#include <conio.h>
#include <string>
#include <cstdlib>
#include <random>
#include <ctime>

using namespace std;

int main() {

    char _levelTwo[20][20];

    int minSizeRand = 1;
    int maxSizeRand = 19;

    //Random Enemie 1 Placement Engine
    static random_device xSeed;
    static mt19937 randGen(xSeed());
    uniform_int_distribution<int> enemieX(minSizeRand, maxSizeRand);

    static random_device ySeed;
    static mt19937 randGen1(ySeed());
    uniform_int_distribution<int> enemieY(minSizeRand, maxSizeRand);

    int snakeRows = enemieX(xSeed);
    int snakeCols = enemieY(ySeed);
    //Sets placement of snake 1
    _levelTwo[snakeRows][snakeCols] = 'S';

    //Random Enemie Placement Engine
    random_device xSeed2;
    mt19937 randGen2(xSeed2());
    uniform_int_distribution<int> enemieX2(minSizeRand, maxSizeRand);

    random_device ySeed2;
    mt19937 randGen3(ySeed2());
    uniform_int_distribution<int> enemieY2(minSizeRand, maxSizeRand);

    int snakeRows2 = enemieX2(xSeed2);
    int snakeCols2 = enemieY2(ySeed);
    //Sets placement of snake 2
    _levelTwo[snakeRows2][snakeCols2] = 'S';
}

I've read C++ generating random numbers in a loop using default_random_engine, but it doesn't answer my question completely.

like image 644
Ethan Shapiro Avatar asked Nov 28 '15 20:11

Ethan Shapiro


1 Answers

First, you don't need more than one random number generator in this case (you almost never need). There is also no need for it to be static. In the question you linked he needed it to be static because the generator was inside a function that was being called multiple times. Everytime the function was called a generator was being instantiated with almost same seed making it generate almost same numbers. Just do

random_device rd;
mt19937 rng(rd());

This defines a random number generator rng with a seed generated by std::random_device. You don't need more of them, because one generator can generate endless sequence of numbers.

Then there are distributions. They work by defining a range in which you want the numbers to be generated. They are lightweight, storing just a pair of numbers. In your case you need 2 of them. One for the distribution of x coordinates and one for y coordinates (If they don't differ you need only one, bacause they would be defining the same range).

uniform_int_distribution<int> xDist(minX, maxX);
uniform_int_distribution<int> yDist(minY, maxY);

You generate numbers by passing the generator through the distribution like you would with a function.

int x = xDist(rng); //generator outputs one integer and updates its state to be able to generate the next one. 
int y = yDist(rng);

Now you want to generate more than one position. Generating the coordinates stays the same, but you have to do it inside the loop. In your first code you generate one position and use it twice, resulting in placing two enemies in the same place. Just include the generation inside the loop.

for (int i = 0; i < 2; i++) {
}
    int x = xDist(rng);
    int y = yDist(rng);
    //do something with x,y
}
like image 118
Sopel Avatar answered Nov 11 '22 04:11

Sopel