// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // 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 // /// <summary> /// Check if the cube definition string s represents a solvable cube. /// </summary> /// <param name="s"> is the cube definition string , see <seealso cref="Facelet"/> </param> /// <returns> 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 </returns> public static int verify(string s) { int[] count = new int[6]; try { for (int i = 0; i < 54; i++) { count[(int)CubeColor.Parse(typeof(CubeColor), i.ToString())]++; } } catch (Exception) { 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()); }
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // return cube in facelet representation public FaceCube toFaceCube() { FaceCube fcRet = new FaceCube(); foreach (Corner c in (Corner[])Enum.GetValues(typeof(Corner))) { int i = (int)c; int j = (int)cp[i]; // cornercubie with index j is at // cornerposition with index i byte ori = co[i]; // Orientation of this cubie for (int n = 0; n < 3; n++) { fcRet.f[(int)FaceCube.cornerFacelet[i][(n + ori) % 3]] = FaceCube.cornerColor[j][n]; } } foreach (Edge e in (Edge[])Enum.GetValues(typeof(Edge))) { int i = (int)e; int j = (int)ep[i]; // edgecubie with index j is at edgeposition // with index i byte ori = eo[i]; // Orientation of this cubie for (int n = 0; n < 2; n++) { fcRet.f[(int)FaceCube.edgeFacelet[i][(n + ori) % 2]] = FaceCube.edgeColor[j][n]; } } return(fcRet); }
/// <summary> /// Generates a random cube. </summary> /// <returns> A random cube in the string representation. Each cube of the cube space has the same probability. </returns> public static string randomCube() { CubieCube cc = new CubieCube(); System.Random gen = new System.Random(); cc.setFlip((short)gen.Next(CoordCube.N_FLIP)); cc.setTwist((short)gen.Next(CoordCube.N_TWIST)); do { cc.setURFtoDLB(gen.Next(CoordCube.N_URFtoDLB)); cc.setURtoBR(gen.Next(CoordCube.N_URtoBR)); } while ((cc.edgeParity() ^ cc.cornerParity()) != 0); FaceCube fc = cc.toFaceCube(); return(fc.to_fc_String()); }
/** * 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, out string info, int maxDepth = 50, long timeOut = 6000, bool useSeparator = false, bool buildTables = false) { info = "Warning, this solution builds tables at run time which is very slow. This will find a solution, however it is reccomended to use the K_SearchRunTime class only to create a local copy of the tables, then use the K_Search class to search for solutions instead."; if (facelets == "UUUUUUUUURRRRRRRRRFFFFFFFFFDDDDDDDDDLLLLLLLLLBBBBBBBBB") { return(""); } int s; // +++++++++++++++++++++check for wrong input +++++++++++++++++++++++++++++ int[] count = new int[6]; try { for (int i = 0; i < 54; i++) { count[(int)CubeColor.Parse(typeof(CubeColor), facelets.Substring(i, 1))]++; } } catch (Exception) { 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 +++++++++++++++++++++++++++++++++ CoordCubeBuildTables c = new CoordCubeBuildTables(cc, buildTables); //return "lol"; 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; long tStart = DateTimeHelper.CurrentUnixTimeMillis(); // +++++++++++++++++++ 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 (DateTimeHelper.CurrentUnixTimeMillis() - tStart > timeOut << 10) { return("Error 8"); } 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] = CoordCubeBuildTables.flipMove[flip[n], mv]; twist[n + 1] = CoordCubeBuildTables.twistMove[twist[n], mv]; slice[n + 1] = CoordCubeBuildTables.FRtoBR_Move[slice[n] * 24, mv] / 24; minDistPhase1[n + 1] = Math.Max(CoordCubeBuildTables.getPruning(CoordCubeBuildTables.Slice_Flip_Prun, CoordCubeBuildTables.N_SLICE1 * flip[n + 1] + slice[n + 1]), CoordCubeBuildTables.getPruning(CoordCubeBuildTables.Slice_Twist_Prun, CoordCubeBuildTables.N_SLICE1 * twist[n + 1] + slice[n + 1])); // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 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); }
/** * 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, out string info, int maxDepth = 22, long timeOut = 6000, bool useSeparator = false) { if (facelets == "UUUUUUUUURRRRRRRRRFFFFFFFFFDDDDDDDDDLLLLLLLLLBBBBBBBBB") { info = "Already Solved"; return(""); } DateTime startTime = DateTime.Now; info = ""; int s; // +++++++++++++++++++++check for wrong input +++++++++++++++++++++++++++++ int[] count = new int[6]; try { for (int i = 0; i < 54; i++) { count[(int)CubeColor.Parse(typeof(CubeColor), facelets.Substring(i, 1))]++; } } catch (Exception) { 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 +++++++++++++++++++++++++++++++++ string currentTime = "[ a: " + String.Format(@"{0:mm\:ss\.ffff}", (DateTime.Now - startTime)) + " ] "; CoordCube c = new CoordCube(cc, startTime, currentTime, out info); //return "lol"; 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; long tStart = DateTimeHelper.CurrentUnixTimeMillis(); // +++++++++++++++++++ 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 (DateTimeHelper.CurrentUnixTimeMillis() - tStart > timeOut << 10) { return("Error 8"); } 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; minDistPhase1[n + 1] = Math.Max(CoordCube.getPruning(CoordCube.Slice_Flip_Prun, CoordCube.N_SLICE1 * flip[n + 1] + slice[n + 1]), CoordCube.getPruning(CoordCube.Slice_Twist_Prun, CoordCube.N_SLICE1 * twist[n + 1] + slice[n + 1])); // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 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); }