// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // Check if the cube string s represents a solvable cube. // 0: Cube is solvable // -1: There is not exactly one facelet of each colour // -2: Not all 12 edges exist exactly once // -3: Flip error: One edge has to be flipped // -4: Not all corners exist exactly once // -5: Twist error: One corner has to be twisted // -6: Parity error: Two corners or two edges have to be exchanged // /** * Check if the cube definition string s represents a solvable cube. * * @param s is the cube definition string , see {@link Facelet} * @return 0: Cube is solvable<br> * -1: There is not exactly one facelet of each colour<br> * -2: Not all 12 edges exist exactly once<br> * -3: Flip error: One edge has to be flipped<br> * -4: Not all 8 corners exist exactly once<br> * -5: Twist error: One corner has to be twisted<br> * -6: Parity error: Two corners or two edges have to be exchanged */ public static int verify(String s) { int[] count = new int[6]; try { for (int i = 0; i < 54; i++) { Color col; if (!Enum.TryParse(s.Substring(i, 1), out col)) { throw new Exception("Invalid color"); } count[(int)col]++; } } catch (Exception e) { return(-1); } for (int i = 0; i < 6; i++) { if (count[i] != 9) { return(-1); } } FaceCube fc = new FaceCube(s); CubieCube cc = fc.toCubieCube(); return(cc.verify()); }
/** * Computes the solver string for a given cube. * * @param facelets * is the cube definition string, see {@link Facelet} for the format. * * @param maxDepth * defines the maximal allowed maneuver length. For random cubes, a maxDepth of 21 usually will return a * solution in less than 0.5 seconds. With a maxDepth of 20 it takes a few seconds on average to find a * solution, but it may take much longer for specific cubes. * *@param timeOut * defines the maximum computing time of the method in seconds. If it does not return with a solution, it returns with * an error code. * * @param useSeparator * determines if a " . " separates the phase1 and phase2 parts of the solver string like in F' R B R L2 F . * U2 U D for example.<br> * @return The solution string or an error code:<br> * Error 1: There is not exactly one facelet of each colour<br> * Error 2: Not all 12 edges exist exactly once<br> * Error 3: Flip error: One edge has to be flipped<br> * Error 4: Not all corners exist exactly once<br> * Error 5: Twist error: One corner has to be twisted<br> * Error 6: Parity error: Two corners or two edges have to be exchanged<br> * Error 7: No solution exists for the given maxDepth<br> * Error 8: Timeout, no solution within given time */ public static String solution(String facelets, int maxDepth, bool useSeparator) { int s; // +++++++++++++++++++++check for wrong input +++++++++++++++++++++++++++++ int[] count = new int[6]; try { for (int i = 0; i < 54; i++) { Color col; if (!Enum.TryParse(facelets.Substring(i, 1), out col)) { throw new Exception("Invalid color"); } count[(int)col]++; } } catch (Exception e) { return("Error 1"); } for (int i = 0; i < 6; i++) { if (count[i] != 9) { return("Error 1"); } } FaceCube fc = new FaceCube(facelets); CubieCube cc = fc.toCubieCube(); if ((s = cc.verify()) != 0) { return("Error " + Math.Abs(s)); } // +++++++++++++++++++++++ initialization +++++++++++++++++++++++++++++++++ CoordCube c = new CoordCube(cc); po[0] = 0; ax[0] = 0; flip[0] = c.flip; twist[0] = c.twist; parity[0] = c.parity; slice[0] = c.FRtoBR / 24; URFtoDLF[0] = c.URFtoDLF; FRtoBR[0] = c.FRtoBR; URtoUL[0] = c.URtoUL; UBtoDF[0] = c.UBtoDF; minDistPhase1[1] = 1;// else failure for depth=1, n=0 int mv = 0, n = 0; bool busy = false; int depthPhase1 = 1; // +++++++++++++++++++ Main loop ++++++++++++++++++++++++++++++++++++++++++ do { do { if ((depthPhase1 - n > minDistPhase1[n + 1]) && !busy) { if (ax[n] == 0 || ax[n] == 3)// Initialize next move { ax[++n] = 1; } else { ax[++n] = 0; } po[n] = 1; } else if (++po[n] > 3) { do {// increment axis if (++ax[n] > 5) { if (n == 0) { if (depthPhase1 >= maxDepth) { return("Error 7"); } else { depthPhase1++; ax[n] = 0; po[n] = 1; busy = false; break; } } else { n--; busy = true; break; } } else { po[n] = 1; busy = false; } } while (n != 0 && (ax[n - 1] == ax[n] || ax[n - 1] - 3 == ax[n])); } else { busy = false; } } while (busy); // +++++++++++++ compute new coordinates and new minDistPhase1 ++++++++++ // if minDistPhase1 =0, the H subgroup is reached mv = 3 * ax[n] + po[n] - 1; flip[n + 1] = CoordCube.flipMove[flip[n], mv]; twist[n + 1] = CoordCube.twistMove[twist[n], mv]; slice[n + 1] = CoordCube.FRtoBR_Move[slice[n] * 24, mv] / 24; sbyte[] table = CoordCube.Slice_Flip_Prun; int index = CoordCube.N_SLICE1 * flip[n + 1] + slice[n + 1]; sbyte[] table1 = CoordCube.Slice_Twist_Prun; int index1 = CoordCube.N_SLICE1 * twist[n + 1] + slice[n + 1]; minDistPhase1[n + 1] = Math.Max((index % 2 == 0) ? (table[index >> 1] & 0x0f) : ((table[index >> 1] & 0xf0) >> 4), (index1 % 2 == 0) ? (table1[index1 >> 1] & 0x0f) : ((table1[index1 >> 1] & 0xf0) >> 4)); // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ if (minDistPhase1[n + 1] == 0 && n >= depthPhase1 - 5) { minDistPhase1[n + 1] = 10;// instead of 10 any value >5 is possible if (n == depthPhase1 - 1 && (s = totalDepth(depthPhase1, maxDepth)) >= 0) { if (s == depthPhase1 || (ax[depthPhase1 - 1] != ax[depthPhase1] && ax[depthPhase1 - 1] != ax[depthPhase1] + 3)) { return(useSeparator ? solutionToString(s, depthPhase1) : solutionToString(s)); } } } } while (true); }