techlord10
techlord10

Reputation: 49

Rubik's Cube rotation in Python

I've got a representation of a Rubik's Cube and I'm trying to add rotation methods. I've been banging my head against this for more than a day, and I just can't find the bug in my code.

I've got a Box class which has string attributes for each of its six faces. I fill a 3X3X3 array with Boxes in the Cube class (including a redundant Box at the center of the Cube, but this code is still unoptimized). Then I assign the correct colors to the boxes, with values of 'none' if that face isn't visible from outside the Cube.

Up until here, it works perfectly, but when I added the first rotation method, rot_front(), it spits out a weird result.

I've added debug methods if you wanna try it out. Here's my code:

class Box:
    def __init__(self):
        self.top = 'none'
        self.bottom = 'none'
        self.right = 'none'
        self.left = 'none'
        self.front = 'none'
        self.back = 'none'

class Cube:
    def __init__(self):
        self.boxes = [[[Box() for i in range(3)] for i in range(3)] for i in range(3)]

        for z in range(3):
            for y in range(3):
                for x in range(3):
                    if z == 0:
                        self.boxes[z][y][x].front = 'white'
                    if z == 2:
                        self.boxes[z][y][x].back = 'yellow'

                    if y == 0:
                        self.boxes[z][y][x].top = 'red'
                    if y == 2:
                        self.boxes[z][y][x].bottom = 'orange'

                    if x == 0:
                        self.boxes[z][y][x].left = 'blue'
                    if x == 2:
                        self.boxes[z][y][x].right = 'green'

    def print_front(self):
        z = 0
        for y in range(3):
            for x in range(3):
                print(cube.boxes[z][y][x].front, end=" ")
            print("")

    def print_back(self):
        z = 2
        for y in range(3):
            for x in range(3):
                print(cube.boxes[z][y][x].back, end=" ")
            print("")

    def print_top(self):
        y = 0
        for z in range(3):
            for x in range(3):
                print(cube.boxes[z][y][x].top, end=" ")
            print("")

    def print_bottom(self):
        y = 2
        for z in range(3):
            for x in range(3):
                print(cube.boxes[z][y][x].bottom, end=" ")
            print("")

    def print_left(self):
        x = 0
        for z in range(3):
            for y in range(3):
                print(cube.boxes[z][y][x].left, end=" ")
            print("")

    def print_right(self):
        x = 2
        for z in range(3):
            for y in range(3):
                print(cube.boxes[z][y][x].right, end=" ")
            print("")

    def rot_front(self):
        front_face = self.boxes[0]
        for y in range(3):
            for x in range(3):
                target = front_face[2-x][y]

                self.boxes[0][y][x].top = target.left
                self.boxes[0][y][x].right = target.top
                self.boxes[0][y][x].bottom = target.right
                self.boxes[0][y][x].left = target.bottom



cube = Cube()
cube.rot_front()


print("FRONT")
cube.print_front()
print("BACK")
cube.print_back()

print("TOP")
cube.print_top()
print("BOTTOM")
cube.print_bottom()

print("LEFT")
cube.print_left()
print("RIGHT")
cube.print_right()

Thanks in advance for your help!

Upvotes: 0

Views: 1043

Answers (1)

bb1950328
bb1950328

Reputation: 1599

The easiest method is to make a deepcopy of self.boxes and change it and then replace self.boxes at the end of the rotation:

import copy

class Cube:
    # other methods stay the same
    def rot_front(self):
        front_face = self.boxes[0]
        new_state = copy.deepcopy(self.boxes)
        for y in range(3):
            for x in range(3):
                target = front_face[2-x][y]

                new_state[0][y][x].top = target.left
                new_state[0][y][x].right = target.top
                new_state[0][y][x].bottom = target.right
                new_state[0][y][x].left = target.bottom
        self.boxes = new_state

The mistake you made is a little bit hard to explain because I'm not a native english speaker, bit I'll try:

You are moving the information from one box to another in the loop. But in some cases the information in target contains information which already was moved and you move it again.

Upvotes: 2

Related Questions