elo2021
elo2021

Reputation: 1

How would you shuffle elements in an dynamic 2d array?

I have been looking online without any luck.

Can one rearrange/shuffle elements in a 2d array randomly? How about a 2d array made of Objects? The 2d array is located in a constructor. The 2d array contains object elements. These elements will be replaced by 'card face' objects. I already have made a class of 'card face' objects, that I duplicated and put inside of a 2d array. Each card face has a pair/match in the array. I thought it easier to loop the card object and their copy into the array to replace each element, then shuffle the array afterward.

SO that example...

[[ AH, AH, 2C],
 [ 2C, 3D, 3D],
 [ 4S, 4S, X]]

would become...

[[ 2C, AH, 2C],
 [ AH, 3D, 4S],
 [ 4S, 3D, X]]

?

Upvotes: 0

Views: 283

Answers (2)

GoWiser
GoWiser

Reputation: 1045

If we assume the objects we are trying to change are of type std::string, then we can use the approach shown below. The methods used for randomizing the order of your elements are templates, so they should work with the type of your choice.

#include <iostream>
#include <string>
#include <random>

template <typename T> void swap(T* a, T* b) {
    T temp = *a;
    *a = *b;
    *b = temp;
}

// Shuffle the old fashioned way
template <typename T> void randomize(T arr[], size_t n) {
    if (n == 0)
        return;
    srand((unsigned)time(NULL));
    for (size_t i = n - 1; i > 0; --i) {
        size_t j = rand() % (i + 1);
        swap(arr + i, arr + j);
    }
}

// Shuffle the c++11 way
template <typename T> void randomize_c11(T arr[], size_t n) {
    if (n == 0)
        return;
    std::random_device rd;
    std::mt19937 g(rd());
    std::shuffle(arr, arr + n, g);
}

template <typename T> void print_array(T arr[], size_t rows, size_t cols) {
    std::string indent = "    ";
    std::cout << "[" << std::endl;
    for (size_t row = 0; row < rows; ++row) {
        std::cout << indent << "[";
        for (size_t col = 0; col < cols; ++col) {
            if (col != 0)
                std::cout  << ", ";
            std::cout << *(arr + row*cols + col);
        }
        std::cout << "]" << std::endl;
    }
    std::cout << "]" << std::endl;
}


int main()
{
    std::string array[4][3] = { { "AH", "AH", "2C"},
        {"2C", "3D", "3D"},
        {"AAAA", "BBB", "CC"},
        {"4S", "4S", "X"} };
    // Convert to 1d array (a pointer)
    std::string* array2 = (std::string*)array;
    // Calculate the size of the array
    size_t count = sizeof(array) / sizeof(array[0][0]);
    size_t rows = sizeof(array) / sizeof(array[0]);
    size_t cols = count / rows;
    // Show the 1d-array before sorting
    print_array((std::string*)array, rows, cols);
    // Shuffle the array the old fashioned way
    randomize(array2, count);

    // You can use the variable array directly and avoid using the variable array2:
    //     randomize((std::string *)array, count);

    // You can also do it using the C++11 way:
    //     randomize_c11((std::string *)array, count);

    // Show the array after sorting
    print_array((std::string*)array, rows, cols);
    return 0;
}

Here is an example of running the program:

enter image description here

Note that the old fashioned way of randomizing using rand() isn't optimal. See:

Pseudo-random number generation in C++
std::random_device

And for shuffling see also:

std::random_shuffle, std::shuffle

Upvotes: 1

Drew
Drew

Reputation: 229

Just mentally unroll the array into 1D, then randomize it like any other:

  1. Pick a random number n between 0 and num_items-1

  2. Copy from the first index to index n in the output array

  3. Pick another random number from a range 0 to num_empty_slots -1 (so 1 lower than before)

  4. Count empty slots from the beginning of the array to the end and copy to the n'th empty slot.

  5. Go back to 3

You don't actually need steps 1 and 2 because 3-5 covers every case, but I included them to make it more intuitive.

Upvotes: 0

Related Questions