I am creating a project in C# that solves Rubiks Cubes. It will take the current state of the Rubiks Cube in as an input, and output a series of moves to perform to solve the cube using the designated notation.
The Cube is represented by an array of 6 string arrays of length 9:
private string[,] CubeState = new string[6,9] {
{ "WHITE", "WHITE", "WHITE", "WHITE", "WHITE", "WHITE", "WHITE", "WHITE", "WHITE"},
{ "BLUE", "BLUE", "BLUE", "BLUE", "BLUE", "BLUE", "BLUE", "BLUE", "BLUE"},
{ "RED", "RED", "RED", "RED", "RED", "RED", "RED", "RED", "RED"},
{ "GREEN", "GREEN", "GREEN", "GREEN", "GREEN", "GREEN", "GREEN", "GREEN", "GREEN"},
{ "ORANGE", "ORANGE", "ORANGE", "ORANGE", "ORANGE", "ORANGE", "ORANGE", "ORANGE", "ORANGE"},
{ "YELLOW", "YELLOW", "YELLOW", "YELLOW", "YELLOW", "YELLOW", "YELLOW", "YELLOW", "YELLOW" } };
I have created an excel spreadsheet to represent each of the faces
You can imagine this as a net that folds together to create the cube.
Since I am using a console application and not a windows forms application, I have to represent the cube by writing each face to the console beneath each other. I do this using the following method PrintCube()
:
public void PrintCube()
{
for (int i = 0; i < 6; i++)
{
for (int j = 0; j < 9; j++)
{
Console.Write("--" + CubeState[i,j]);
if (j % 3 == 2 && j != 0)
{
Console.Write("\r\n");
}
}
Console.WriteLine("\r\n");
}
}
This makes the standard output of the solved cube this:
Currently, I am at the stage of coding each different moves that can be performed on the cube, but I have hit a snag.
Here is the code that performs operations:
public void PerformOperation(CubeOperations operation)
{
string[,] newCubeState = CubeState;
string tempString;
switch (operation)
{
case CubeOperations.F:
for (int i = 6; i < 9; i++)
{
// Test 1
tempString = CubeState[4, (3 * (i - 6)) + 2];
newCubeState[4, (3 * (i - 6)) + 2] = CubeState[3, i - 6]; //258 012
newCubeState[3, i - 6] = CubeState[2, 3 * (i - 6)]; //012 036
newCubeState[2, 3 * (i - 6)] = CubeState[1, i]; //036 678
newCubeState[1, i] = tempString; //678 258
// Test 2
/*newCubeState[1, i] = CubeState[4, i];
newCubeState[2, i] = CubeState[1, i];
newCubeState[3, i] = CubeState[2, i];
newCubeState[4, i] = CubeState[3, i];*/
}
RotateFaceRight(newCubeState, Rubiks_Cube_Solver.CubeCenters.WHITE);
break;
case CubeOperations.R:
for (int i = 2; i < 9; i += 3)
{
// Test 1
tempString = CubeState[3, i];
newCubeState[3, i] = CubeState[5, 8 - i]; //258 630
newCubeState[5, i - 2] = CubeState[1, 10 - i]; //036 852
newCubeState[1, i] = CubeState[0, i]; //258 258
newCubeState[0, i] = tempString; //258 258
// Test 2
/*newCubeState[0, i] = CubeState[3, i];
newCubeState[1, i] = CubeState[0, i];
newCubeState[5, i] = CubeState[1, i - 2];
newCubeState[3, i - 2] = CubeState[5, i];*/
}
RotateFaceRight(newCubeState, Rubiks_Cube_Solver.CubeCenters.RED);
break;
case CubeOperations.U:
break;
case CubeOperations.L:
break;
case CubeOperations.B:
break;
case CubeOperations.D:
break;
case CubeOperations.FPRIME:
break;
case CubeOperations.RPRIME:
break;
case CubeOperations.UPRIME:
break;
case CubeOperations.LPRIME:
break;
case CubeOperations.BPRIME:
break;
case CubeOperations.DPRIME:
break;
case CubeOperations.F2:
break;
case CubeOperations.R2:
break;
case CubeOperations.U2:
break;
case CubeOperations.L2:
break;
case CubeOperations.B2:
break;
case CubeOperations.D2:
break;
default:
break;
}
CubeState = newCubeState;
}
I am coding the operations sequentially and, as such, have only completed the F operation as of right now, but I cannot for the life of me figure out where I am going wrong on the R operation.
In Rubik's Cube notation, we see that the operation R on a solved cube, starting on the white face outwards and a blue face on top, denotes the following movement:
Hold the cube with the white face out, and the blue face on top.
Twist the red face 90 degrees clockwise, such that the right-hand side of the white face moves onto the blue face, the green onto the white, the yellow onto the green and the blue onto the yellow.
Doing these two steps results in an R operation.
To see what we need to do in code for this to happen, let's return to the excel spreadsheet.
Starting with the white side, we can see that we must change:
- indexes 2, 5 and 8 of the White face to indexes 2, 5 and 8 on the Green face.
- indexes 2, 5 and 8 of the Blue face to indexes*2, 5 and 8* respectively on the White Face
- When we get to the Yellow face, however, since the face in the net must "flip" around to connect the orange, blue, green and red faces, we must change indexes 0, 3 and 6. These each change to indexes 8, 5 and 2 on the Blue face respectively. It is easier to think about why this is true if you have a cube in front of you
- On the Green face, we change indexes 2, 5 and 8 to indexes 6, 3 and 0 on the Yellow face. Again, this is because of how we interpret the net.
Zooming in on the code for Operation R, we can see how I achieve this:
case CubeOperations.R:
for (int i = 2; i < 9; i += 3)
{
//Test 1
tempString = CubeState[3, i];
newCubeState[3, i] = CubeState[5, 8 - i]; //258 630
newCubeState[5, i - 2] = CubeState[1, 10 - i]; //036 852
newCubeState[1, i] = CubeState[0, i]; //258 258
newCubeState[0, i] = tempString; //258 258
// Test 2
/*newCubeState[0, i] = CubeState[3, i];
newCubeState[1, i] = CubeState[0, i];
newCubeState[5, i] = CubeState[1, i - 2];
newCubeState[3, i - 2] = CubeState[5, i];*/
}
I have comments next to each line that states the change taking place, where //258 630
denotes that the face denoted by newCubeState
has indexes 2, 5 and 8 changed to what was on the face denoted by CubeState
's indexes 6, 3 and 0 respectively.
As seen by the 2d array above, we can see that the first index represents the face becoming [0] = "WHITE", [1] = "BLUE", [2] = "RED",[3] = "GREEN", [4] = "ORANGE", [5] = "YELLOW"
Knowing this, we can interpret my code like this:
First, the 2nd index on the Green face becomes the 6th index on the Yellow face. [GREEN -> YELLOW]
Second, the 0th index on the Yellow face becomes the 8th index on the Blue Face [YELLOW -> BLUE]
Third, the 2nd index on the Blue face becomes the 2nd index on the White face. [BLUE -> WHITE]
Fourth, the 2nd index on the White face becomes the 2nd index on the Green face. [WHITE-> GREEN]
Note that for some strange reason, even though they are completely separate variables, it seems to affect CubeState[x,y]
when I set newCubeState[i,j] = CubeState[x, y]
, as such, I need to use an index before it is changed, which leads to needing the temporary variable tempString
, however, that is not the issue at hand here.
Fifth, the 5th index on the Green face becomes the 3rd index on the Yellow face. [GREEN -> YELLOW]
Sixth, the 3rd index on the Yellow face becomes the 5th index on the Blue Face [YELLOW -> BLUE]
Seventh, the 5th index on the Blue face becomes the 5th index on the White face. [BLUE -> WHITE]
Eighth, the 5th index on the White face becomes the 5th index on the Green face. [WHITE-> GREEN]
Ninth, the 8th index on the Green face becomes the 0th index on the Yellow face. [GREEN -> YELLOW]
Tenth, the 6th index on the Yellow face becomes the 2nd index on the Blue Face [YELLOW -> BLUE]
Eleventh, the 8th index on the Blue face becomes the 8th index on the White face. [BLUE -> WHITE]
Twelfth, the 8th index on the White face becomes the 8th index on the Green face. [WHITE-> GREEN]
This should result in the following output:
WHITE - WHITE - GREEN
WHITE - WHITE - GREEN
WHITE - WHITE - GREEN
BLUE - BLUE - WHITE
BLUE - BLUE - WHITE
BLUE - BLUE - WHITE
RED - RED - RED
RED - RED - RED
RED - RED - RED
GREEN - GREEN - YELLOW
GREEN - GREEN - YELLOW
GREEN - GREEN - YELLOW
ORANGE - ORANGE - ORANGE
ORANGE - ORANGE - ORANGE
ORANGE - ORANGE - ORANGE
BLUE - YELLOW - YELLOW
BLUE - YELLOW - YELLOW
BLUE - YELLOW - YELLOW
However, we see that this is not the case:
For some strange reason, we see that the 8th index on the 3rd face (GREEN) becomes BLUE instead of YELLOW, as well as the 6th index on the 5th face (YELLOW), becoming the WHITE instead of BLUE.
I have no clue why this happens, I would much appreciate help with this.
It shouldn't be causing any problems, but here is my RotateFaceRight()
method:
private void RotateFaceRight(string[,] cube, CubeCenters faceCenterColour)
{
string[] face = new string[9];
int faceNumber = (int)faceCenterColour;
for (int i = 0; i < 9; i++)
{
face[i] = cube[(int)faceCenterColour, i];
}
/*
* 012 -> 630
* 345 -> 741
* 678 -> 852
*/
cube[faceNumber, 0] = face[6];
cube[faceNumber, 1] = face[3];
cube[faceNumber, 2] = face[0];
cube[faceNumber, 3] = face[7];
cube[faceNumber, 4] = face[4];
cube[faceNumber, 5] = face[1];
cube[faceNumber, 6] = face[8];
cube[faceNumber, 7] = face[5];
cube[faceNumber, 8] = face[2];
}
The rest of my code is here:
Cube.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Rubiks_Cube_Solver
{
class Cube
{
private string[,] CubeState = new string[6, 9] {
{ "WHITE", "WHITE", "WHITE", "WHITE", "WHITE", "WHITE", "WHITE", "WHITE", "WHITE"},
{ "BLUE", "BLUE", "BLUE", "BLUE", "BLUE", "BLUE", "BLUE", "BLUE", "BLUE"},
{ "RED", "RED", "RED", "RED", "RED", "RED", "RED", "RED", "RED"},
{ "GREEN", "GREEN", "GREEN", "GREEN", "GREEN", "GREEN", "GREEN", "GREEN", "GREEN"},
{ "ORANGE", "ORANGE", "ORANGE", "ORANGE", "ORANGE", "ORANGE", "ORANGE", "ORANGE", "ORANGE"},
{ "YELLOW", "YELLOW", "YELLOW", "YELLOW", "YELLOW", "YELLOW", "YELLOW", "YELLOW", "YELLOW" } };
private readonly string[] CubeCenters = new string[] { "WHITE", "BLUE", "RED", "GREEN", "ORANGE", "YELLOW" };
private readonly string[] CubeSides = new string[] { "FRONT", "TOP", "RIGHT", "BOTTOM", "LEFT", "BACK" };
public Cube()
{
}
public void PerformOperation(CubeOperations operation)
{
string[,] newCubeState = CubeState;
string tempString;
switch (operation)
{
//Console.WriteLine("{0} -> {1}\nOld Face: {2} Old Item: {3}\nNew Face: {4} New Item: {5}\n\n", newCubeState[3, i], CubeState[5, 8 - i], 5, (8 - i), 3, (i));
case CubeOperations.F:
for (int i = 6; i < 9; i++)
{
// Test 1
tempString = CubeState[4, (3 * (i - 6)) + 2];
newCubeState[4, (3 * (i - 6)) + 2] = CubeState[3, i - 6]; //258 012
newCubeState[3, i - 6] = CubeState[2, 3 * (i - 6)]; //012 036
newCubeState[2, 3 * (i - 6)] = CubeState[1, i]; //036 678
newCubeState[1, i] = tempString; //678 258
// Test 2
/*newCubeState[1, i] = CubeState[4, i];
newCubeState[2, i] = CubeState[1, i];
newCubeState[3, i] = CubeState[2, i];
newCubeState[4, i] = CubeState[3, i];*/
}
RotateFaceRight(newCubeState, Rubiks_Cube_Solver.CubeCenters.WHITE);
break;
case CubeOperations.R:
for (int i = 2; i < 9; i += 3)
{
// Test 1
tempString = CubeState[3, i];
newCubeState[3, i] = CubeState[5, 8 - i]; //258 630
newCubeState[5, i - 2] = CubeState[1, 10 - i]; //036 852
newCubeState[1, i] = CubeState[0, i]; //258 258
newCubeState[0, i] = tempString; //258 258
// Test 2
/*newCubeState[0, i] = CubeState[3, i];
newCubeState[1, i] = CubeState[0, i];
newCubeState[5, i] = CubeState[1, i - 2];
newCubeState[3, i - 2] = CubeState[5, i];*/
}
RotateFaceRight(newCubeState, Rubiks_Cube_Solver.CubeCenters.RED);
break;
case CubeOperations.U:
for (int i = 0; i < 3; i++)
{
// Test 1
tempString = CubeState[4, i];
newCubeState[4, i] = CubeState[0, i]; //012 012
newCubeState[0, i] = CubeState[2, i]; //012 012
newCubeState[2, i] = CubeState[5, i]; //012 012
newCubeState[5, i] = tempString; //012 012
// Test 2
/*newCubeState[0, i] = CubeState[2, i];
newCubeState[2, i] = CubeState[5, i];
newCubeState[5, i] = CubeState[4, i];
newCubeState[4, i] = CubeState[0, i];*/
}
RotateFaceRight(newCubeState, Rubiks_Cube_Solver.CubeCenters.BLUE);
break;
case CubeOperations.L:
for (int i = 0; i < 7; i += 3)
{
// Test 1
tempString = CubeState[0, i];
newCubeState[0, i] = CubeState[1, i]; //036 036
newCubeState[1, i] = CubeState[5, i + 2]; //036 258
newCubeState[5, i + 2] = CubeState[3, i]; //258 036
newCubeState[3, i] = tempString; //036 036
// Test 2
/*newCubeState[0, i] = CubeState[1, i];
newCubeState[1, i] = CubeState[5, i];
newCubeState[5, i] = CubeState[3, i];
newCubeState[3, i] = CubeState[0, i];*/
}
RotateFaceRight(newCubeState, Rubiks_Cube_Solver.CubeCenters.ORANGE);
break;
case CubeOperations.B:
for (int i = 0; i < 3; i++)
{
// Test 1
tempString = CubeState[1, i];
newCubeState[1, i] = CubeState[2, (i * 3) + 2]; //012 258
newCubeState[2, (i * 3) + 2] = CubeState[3, i + 6]; //258 678
newCubeState[3, i + 6] = CubeState[4, (i * 3)]; //678 036
newCubeState[4, (i * 3)] = tempString; //036 012
// Test 2
/*newCubeState[1, i] = CubeState[2, i];
newCubeState[2, i] = CubeState[3, i];
newCubeState[3, i] = CubeState[4, i];
newCubeState[4, i] = CubeState[1, i];*/
}
RotateFaceRight(newCubeState, Rubiks_Cube_Solver.CubeCenters.YELLOW);
break;
case CubeOperations.D:
for (int i = 6; i < 9; i++)
{
// Test 1
tempString = CubeState[2, i];
newCubeState[2, i] = CubeState[0, i]; //678 678
newCubeState[0, i] = CubeState[4, i]; //678 678
newCubeState[4, i] = CubeState[5, i]; //678 678
newCubeState[5, i] = tempString; //678 678
// Test 2
/*newCubeState[0, i] = CubeState[4, i];
newCubeState[2, i] = CubeState[0, i];
newCubeState[5, i] = CubeState[2, i];
newCubeState[4, i] = CubeState[5, i];*/
}
RotateFaceRight(newCubeState, Rubiks_Cube_Solver.CubeCenters.GREEN);
break;
case CubeOperations.FPRIME:
break;
case CubeOperations.RPRIME:
break;
case CubeOperations.UPRIME:
break;
case CubeOperations.LPRIME:
break;
case CubeOperations.BPRIME:
break;
case CubeOperations.DPRIME:
break;
case CubeOperations.F2:
break;
case CubeOperations.R2:
break;
case CubeOperations.U2:
break;
case CubeOperations.L2:
break;
case CubeOperations.B2:
break;
case CubeOperations.D2:
break;
default:
break;
}
CubeState = newCubeState;
}
private void RotateFaceRight(string[,] cube, CubeCenters faceCenterColour)
{
string[] face = new string[9];
int faceNumber = (int)faceCenterColour;
for (int i = 0; i < 9; i++)
{
face[i] = cube[(int)faceCenterColour, i];
}
/*
* 012 -> 630
* 345 -> 741
* 678 -> 852
*/
cube[faceNumber, 0] = face[6];
cube[faceNumber, 1] = face[3];
cube[faceNumber, 2] = face[0];
cube[faceNumber, 3] = face[7];
cube[faceNumber, 4] = face[4];
cube[faceNumber, 5] = face[1];
cube[faceNumber, 6] = face[8];
cube[faceNumber, 7] = face[5];
cube[faceNumber, 8] = face[2];
}
public void PrintCube()
{
for (int i = 0; i < 6; i++)
{
for (int j = 0; j < 9; j++)
{
Console.Write("--" + CubeState[i, j]);
if (j % 3 == 2 && j != 0)
{
Console.Write("\r\n");
}
}
Console.WriteLine("\r\n");
}
}
}
}
CubeCenters.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Rubiks_Cube_Solver
{
enum CubeCenters
{
WHITE,
BLUE,
RED,
GREEN,
ORANGE,
YELLOW
}
}
CubeOperations.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Rubiks_Cube_Solver
{
enum CubeOperations
{
F,
R,
U,
L,
B,
D,
FPRIME,
RPRIME,
UPRIME,
LPRIME,
BPRIME,
DPRIME,
F2,
R2,
U2,
L2,
B2,
D2
}
}
Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Rubiks_Cube_Solver
{
class Program
{
static void Main(string[] args)
{
Cube cube = new Cube();
cube.PerformOperation(CubeOperations.R);
cube.PrintCube();
Console.ReadLine();
}
}
}