John B
John B

Reputation: 99

Picking random chars from char array?

I'm very new to C++ and have a pretty daunting assignment due this week. I won't get into too much detail about it as I don't want work done for me, but can anyone point me in the right direction as to how I would go about picking random characters from a multi-dimensional string array?

char gameZero[16][6] = { {'A','A','C','I','O','T'}, {'A','H','M','O','R','S'}, {'E','G','K','L','U','Y'}, {'A','B','I','L','T','Y'}, {'A','C','D','E','M','P'}, {'E','G','I','N','T','V'}, {'G','I','L','R','U','W'}, {'E','L','P','S','T','U'}, {'D','E','N','O','S','W'}, {'A','C','E','L','R','S'}, {'A','B','J','M','O','Q'}, {'E','E','F','H','I','Y'}, {'E','H','I','N','P','S'}, {'D','K','N','O','T','U'}, {'A','D','E','N','V','Z'}, {'B','I','F','O','R','X'} };

The goal is to print out a 4x4 board of these characters, picking one random character from each array at the start of every game so not one board is the same.

Any advice/tips on how to do this would be greatly appreciated-- thank you!

EDIT:

I have gotten to a point where I can generate a random indices from both arrays, however the current way I am doing it only outputs one character, whereas I need ONE char from each of the 16 assortments within the array. Any ideas on how I can output one from each? I'd imagine I have to put the index generators inside some sort of loop.

mt19937 gen(time(nullptr)); // random number generator

// used to generate random number in specific range 
uniform_int_distribution<int> random_outer(0, outer_size - 1);
uniform_int_distribution<int> random_inner(0, inner_size - 1);

int index_outer = random_outer(gen); // used to generate random outer index
int index_inner = random_inner(gen); // used to generate random inner index

cout << gameZero[index_outer][index_inner] << endl;

Upvotes: 1

Views: 1333

Answers (4)

John B
John B

Reputation: 99

With a mixture of help thanks to all of the people who responded in this thread, I believe I've come to a reasonable answer to my problem. If anyone happens to come across this thread, here it what I came up with:

void shuffleDice() { // shuffles Game #0 dice. 

mt19937 gen(time(nullptr));
uniform_int_distribution<int> random_inner(0, inner_size - 1);

int n = random_inner(gen); // generates random number for inner array 
for (int i = 0; i < 16; i++) // loops through outer array
{
    cout << gameZero[i][n] << '\n';
}

Keep in mind I am new to programming/C++, so it may not be the prettiest, but it works nonetheless.

Upvotes: 0

David C. Rankin
David C. Rankin

Reputation: 84561

Given your gameZero of type char[16][6], you need only generate a single random number that represents an offset from the beginning of gameZero in the range (0, sizeof gameZero). An array of any fundamental type (char, int, double, etc...) is guaranteed to be sequential in memory. Further, in your case with type char, each char is 1-byte. So you can access any of the characters in gameZero by computing an offset from the start of the array.

As you have found, C++ provides its own Pseudo-random number generation. You can pick any one of the distribution engines to create a random distribution. When you need a random number from the make a call using your distribution passing the engine you have created an instance to as its argument. For example to use create a random distribution using the std::mersenne_twister_engine, you could do:

#include <random>
...
    char gameZero[16][6] = {{'A','A','C','I','O','T'}, 
    ...
    std::random_device rd;              /* random device/seed */
    std::mt19937 gen(rd());             /* standard mersenne_twister_engine */
    std::uniform_int_distribution<> dist(0, sizeof gameZero);    /* dist */

Then in order to pick a random element representing an offset within gameZero you simply request a random number using:

        int off = dist(gen);        /* get random offset in gameZero */

From the offset, the [x][y] element within gameZero can be computed simply by using the number of columns in your array (6 in your case), e.g.

        int x = off / 6,            /* compute row from offset */
            y = off - 6 * x;        /* compute col from offset */

(note: the integer division is intentional in computing the x (row) value above)

You can then access the random element simply with gameZero[x][y].

For example, if in a loop you request a random offset and compute the [x][y] indexes as explained above, you can output the offset, the computed indexes and the character at that index similar to the following:

$ ./bin/randarr2d
92 - gameZero[15][2] = F
 9 - gameZero[ 1][3] = O
14 - gameZero[ 2][2] = K
91 - gameZero[15][1] = I
86 - gameZero[14][2] = E
46 - gameZero[ 7][4] = T
92 - gameZero[15][2] = F
33 - gameZero[ 5][3] = N
87 - gameZero[14][3] = N
57 - gameZero[ 9][3] = L
87 - gameZero[14][3] = N
50 - gameZero[ 8][2] = N
10 - gameZero[ 1][4] = R
23 - gameZero[ 3][5] = Y
...

Understand, you can access the element directly with the offset alone as well, but that would cause a technical violation of array bounds. (e.g. *(*gameZero + off)) The short-story is a 2D array is actually an array of 1D arrays. When you access an array it is converted to a pointer to its 1st element. In the case of the 2D array, that is a pointer to the first array. (the 1st 6-char array in your case), so if you apply an offset of more than 5, you are technically addressing an element outside of the bounds of the 1st 1D array even though you are still within the bounds of your 2D array. Computing the x, y indexes from the single offset eliminates that issue.

Look things over and let me know if you have any further questions.

Upvotes: 0

eerorika
eerorika

Reputation: 238341

You can use the following algorithm:

  • generate random number x in the interval [0, std::size(gameZero )[
  • generate random number y in the interval [0, std::size(gameZero[0])[
  • Access gameZero[x][y] for a random character of the 2D array.

Upvotes: 2

acegs
acegs

Reputation: 2809

  • provide a list of int with 6 items.
  • initialize it with index values from 0 - 5.
  • for every cell in a board: //from 0 - 15.
    • shuffle the list-of-int.
    • for every 4x4 board you have: //let's say max of 6.
      • set the current cell of the current board with item in list-of-int at index iBoard.
        • //example: board[iBoard][iCell] = listInt[iBoard]

Upvotes: 0

Related Questions