## Yet Another Rubik’s Cube

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:

Rubik’s Cube with VPython.

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 front 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.

This entry was posted in Uncategorized. Bookmark the permalink.

### 2 Responses to Yet Another Rubik’s Cube

1. 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

This site uses Akismet to reduce spam. Learn how your comment data is processed.