2

I'm trying to make a Rubik's Cube Scrambler that prints a random series of movements to scramble my cube. However, sometimes my program prints two moves that cancel each other out. How can I avoid this?

This is what I have so far:

import random

scramble_length = random.randint(9,24)

move_list = ["U","U'","D","D'","B","B'","F","F'","L","L'","R","R'"]

for x in range(scramble_length):
    print(random.choice(move_list))

Sorry if my code isn't that good. I'm just starting out.

  • just store the previous move, and if the current move cancels the previous one, cast another random move. BTW "avoid printing the same thing" or "avoid printing 2 opposite things" aren't the same! – Jean-François Fabre Jan 31 '19 at 20:46
  • What level of inversion are you OK with? What about `["U", "D", "U'", "D'"]`? You're still doing a random shuffle if you have an inverse operation just after the previous one. – PMende Jan 31 '19 at 20:51

4 Answers4

0

Assign the last move to a variable outside of your loop and compare against the last move. if they cancel out, generate a new one and compare again.

something like this (assuming i properly understood your 'moves'):

import random

scramble_length = random.randint(9,24)

move_list = ["U","U'","D","D'","B","B'","F","F'","L","L'","R","R'"]
varHold =""

for x in range(scramble_length):
    varNew = random.choice(move_list)
    B_DontContinue = True
    while (B_DontContinue):
        B_DontContinue = False
        if varHold == "U" and varNew == "U'":
            B_DontContinue=True
        elif varHold == "D" and varNew == "D'":
            B_DontContinue = True
        elif varHold == "R" and varNew =="R'":
            B_DontContinue = True
        elif varHold == "L" and varNew == "L'":
            B_DontContinue = True
        elif varHold == "B" and varNew == "B'":
            B_DontContinue = True
        elif varHold == "F'" and varNew == "F'":
                B_DontContinue = True

    print(random.choice(move_list))
sh7411usa
  • 196
  • 1
  • 13
  • A) if, B) elif, and C) else. It just looks silly all those single if statements.. and it takes more time because python has to close the complete if-statement first before its able to do the next. (talking nano seconds for a single if-statement, thus adding many up gives you more than seconds delay if you need to repeat this while-statement a billion times). – ZF007 Jan 31 '19 at 21:28
  • Granted, doesn't look so smooth, but they technically are un-related boolean comparisons. And, as far as I know, theres no Switch statement in python [link](https://stackoverflow.com/questions/60208/replacements-for-switch-statement-in-python) so all such type operations in python will look a little clunky. – sh7411usa Jan 31 '19 at 21:35
  • Those are related boolean comparisons, since they're all on the same two variables. if..elif..else would work. Also `U` and `U'` are opposite moves, not `U` and `D`. (Each letter stands for a different face. The `'` means to turn the face 1/4 turn in the opposite direction, clockwise vs. counter-clockwise.) – Bill the Lizard Feb 01 '19 at 18:05
  • Worse than the verbose if is the while loop and condition variable that should cause another option to be randomly chosen but the code doesn't do that. But it would be better to simply remove the reverse option from the move_list before the random choice rather than rejecting. – Dan D. Feb 03 '19 at 12:30
0

I can think of a couple of different ways to approach this.

  1. You could remove all of the ' moves from your list. Your cube will be just as scrambled by a random sequence of turns all in the same direction. You'll still have the small possibility of four of the same move in a row cancelling each other out, but that's a much smaller probability than two opposite moves in a row.

  2. After you generate the list of moves, scan it for two moves in a row that cancel, then replace one of them (or shuffle the list). Keep doing this until you don't have any pairs of canceling moves.

Bill the Lizard
  • 398,270
  • 210
  • 566
  • 880
0

You can use set difference to remove the opposite of the last move from the possible moves before passing them to random.choice:

import random
scramble_length = random.randint(9, 24)
moves = {"U", "U'", "D", "D'", "B", "B'", "F", "F'", "L", "L'", "R", "R'"}
move = ''
for x in range(scramble_length):
    move = random.choice(tuple(moves - {move[0] if len(move) == 2 else move + "'"}))
    print(move)

Sample output:

B'
U'
D
F
B'
B'
R'
F'
R'
B'
F
D'
B'
R
B'
F
U'
D
D
U
L
U'
B
blhsing
  • 91,368
  • 6
  • 71
  • 106
0

Instead of giving it as comment.

The cube mapping structure:

1 - There are nine tiles on each side of the cube in rows (R) of three and/or columns (C) of three.

2 - From left to right each column is numbered as 1,2 or 3. Idem for rows.

3 - The example "UC1" stands for the following instruction: "Move column 1" > "Up".


So if you introduce coordinates you would get for example string:

["UC1", "DR2", "UC2'", "DC3", "U1C", RR1].

Here RR1 = "move row 1 > "right".

Thus adding the mapping structure your change to end-up with the same exact canceling moves directly behind each other declines a lot. And if your moves can be divided by 4 you might end up for one tile to be on the same location again but the other two tiles (either column or row) are different regardless of color of the tile.

Take into account that just as Jean mentioned you need to remember the last move (last_move = [direction, row/column, row/column number]).

Many variables to code for ;p

ZF007
  • 3,708
  • 8
  • 29
  • 48