Last week I had a conversation at work about ideas for programming projects for students, and the Rubik’s cube was suggested as one idea. There are many possible approaches to this problem, from merely modeling the cube and allowing a user to manipulate it, to actually *solving* the cube in some automated way.

Part of the context of the discussion was the use of Visual Python for manipulating 3D objects, which I have been using with some success for a couple of months now underneath my robot simulator. To provide an example of how VPython alone might be useful in the classroom, I decided to write a simple model of the Rubik’s cube. I was frankly surprised at just *how* simple this turned out to be; the end result was just a few dozen lines of code, collapsed here (also on GitHub):

""" Press 'F', 'B', 'L', 'R', 'U', 'D' (or lowercase) to rotate the corresponding face clockwise (counterclockwise). """ from vpython import * # Map keypresses to corresponding face colors and rotation axes. faces = {'r': (color.red, (1, 0, 0)), 'l': (color.orange, (-1, 0, 0)), 'u': (color.white, (0, 1, 0)), 'd': (color.yellow, (0, -1, 0)), 'f': (color.green, (0, 0, 1)), 'b': (color.blue, (0, 0, -1))} # Create colored stickers on each face, one cubie at a time. stickers = [] for face_color, axis in faces.values(): for x in (-1, 0, 1): for y in (-1, 0, 1): # Start with all stickers on the top face, then rotate them "down" # to the appropriate face. sticker = box(color=face_color, pos=vec(x, y, 1.5), length=0.98, height=0.98, width=0.05) cos_angle = dot(vec(0, 0, 1), vec(*axis)) pivot = (cross(vec(0, 0, 1), vec(*axis)) if cos_angle == 0 else vec(1, 0, 0)) sticker.rotate(angle=acos(cos_angle), axis=pivot, origin=vec(0, 0, 0)) stickers.append(sticker) scene.lights.append(distant_light(direction=vec(*axis), color=color.gray(0.3))) # Get keyboard moves and rotate the corresponding face. fps = 24 while True: key = scene.waitfor('keydown').key if key.lower() in faces: face_color, axis = faces[key.lower()] angle = ((pi / 2) if key.islower() else -pi / 2) for r in arange(0, angle, angle / fps): rate(fps) for sticker in stickers: if dot(sticker.pos, vec(*axis)) > 0.5: sticker.rotate(angle=angle / fps, axis=vec(*axis), origin=vec(0, 0, 0))

And here is a screenshot:

Much of the user interface comes for free with VPython, including rotating the cube and zooming in/out with the mouse. (Right-click-and-drag to rotate, or right/left-click-and-drag to zoom in or out.) Turn faces by pressing keys using Singmaster notation, using **F** or **f** to rotate the **f**ront face clockwise or counterclockwise, respectively, and so on.

I found this project interesting because the Rubik’s cube and its solution usually involve some group and/or graph theory to represent states of the cube and the moves from one state to another. In this case, however, the implementation is sort of purely geometric: instead of explicitly modeling the permutation of the cubies, we just keep track of the position and orientation of the colored “stickers” on the cubies, so that turning a face of the cube simply corresponds to rotating some 3D objects… which makes smooth animation pretty easy, too.

Of course, this approach has some disadvantages as well. For example, representing the cube this way would probably not be the most suitable for an automated solver. But my initial goal was simply to show the potential bang:buck ratio from using VPython in particular, and Python in general. And I had some fun in the process.

Pingback: Solving the 2x2x2 Rubik’s Cube | Possibly Wrong

Hey, Great program!

I was looking for ideas on coding a working Rubik’s Cube and once I saw your VPython screenshot I knew I could do it. I wasn’t sure I could do it in “just a few dozen lines of code” though. It finally took me a few hundred lines but it was a great exercise! Then I allowed myself to peek at your code and I didn’t feel too bad. You’re way ahead of me in Python. I love how your program rotates the rows and columns in real time.

I wrote a bunch of functions for the rotations which match the algorithmic solutions I’ve seen, so mine might be a good fit for an automatic solver.

Thanks for the lesson!

Peter Farrell

“Hacking Math Class with Python”

http://www.farrellpolymath.com