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:

#!/usr/bin/env python

from visual import *

fps = 24

# Map keypresses to corresponding face colors and normal vectors.
faces = {'r': (color.red, (1, 0, 0)),
         'o': (color.orange, (-1, 0, 0)),
         'y': (color.yellow, (0, 1, 0)),
         'b': (color.blue, (0, -1, 0)),
         'w': (color.white, (0, 0, 1)),
         'g': (color.green, (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=(x, y, 1.5),
                          length=0.98, height=0.98, width=0.05)
            cos_angle = dot((0, 0, 1), axis)
            pivot = (cross((0, 0, 1), axis) if cos_angle == 0 else (1, 0, 0))
            sticker.rotate(angle=acos(cos_angle), axis=pivot, origin=(0, 0, 0))
            stickers.append(sticker)

# Get keyboard moves and rotate the corresponding face.
while True:
    key = scene.kb.getkey()
    if key.lower() in faces:
        face_color, axis = faces[key.lower()]
        angle = ((pi / 2) if key.isupper() else -pi / 2)
        for r in arange(0, angle, angle / fps):
            rate(fps)
            for sticker in stickers:
                if dot(sticker.pos, axis) > 0.5:
                    sticker.rotate(angle=angle / fps, axis=axis,
                                   origin=(0, 0, 0))

And here is a screenshot:

rubik

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.)  My simple approach to specifying moves was to identify each face with the color of its center “cubie,” which does not move.  Press r to rotate the “red” face clockwise, or R to rotate it counterclockwise; similarly for orange, yellow, green, blue, and white.

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. Pingback: Solving the 2x2x2 Rubik’s Cube | Possibly Wrong

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

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s