killerkody gaming
killerkody gaming

Reputation: 113

How do I shuffle a 2D array in C++

I searched on the forum and found only shuffling solutions withing Java or Javascript. For my project, I need to be able to shuffle a 2 dimensional card deck array. It is within two dimensions to be able to have the suit and the card score available. cardDeck[5][14] is my array. To specify, I do not need to have every value moved to a different location, and I don't have to move between the rows because of how the array is designed. Each row represents a suit and each column is a card score from 1 to 13. I tried looking at the shuffle function on cplusplus website, but I don't really understand how the function prototype works. Is there anyway someone could help me shuffle these rows? I appreciate your help.

The reason I have it designed this way is because for my project I am required to use composition by having a class called Deck with two objects of a previous project's card game. cardDeck[3][5] = {0,1,2,3,4} {0,1,2,3,4} {0,1,2,3,4};is a smaller version of what my array is. But in my program I use a member function to fill the deck for me so I don't have to write out 52 items.

Upvotes: 2

Views: 2243

Answers (2)

Felipe Oliveira
Felipe Oliveira

Reputation: 1

Please, keep in mind that I did not compile any of these codes, so there might be some errors on the code.

Here is how you can use std::shuffle to shuffle elements in an arbitrary array:

#include <random>
#include <algorithm>
#include <iterator>
#include <iostream>
#include <vector>

int main()
{
    // STL functions that operate over range of elements usually take
    // iterators as arguments, so your data must be in an iterable 
    // container, like std::vector or std::array
    std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

    // initialize random number generator engine
    std::random_device rd;
    std::mt19937 g(rd());

    // first argument is an iterator to the beginning of the vector (v[0])
    // second argument is an iterator to the end of the vector (v[v.size()-1])
    // third argument is the rng engine
    std::shuffle(v.begin(), v.end(), g);

    for (auto i : v) {
        std::cout << i << " ";
    }
    std::cout << "\n";
}

A possible outcome would be 8 6 10 4 2 3 7 1 9 5.

Regarding your problem, here is how I would do it. In order to use std::shuffle you need that your data is in a iterable container such as a std::vector, so we need to convert your initial 2D array into a vector of vector of ints (std::vector<std::vector<int>>). Once we have this, we can use std::shuffle to shuffle the elements of each row. When we are done, we can simply copy back the elements to the initial 2D array, if we so wish.

#include <random>
#include <algorithm>
#include <iterator>
#include <iostream>
#include <vector>

int main()
{
    int cards[5][14];

    // init cards...

    std::vector<std::vector<int>> cardsVec;

    for (int j = 0; j < 5; ++j) {
        cardsVec.push_back(std::vector<int>(cards + j * 5, cards + j * 5 + 14));
    }

    std::random_device rd;
    std::mt19937 g(rd());

    // use a range-for it iterate over cardsVec
    for (auto& row: cardsVec) { 
        std::shuffle(row.begin(), row.end(), g);
    }

    for (int j = 0; j < 5; ++j) {
        for (int k = 0; k < 14; ++k) {
            cards[j][k] = cardsVec[j][k];
        }
    }
}

Now, please keep in mind that you can do everything with just the vectors if you wish, the only reason I copied the contents of arrays to the vectors and back is that you mentioned using an array in your problem. Here is how it might look if we used only vectors instead of arrays:

#include <random>
#include <algorithm>
#include <iterator>
#include <iostream>
#include <vector>

int main()
{
    std::vector<std::vector<int>> cards;
    cards.resize(5); // allocates 5 rows

    for (auto& row : cards) {
        row.resize(14) // allocates 14 cards in this row
    }

    // init cards as you would init the array version...

    std::random_device rd;
    std::mt19937 g(rd());

    // use a range-for it iterate over cards
    for (auto& row: cards) { 
        std::shuffle(row.begin(), row.end(), g);
    }

    // ...
}

Finally, C++ has an array container as well. It is basically the same as flat arrays, with the addition of being safer and iterable, like vectors, and thus can be used directly in the STL functions that take iterators as arguments. Like flat arrays, the std::array has a fixed size which must be know in compile time, so won't be allocating it like you would the vector.

#include <random>
#include <algorithm>
#include <iterator>
#include <iostream>
#include <array>

int main()
{
    // array of 5 arrays of 14 integers
    std::array<std::array<int, 14>, 5> cards;

    // init cards as you would init the array version...

    std::random_device rd;
    std::mt19937 g(rd());

    // use a range-for it iterate over cards
    for (auto& row: cards) { 
        std::shuffle(row.begin(), row.end(), g);
    }

    // ...
}

Upvotes: 0

R Sahu
R Sahu

Reputation: 206717

One way to do that would be:

  1. Create a 1D array of size 5*14.
  2. Set the values of the elements of the array to 0 - 5*14-1.
  3. Shuffle the 1D array.
  4. Iterate through the elements of the 1D array and move the elements in the 2D array by mapping 1D indices to 2D indices.

Upvotes: 4

Related Questions