0

I'm doing a C++ program, in which I want to shuffle an array (or part of an array). Here is the array:

        string colorTheme[8][8] = {
            {"blue", "blue", "green", "green", "violet", "violet", "teal", "teal"},
            {"beige", "beige", "red", "red", "indigo", "indigo", "pink", "pink"},
            {"cyan", "cyan", "yellow", "yellow", "orange", "orange", "azure", "azure"},
            {"purple", "purple", "lime", "lime", "tangerine", "tangerine", "fuschia", "fuschia"},
            {"brown", "brown", "gray", "gray", "black", "black", "white", "white"},
            {"olive", "olive", "crimson", "crimson", "silver", "silver", "gold", "gold"},
            {"maroon", "maroon", "coral", "coral", "plum", "plum", "ivory", "ivory"},
            {"aqua", "aqua", "jade", "jade", "amber", "amber", "ruby", "ruby"}
        };

If I wanted to shuffle the first n rows and n columns, how would I do it? Ideally, I would run

shuffle(n);

because colorTheme is in the same class as shuffle().

  • You cannot shuffle the array because it is `const`. – MikeCAT Jul 22 '22 at 20:08
  • *If I wanted to shuffle the first n rows and n columns,* -- Given that input, what exactly do you mean by "shuffle the first n rows and n columns"? Let's say you want to shuffle the first row -- isn't that going to shuffle the entire row, regardless of the column? – PaulMcKenzie Jul 22 '22 at 20:09
  • @MikeCAT I didn't specify this (my mistake), but I had a copy of the array with the same values. For now, I'll remove `const` from the declaration. – Nishant Kompella Jul 22 '22 at 20:15
  • @PaulMcKenzie The array is a square of 8 strings by 8 strings. If I wanted to take a square of the first, say, four strings by four strings, and shuffle them, how would I go about doing that? – Nishant Kompella Jul 22 '22 at 20:16
  • A hard-example of what a subN by subN shuffle of an N by N array would look like before and after is pretty-much mandatory for this ask. Specifically, it answers the inquisition of whether **all** cells in the subN by subN partition are viable to swap with all *other* cells in the same partition (as opposed to row-only or column-only). It makes a difference, as it significantly alters the possible algorithms to do so. – WhozCraig Jul 22 '22 at 20:47

2 Answers2

1

You can't shuffle const array, but you can do it by changing it, I will post an example of shuffling a 2d array, you can refer that if you want to:

#include <iostream>
#include <cstdlib>
#include <ctime>
#include <cstring>
#include <string>
#include <algorithm>
#include <iterator>

int main()
{
    // the hard, inefficient way
    {
        enum { N = 7, M = 13 } ;
        char dest[N][M] = { "zero", "one", "two", "three", "four", "five", "six" } ;

        std::srand( std::time(nullptr) ) ;

        for( int i = N-1 ; i > 0 ; --i ) // fisher yates shuffle
        {
            const int pos = std::rand() % (i+1) ;
            char temp[M] ;
            std::strcpy( temp, dest[pos] ) ;
            std::strcpy( dest[pos], dest[i] ) ;
            std::strcpy( dest[i], temp ) ;
        }

        for( const char* cstr : dest ) std::cout << cstr << ' ' ;
        std::cout << '\n' ;
    }

    // the simple, efficient way
    {
        enum { N = 7 } ;
        std::string dest[N] = { "zero", "one", "two", "three", "four", "five", "six" } ;

        std::srand( std::time(nullptr) ) ; // if it has not already been done

        std::random_shuffle( std::begin(dest), std::end(dest) ) ;

        for( const std::string& str : dest ) std::cout << str << ' ' ;
        std::cout << '\n' ;
    }
}
Sojo C Johny
  • 126
  • 8
  • Using an `enum` is meaningful in C, to enforce that `M` and `N` are [integer constants](https://en.cppreference.com/w/c/language/integer_constant) and that therefore a [variable-length array](https://en.cppreference.com/w/c/language/array#Variable-length_arrays) is not created. However, in C++, it is sufficient to simply write `const int N = 7, M = 13;` instead of `enum { N = 7, M = 13 } ;`. – Andreas Wenzel Jul 22 '22 at 20:44
  • Fyi, `std::random_shuffle` was deprecated in C++14, removed outright in C++17. Use a decently clothed RNG or PRNG and `std::shuffle` instead. This also doesn't answer the question of shuffling only a partition of an array of arrays, *both* on the column *and* row axis. – WhozCraig Jul 22 '22 at 20:47
0

The best way to tackle this problem is to convert the 2D array into 1D, as shuffling a 1D array is a lot simpler. Under the covers, create an int array shuffler; fill an int array with values from 0 - n^2 and shuffle them using something like rand. From there, use the values in the int array as new positions for your string array. Once you have shuffled your string array, convert it back into a 1D array. Here is a simple c++ source file I created (feel free to use).

#include <iostream>
#include <string>

using namespace std;

void shufflePos(int n, int arr[]);

void printArray(int *a, int length) {
    cout << "[ ";
    for (int i = 0; i < length; i ++) {
        cout << a[i];
        if (i != length - 1) {
            cout << ", ";
        }
    }
    cout << " ]\n";
}

void shufflePos(int n, int arr[]) {
    for(int i = 0; i < n; i++) {
        arr[i] = i;
    } 
    // shuffle positions
    srand(time(0));
    for(int i = 0; i < (n - 2); i++) {
        /*if(arr[i] != i) // i has already been swapped
            continue;
        */
        int tmp = arr[i];
//        cout << "i = " << i << ", n - i = " << (n - i) << ", ";
        int random = rand();
//        cout << "random = " << random << ", ";
        int nextPos = i + random % (n - i);
//        cout << "nextPosition = " << nextPos << endl;
        arr[i] = arr[nextPos]; // swap
        arr[nextPos] = tmp;
    }
        //printArray(arr, n);
/*    bool chck = check(arr, n);
    if(chck == false)
        cout << "FALSE" << endl;
    else
        cout << "TRUE" << endl; */
}

void swapString(string arr[], int pos1, int pos2) {
    string tmp = arr[pos1];
    arr[pos1] = arr[pos2];
    arr[pos2] = tmp;
    return;
}

void shuffleString(string strs[], int len) {
    int valArr[len];
    shufflePos(len, valArr);
    string to[len];
    // copying values into another array
    for(int i = 0; i < len; i++) {
        to[i] = strs[valArr[i]];
    }
    // copying to[] into strs[]
    for(int i = 0; i < len; i++) {
        strs[i] = to[i];
    }
}

int main() {
    string colorTheme[8][8] = {
        {"blue", "blue", "green", "green", "violet", "violet", "teal", "teal"},
        {"beige", "beige", "red", "red", "indigo", "indigo", "pink", "pink"},
        {"cyan", "cyan", "yellow", "yellow", "orange", "orange", "azure", "azure"},
        {"purple", "purple", "lime", "lime", "tangerine", "tangerine", "fuschia", "fuschia"},
        {"brown", "brown", "gray", "gray", "black", "black", "white", "white"},
        {"olive", "olive", "crimson", "crimson", "silver", "silver", "gold", "gold"},
        {"maroon", "maroon", "coral", "coral", "plum", "plum", "ivory", "ivory"},
        {"aqua", "aqua", "jade", "jade", "amber", "amber", "ruby", "ruby"}
    };
    cout << "What size of array do you want?" << endl;
    int i;
    cin >> i;
    int n = i * i; // length of 1D array
    string darr[n]; // 1D array
    for(int r = 0; r < i; r++) { // fill values of 1D array // rows
        for(int c = 0; c < i; c++) { // columns
            darr[(i * r + c)] = colorTheme[c][r];
        }
    }
    cout << 1 << endl;
    shuffleString(darr, n);
    cout << 2 << endl;
    // convert 1D array back into 2D array
    for(int r = 0; r < i; r++) {
        for(int c = 0; c < i; c++) {
            colorTheme[c][r] = darr[(i * r) + c];
        }
    }
    for(int r = 0; r < i; r++) { // rows
        for(int c = 0; c < i; c++) { // columns
            cout << ": " << colorTheme[c][r] << " ";
        }
        cout << endl;
    }
}
  • You use variable-length arrays a lot. Note that in C++, they are a *non-standard extension* implemented by some compilers, see [this question](https://stackoverflow.com/questions/1887097/why-arent-variable-length-arrays-part-of-the-c-standard) and answers. You can use [std::vector](https://en.cppreference.com/w/cpp/container/vector) instead. – YurkoFlisk Jul 27 '22 at 00:42
  • @YurkoFlisk ah, I didn't realize that. I don't know how to use vector, so I simply used a variable-length array. – Infection Tag Jul 27 '22 at 17:16