Solving Physical Puzzles with Ruby

Most of the time, challenges I tackle with Ruby solve code-related problems. This includes things like web services, scripts, chatbots, etc., all of which are virtual in some way. Recently though, I decided to solve a puzzle in the real world.

My son was trying to put together a wooden puzzle. It requires having four colors (blue, green, red, and yellow) each present on all four sides of a rectangle. These colors are on wooden cubes that can be rotated. So four cubes, each with six sides to rotate around. It turns out that this means there are a lot of possible combinations of these cubes, most of which won’t work. By my math, there are six sides that can face up (a “y” axis), multiplied by four possible rotations around that axis (6 * 4 = 24) for each cube. Raised to the power of the four cubes (24^4 = 331776). After about 30 minutes of hearing his frustration, I told him “I bet I can solve this puzzle with some code” but he was skeptical.

I took that as a challenge to both my coding skills and his respect for me as his dad, so I obliged. After finishing, I figured it would be worth sharing.

Modeling the Physical World

The first thing I needed to do was figure out how to capture this physical puzzle in code. I started with the individual cubes. Initially, I just decided to layout the cube by counting the sides sequentially (starting at 0, naturally) like this:

Puzzle Cube1

Unwrapped, this looks like:

Puzzle OpenCube1

After imagining a few rotations of a cube I realized that it wasn’t a straightforward way to rotate along both axes. I couldn’t just take an array of the colors for each side and call #rotate on it. Here are what the rotations looked like:

Puzzle Rotations1

Rotations around either axis only result in four faces rotating, leaving the other two stationary. This messes up any simple rotation scheme. But those two stationary sides got me thinking. There’s something special about opposite sides. I realized that I could treat opposite sides as pairs. If you stare at a cube, you can only see three sides at once. By treating opposite sides as pairs, “flipping” between visible and hidden is always a simple 90 degree rotation away.

Here is what the new cube might look like:

Puzzle Cube2

Unwrapped, it is easier to see that opposite sides are “next to each other” when numbered (“0” is opposite “1“, “2” is opposite “3“, and “4” is opposite “5“):

Puzzle OpenCube2

Given this, a switch from “visible” to “hidden” of opposite sides looks like a simple rotation:

Puzzle Rotations2

Hiding side “2” makes side “3” visible and hiding side “0” shows side “1”, no matter which axis we rotate.

Looking at Some Code

With that in mind, let’s dive into some code. First, I modeled the Cube:

Then I took on modeling the Puzzle that held the cubes:

From there, it was a simple matter of constructing the four cubes (listing each side in the proper order) and then solving:

That’s it! The output ends up looking something like this:

Check out the entire solution in this gist. Let me know what you think in the comments!

Spread the love