Search code examples
pythonrandomdictionaryrubiks-cube

Using Dictionaries in Python in place of Case/Switch statement


I want to randomize a rubik's cube that is initialized as complete (all colors on the correct sides). I have move functions that rotate the cube. I want to randomly pick 50 functions in a row to properly randomize it.

I am doing this project to learn a little bit more about Python, since I mostly do C++ and I see there is no case/switch for Python, so I am trying a dictionary. When I make the dictionary, the code seems to execute for some reason:

def random_cube(self):
    scramble = {    0 : self.up_turn(),
                    1 : self.down_turn(),
                    2 : self.left_turn(),
                    3 : self.right_turn(),
                    4 : self.front_turn(),
                    5 : self.back_turn(),
                    6 : self.up_turn("inverted"),
                    7 : self.down_turn("inverted"),
                    8 : self.left_turn("inverted"),
                    9 : self.right_turn("inverted"),
                    10: self.front_turn("inverted"),
                    11: self.back_turn("inverted")
                }
    for x in range(50):
        i = random.randint(0,11)
        scramble[i]

So when I make this dictionary, it seems to run through and execute all 11 entries for some reason (I think). I can't seem to find a better way, at least more elegant than a long if/elif string of statements.

!EDIT: Implementing both suggestions, the ("inverted") flag for the functions are not being set by either suggestion. For example, calling 1 and 7 both give me down_turn, but the output shows that the flag was not set when it should have been on number 7.

Any ideas?


Solution

  • When you define the dict, it's actually calling the functions, and storing the return value in the dictionary. To just have the dictionary store a reference to the functions, you need to drop the trailing parentheses. So something like:

    scramble = {  0: self.up_turn,
                  1: self.down_turn,
                  etc.
    

    Then, at the bottom, call scramble[i]().

    This will call the function with no arguments. To handle the case where you pass "inverted" as an argument, you could either define separate functions like up_turn_inverted(), etc., or you could have the dictionary store a 2-ple consisting of the function, and the argument, then call something liks scramble[i][0](scramble[i][1])

    Update from suggestion in comments: You could also use lambda expressions to define the functions, particularly the ones that require an argument. This is basically equivalent to defining an up_turn_inverted function, but done in-place as an anonymous function. It would look like this:

    6: lambda: self.up_turn("inverted")
    7: lambda: self.down_turn("inverted")
    

    etc.