简体   繁体   中英

Rubik's Cube Scramble Generator algorithm

I've been recently working on a project which includes a Rubik's Cube scramble generator. Basically the program should generate and display random cube notations so that the user can follow each move and have a fairly scrambled cube. Notations include "R" for turning the right layer , "L" for turning the left layer, "F" for turning front layer, "D" for down, "U" for up and "B" for back. And so you have a total of 6 sides "R, L, U, D, F, B". The appostrophe after any of these notations means moving that layer counter clockwise and "2" means moving that layer twice. The problem is you can't have the same notation be repeated next to each other like "R, R" as it would be the same as "R2", nor you can have "R, R' " next to each other as they would cancel each other out. My solution to this was making a 2 dimensional array for storing the 3 groups of notations for every type.

string notation_group[row][column] = { { "R ", "L ", "F ", "B ", "U ", "D " },
    {"R' ", "L' ", "F' ", "B' ", "U' ", "D' "}, { "R2", "L2", "F2", "B2", "U2", "D2"} };

This means that whenever the program picks a random column from any of these groups, the program has to prevent the next generated notation from choosing the same column in any other group. So let's say if the program picks the first element of the first group "R", then for the next iteration it can choose any notation except "R", "R' " and "R2", all of which belong to the first column of their respective groups. So all the program has to do is not to pick that column during the next iteration.

I used a "temp" variable to keep in mind the current randomly generated notation and compare it to the next one, and generating a new one whenever those are equal.

int temp;

            scrambled_notation[i] = notation_group[pickGroup][pickColumn];

            temp = pickColumn;

            pickColumn = 0 + rand() % 6;

            while (temp == pickColumn) {
                pickColumn = 0 + rand() % 6;
            }

It does work but there is still another problem, whenever you have something like "R, L" or "R, L', R" be repeated multiple times next to each other they would again cancel each other out leaving no affect on the cube. Is there any idea for how can I prevent two of the opposing sides being repeated next to each other for more than once? I would greatly appreciate the help.

    void initScramble(const int, string[][6], string[]);

int main() {

    srand(time(0));

    const int row = 3, column = 6;
    string notation_group[row][column] = { { "R", "L", "F", "B", "U", "D" },
    {"R'", "L'", "F'", "B'", "U'", "D'"}, { "R2", "L2", "F2", "B2", "U2", "D2"} };

    const int scrambleSize = 22;
    string scrambled_notation[scrambleSize];

    cout << "SCRAMBLE: " << endl;

    initScramble(scrambleSize, notation_group, scrambled_notation);

    system("pause");
    return 0;
}

void initScramble(const int scrambleSize, string notation_group[][6], string scrambled_notation[]) {

    int pickColumn = 0 + rand() % 6;

    while (true) {

        cin.get();

        for (int i = 0; i < scrambleSize; i++) {

            int pickGroup = 0 + rand() % 3;

            int temp;

            scrambled_notation[i] = notation_group[pickGroup][pickColumn];

            temp = pickColumn;

            pickColumn = 0 + rand() % 6;

            while (temp == pickColumn) {
                pickColumn = 0 + rand() % 6;
            }
        }

        for (int i = 0; i < scrambleSize; i++) {
            cout << scrambled_notation[i] << "  ";
        }
        cin.get();
        system("CLS");
    }

}

You have to look for the last two moves as long as they are commutative. If not, then you only check for the last move. This is simplified by the fact that each pair of columns are commutative:

void initScramble(const int scrambleSize, string notation_group[][6], string scrambled_notation[]) {
    while (true) {
        int lastColumn = 7; // Invalid columns
        int beforeLastColumn = 7;

        cin.get();

        for (int i = 0; i < scrambleSize; i++) {
            int pickGroup = 0 + rand() % 3;
            int pickColumn = 0 + rand() % 6;
            bool isCommutative = (lastColumn / 2) == (beforeLastColumn / 2);

            while (pickColumn == lastColumn || isCommutative && pickColumn == beforeLastColumn) {
                pickColumn = 0 + rand() % 6;
            }

            scrambled_notation[i] = notation_group[pickGroup][pickColumn];
            beforeLastColumn = lastColumn;
            lastColumn = pickColumn;
        }

        for (int i = 0; i < scrambleSize; i++) {
            cout << scrambled_notation[i] << "  ";
        }
        cin.get();
        system("CLS");
    }
}

You don't have to look further since you can have only 2 commutative consecutive moves following your rules of scrambling. For example, 'L,R,L' and 'L,R,R' will be discarded, and thus, 3 commutative moves will never be generated.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM