Rubik's Cube Notebook

Rubik's Cube Notebook


I've been thinking for a while about developing a model to simulate a Rubik's cube in Python. I wanted to make use of object-oriented programming, and this project was the perfect excuse to get down to work.

View and download the code here
Go to the repo


Objectives

Code a Rubiks Cube model using object-oriented programming. The model should provide a user interface to interact with the cube and a render engine to visualize its process.


Object-oriented programming model

I started by developing a centric architecture pattern with an orchestrator class. Then I added a class to generate the mapped cube as a data frame and a 2D visualizer with the unwrapped cube to render the work in progress. Finally, I developed a "Drive" class to apply permutations in the cube.

Although it was not enough with a 2D unwrapped model, I started thinking about a 3D render engine using the Matplotlib library. I choose this library for its ease of use. It was hard to figure out how to update the model in real-time but way worth it.

To develop the model, I defined these four Python classes:

  1. Class App: This class initiates the whole program and acts as an orchestrator calling other classes
  2. Class Cube: This class represents the Rubik's cube model as a Dataframe.
  3. Class Drive: This class maps the permutations and applies moves to the cube.
  4. Class Viz: This class generates 2D and 3D models and renders each representation.

As a graphic support I drew a pattern with the classes, their methods and the calls between the different components in the infographic below.

OOP Rubik's Cube

OOP Rubik's Cube


Cube notation model

Before developing the code, I needed to define how to represent and serialize the data. It was so fun to notate and map the cube.

Naming convention

First, I established a naming convention naming each face by color. I used the same color scheme I have at my physical Rubik's cube, the BOY scheme (blue-orange-yellow).

  • W -> white
  • G -> green
  • O -> Orange
  • B -> Blue
  • R -> Red
  • Y -> Yellow

Faces notation

I am used to solving my Rubik's cube starting on the white face. Therefore, I decided to take this face as the main reference, becoming the front and the center face when unwrapping the cube.

    | R |
| B | W | G | Y |
    | O |

Faces parametrization

Once I assigned the colors to the faces, I named each face square by the initial of its color and the position occupied in the matrix. After this step, I had my model parametrized and ready to roll.

         |R1|R2|R3|
         |R4|R5|R6|
         |R7|R8|R9|
|B1|B2|B3|W1|W2|W3|G1|G2|G3|Y1|Y2|Y3|
|B4|B5|B6|W4|W5|W6|G4|G5|G6|Y4|Y5|Y6|
|B7|B8|B9|W7|W8|W9|G7|G8|G9|Y7|Y8|Y9|
         |O1|O2|O3|
         |O4|O5|O6|
         |O7|O8|O9|

Serialization structure

Last but not least, it was necessary to save the state of the data. To accomplish this, I used a JSON format structure defining keys by their face color and the list of squares of each face as values.

{
  "w": ["w1", "w2", "w3", "w4", "w5", "w6", "w7", "w8", "w9"],
  "r": ["r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9"],
  "g": ["g1", "g2", "g3", "g4", "g5", "g6", "g7", "g8", "g9"],
  "o": ["o1", "o2", "o3", "o4", "o5", "o6", "o7", "o8", "o9"],
  "b": ["b1", "b2", "b3", "b4", "b5", "b6", "b7", "b8", "b9"],
  "y": ["y1", "y2", "y3", "y4", "y5", "y6", "y7", "y8", "y9"]
}


Moves notation

I used the Singmaster notation developed by David Singmaster. Its relative nature allows algorithms to be written in such a way that they can be applied regardless of which side is designated the top or how the colors are organized on a particular cube.

  • t: Top side move 1 clockwise
  • f: Front side move 1 clockwise
  • d: Down side move 1 clockwise
  • r: Right side move 1 clockwise
  • l: Left side move 1 clockwise
  • b: Back side move 1 clockwise

So for example we could apply a combined premutation by doing:

t2l3b1r2
  • t2: Top side move 2 clockwise
  • l3: Left side move 3 clockwise (same as left side move 1 anticlockwise)
  • b1: Back side move 1 clockwise
  • r2: Right side move 2 clockwise


Result

The final output displayed was way faster than I expected. The trick of regenerating the whole geometry for each move works like a charm is capable of applying over a hundred permutations in less than 30 seconds. Here is a capture of the final output applying twenty random moves to the cube.

Rubik's Cube Model

Rubik's Cube RT rendered model



References and links

Una respuesta

  1. Great!! You’re very great!! It’s a good job! Congratulations!!

    Carlos 1 año hace Reply

Leave a Comment