Rubik's Cube Simulator in C
Ahh the Rubik's Cube, a 6x3x3 cube game you can read about on Wikipedia. Here I'll be breaking down how I've simulated the game in C. The objective is to model a 3D object in 2D space while also letting users rotate any face either clockwise and counter clockwise.
There are a few things to consider, we need the ability to:
- rotate the 3x3 face
- rotate the 3 cubies on the 4 adjacent edge faces
- keep center cubie fixed
The cube is a 54 byte (6x9) array representing every the color of every face. A finished cube will look like the array below. Every row is a face, columns are locations of cubies on the face, and values are colors.
Rotation works by rotating the face and the adjacent edges. Face rotation is done by applying the mapping below to a specific row i.e. the value at index 0 is moved to 6, 1 to 3, etc. At the moment, counter clockwise rotation is done by repeating this process 3 times.
// rotation matrix
const byte F[] = {6, 3, 0, 7, 4, 1, 8, 5, 2};
Rotating the adjacent edges requires mapping out the 4 edge faces that would be at the top, right, left, and bottom of every face as well as the side of the face that's abutting the edge. The adjacency matrix is where the magic happens. Every row is a face on the cube, the columns signify the top, right, bottom, and right edges in that order.
Three types of information are encoded into a cell of the adjacency matrix:
- the upper portion (
0xF0
) specifies which face it's adjacent too - the lower portion (
0x0F
) specifies:- the abutting face (0 to 3) we're to rotate. This maps to the adjacent edges.
- the orientation, the back face has the opposite rotation vector of the front face and how we iterate through the adjacent edges is reversed. Same is true with left and right face.
// adjacency matrix (face and rotation: T, R, L, B)
const byte X[][4] = {
{0x40, 0x30, 0x20, 0x10}, // U 0000
{0x0A, 0x22, 0x52, 0x49}, // L 1001
{0x0B, 0x32, 0x58, 0x11}, // F 1010
{0x01, 0x4A, 0x59, 0x21}, // R 0110
{0x00, 0x1A, 0x53, 0x39}, // B 0101
{0x13, 0x23, 0x33, 0x43} // D 0000
};
// adjacent edges
const byte E[][4] = {
{0, 1, 2}, // TOP
{2, 5, 8}, // RIGHT
{0, 3, 6}, // LEFT
{6, 7, 8} // BOTTOM
};
Source code is available on github
References:
- Implementing Rubik's Cube: An Exercise in Hybrid Programming http://www.chilton.com/~jimw/rubik.html
- Representing rubik's cube in APL https://dl.acm.org/doi/10.1145/800058.801107