====== The Rubik's cube 2 by 2 ====== {{ :java:cubo_rubik_2x2.jpg?direct&100 |}} Because I'm not good at all at solving this puzzle, I've decided to give Java an opportunity to solve it for me. So, I've made a program to solve the rubik's cube. If you want to simply run the program, here it is: {{:java:rubik.zip|}} Just uncompress the contents of this zip file and you will find a file called ''rubik.jar''. Run it using the following command: java -jar rubik.jar And you the program will start. Remember that the faces of the cube must be read as if you were reading a text: from left to right, topmost to bottom. And the source code of the project: {{:java:rubik_src.zip|}} ===== My comments ===== The data structure I've choose for the cube is in fact a 4x4 matrix of colors: public class Cube22 implements Cube { private static final int SIDE_SIZE = 2; private static final String nl = System.getProperty("line.separator"); private Color[][][] cube = new Color[SIDE_SIZE+2][SIDE_SIZE+2][SIDE_SIZE+2]; // default constructor: a cube // with all the colors correct public Cube22() { /* * TOP OF THE CUBE * +-+-+-+-+ * | | | | | * +-+-+-+-+ * | |b|b| | * +-+-+-+-+ * | |b|b| | * +-+-+-+-+ * | | | | | * +-+-+-+-+ */ cube[0][0][0] = Color.NOCOLOR; cube[1][0][0] = Color.NOCOLOR; cube[2][0][0] = Color.NOCOLOR; cube[3][0][0] = Color.NOCOLOR; cube[0][1][0] = Color.NOCOLOR; cube[1][1][0] = Color.BLUE; cube[2][1][0] = Color.BLUE; cube[3][1][0] = Color.NOCOLOR; cube[0][2][0] = Color.NOCOLOR; cube[1][2][0] = Color.BLUE; cube[2][2][0] = Color.BLUE; cube[3][2][0] = Color.NOCOLOR; cube[0][3][0] = Color.NOCOLOR; cube[1][3][0] = Color.NOCOLOR; cube[2][3][0] = Color.NOCOLOR; cube[3][3][0] = Color.NOCOLOR; /* * VERTICAL COLORS, 1 * +-+-+-+-+ * | |V|V| | * +-+-+-+-+ * |W| | |Y| * +-+-+-+-+ * |W| | |Y| * +-+-+-+-+ * | |R|R| | * +-+-+-+-+ */ cube[0][0][1] = Color.NOCOLOR; cube[1][0][1] = Color.VIOLET; cube[2][0][1] = Color.VIOLET; cube[3][0][1] = Color.NOCOLOR; cube[0][1][1] = Color.WHITE; cube[1][1][1] = Color.NOCOLOR; cube[2][1][1] = Color.NOCOLOR; cube[3][1][1] = Color.YELLOW; cube[0][2][1] = Color.WHITE; cube[1][2][1] = Color.NOCOLOR; cube[2][2][1] = Color.NOCOLOR; cube[3][2][1] = Color.YELLOW; cube[0][3][1] = Color.NOCOLOR; cube[1][3][1] = Color.RED; cube[2][3][1] = Color.RED; cube[3][3][1] = Color.NOCOLOR; /* * VERTICAL COLORS, 2 * +-+-+-+-+ * | |V|V| | * +-+-+-+-+ * |W| | |Y| * +-+-+-+-+ * |W| | |Y| * +-+-+-+-+ * | |R|R| | * +-+-+-+-+ */ cube[0][0][2] = Color.NOCOLOR; cube[1][0][2] = Color.VIOLET; cube[2][0][2] = Color.VIOLET; cube[3][0][2] = Color.NOCOLOR; cube[0][1][2] = Color.WHITE; cube[1][1][2] = Color.NOCOLOR; cube[2][1][2] = Color.NOCOLOR; cube[3][1][2] = Color.YELLOW; cube[0][2][2] = Color.WHITE; cube[1][2][2] = Color.NOCOLOR; cube[2][2][2] = Color.NOCOLOR; cube[3][2][2] = Color.YELLOW; cube[0][3][2] = Color.NOCOLOR; cube[1][3][2] = Color.RED; cube[2][3][2] = Color.RED; cube[3][3][2] = Color.NOCOLOR; /* * BOTTOM OF THE CUBE * +-+-+-+-+ * | | | | | * +-+-+-+-+ * | |G|G| | * +-+-+-+-+ * | |G|G| | * +-+-+-+-+ * | | | | | * +-+-+-+-+ */ cube[0][0][3] = Color.NOCOLOR; cube[1][0][3] = Color.NOCOLOR; cube[2][0][3] = Color.NOCOLOR; cube[3][0][3] = Color.NOCOLOR; cube[0][1][3] = Color.NOCOLOR; cube[1][1][3] = Color.GREEN; cube[2][1][3] = Color.GREEN; cube[3][1][3] = Color.NOCOLOR; cube[0][2][3] = Color.NOCOLOR; cube[1][2][3] = Color.GREEN; cube[2][2][3] = Color.GREEN; cube[3][2][3] = Color.NOCOLOR; cube[0][3][3] = Color.NOCOLOR; cube[1][3][3] = Color.NOCOLOR; cube[2][3][3] = Color.NOCOLOR; cube[3][3][3] = Color.NOCOLOR; } // Cube22 @Override public Color getColor( int x, int y, int z ) { return cube[x][y][z]; } @Override public void setColor( int x, int y, int z, Color color ) { cube[x][y][z] = color; } @Override public Cube getCopy() { Cube22 result = new Cube22(); for( int x = 0; x < 4; x++ ) for( int y = 0; y < 4; y++ ) for( int z = 0; z < 4; z++ ) { result.setColor(x, y, z, getColor(x, y, z)); } return result; } // getCopy @Override public String toString() { StringBuilder out = new StringBuilder(); out.append( " ____________ " ); out.append( nl ); out.append( " / / /|" ); out.append( nl ); out.append( " / "+Color.toString(cube[1][1][0])+" / "+Color.toString(cube[2][1][0])+" / |" ); out.append( nl ); out.append( " /_____/_____/ "+Color.toString(cube[3][1][1])+"|" ); out.append( nl ); out.append( " / / /| ," ); out.append( nl ); out.append( " / "+Color.toString(cube[1][2][0])+" / "+Color.toString(cube[2][2][0])+" / | /|" ); out.append( nl ); out.append( " /_____/_____/ |/ |" ); out.append( nl ); out.append( " | | |"+Color.toString(cube[3][2][1])+" / "+Color.toString(cube[3][1][2])+"," ); out.append( nl ); out.append( " | "+Color.toString(cube[1][3][1])+" | "+Color.toString(cube[2][3][1])+" | /| / " ); out.append( nl ); out.append( " |_____|_____|/ |/ " ); out.append( nl ); out.append( " | | |"+Color.toString(cube[3][2][2])+" / " ); out.append( nl ); out.append( " | "+Color.toString(cube[1][3][2])+" | "+Color.toString(cube[2][3][2])+" | / " ); out.append( nl ); out.append( " |_____|_____|/ " ); out.append( nl ); return out.toString(); } // toString /** * Return true if the cube is solved, in other words, all the colors * are grouped in the same face of the cube. * * @return */ @Override public boolean isSolved() { boolean facade1; boolean facade2; boolean facade3; boolean facade4; boolean facade5; boolean facade6; facade1 = cube[1][1][0] == cube[2][1][0] && cube[2][1][0] == cube[1][2][0] && cube[1][2][0] == cube[2][2][0]; facade2 = cube[3][2][1] == cube[3][1][1] && cube[3][1][1] == cube[3][1][2] && cube[3][1][2] == cube[3][2][2]; facade3 = cube[1][3][1] == cube[2][3][1] && cube[2][3][1] == cube[1][3][2] && cube[1][3][2] == cube[2][3][2]; facade4 = cube[1][1][3] == cube[2][1][3] && cube[2][1][3] == cube[1][2][3] && cube[1][2][3] == cube[2][2][3]; facade5 = cube[0][2][1] == cube[0][1][1] && cube[0][1][1] == cube[0][1][2] && cube[0][1][2] == cube[0][2][2]; facade6 = cube[1][0][1] == cube[2][0][1] && cube[2][0][1] == cube[1][0][2] && cube[1][0][2] == cube[2][0][2]; return facade1 && facade2 && facade3 && facade4 && facade5 && facade6; } /** * Determine if two cubes are equal regardless of their orientation. * This is important because this, applied to the search algorithm * prevents to explore branches that in fact are the seame than a * previous one but with the colors rotated. * */ @Override public boolean equals( Object comp ) { if( this == comp ) return true; if( comp instanceof Cube22 ) { Cube22 compCube = (Cube22) comp; return equalsXYZ(compCube); } else return false; } // equals public boolean equalsXYZ( Cube compCube ) { boolean equal = true; for( int x = 0; x < SIDE_SIZE+2 && equal; x++ ) for( int y = 0; y < SIDE_SIZE+2 && equal; y++ ) for( int z = 0; z < SIDE_SIZE+2 && equal; z++ ) equal = equal && (cube[x][y][z] == compCube.getColor(x, y, z)); return equal; } // equals } After two days developing (in my spare time) I've realized that it was a wrong decision, because there is a better way to store the cube and allow the rotation operations to be more easy: is to create a ''sticker'' data structure and link the stickers between them. Thus, the operation of rotation of the cube is more easy and less error prone. An idea of what it would be: class Sticker { private Sticker north; private Sticker south; private Sticker east; private Sticker west; private Sticker northCorner; } So, the cube is constructer by linking the respective north, south, east ... links between them. But I think it would be needed to keep a link in order to know the orientation of the cube (to know what is ''up'' and ''down''): because of this is necessary this ''northCorner'', who will be set with a value only with one sticker.