Example #1
0
string Search::solution(string facelets, int maxDepth, long timeOut, bool useSeparator) {
    int s = 0;
    
    // +++++++++++++++++++++check for wrong input +++++++++++++++++++++++++++++
    int count[6] = {0};
    try {
        for (int i = 0; i < 54; i++)
        {
            switch (facelets[i]) {
                case 'U':
                    count[U]++;
                    break;
                case 'R':
                    count[R]++;
                    break;
                case 'F':
                    count[F]++;
                    break;
                case 'D':
                    count[D]++;
                    break;
                case 'L':
                    count[L]++;
                    break;
                case 'B':
                    count[B]++;
                    break;
                default:
                    break;
            }
        }
    } catch (exception e) {
        return "Error 1";
    }
    for (int i = 0; i < 6; i++)
        if (count[i] != 9)
            return "Error 1";
    
    FaceCube fc = FaceCube(facelets);
    auto_ptr<CubieCube> cc = fc.toCubieCube();
    if ((s = cc->verify()) != 0){
        string result = "Error ";
        result +=  (char)(abs(s)+'0');
        return result;
    }
    
    // +++++++++++++++++++++++ initialization +++++++++++++++++++++++++++++++++
    //---------------------------
    CoordCube c = 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;
    
    struct timeval tv;
    gettimeofday(&tv,NULL);
    
    long tStart = tv.tv_sec * 1000 + tv.tv_usec / 1000;
    
    // +++++++++++++++++++ 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) {
                        
                        gettimeofday(&tv,NULL);
                        
                        if ((tv.tv_sec * 1000 + tv.tv_usec / 1000) - 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] = 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);
}
Example #2
0
/**
 * 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
 */
std::string Search::solution(std::string facelets, int maxDepth, long timeOut, bool useSeparator) {
    int s;

    // +++++++++++++++++++++check for wrong input +++++++++++++++++++++++++++++
    int count[6];
    for (int i = 0; i < 6; ++i)
        count[i] = 0;
    try {
        for (int i = 0; i < 54; i++)
            ++count[FaceCube::charToColor(facelets[i])];
    } catch (...) {
        return "Error 1";
    }
    for (int i = 0; i < 6; i++)
        if (count[i] != 9)
            return "Error 1";

    FaceCube fc(facelets);
    CubieCube cc(fc.toCubieCube());
    if ((s = cc.verify()) != 0) {
        char e[40];
        sprintf(e, "Error %d", abs(s));
        return e;
    }

    // +++++++++++++++++++++++ initialization +++++++++++++++++++++++++++++++++
    CoordCube c(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 = 1, n = 0;
    bool busy = false; // gets set when a move is popped from the stack
    int depthPhase1 = 1;

    clock_t tStart = clock();
    timeOut *= CLOCKS_PER_SEC;

    // +++++++++++++++++++ Main loop ++++++++++++++++++++++++++++++++++++++++++
    do {
        /* Find the next node to test
         * This is an Iterative Deepening A* search (IDA*)
         * which means we are doing a depth first search over and over again
         * with increasing depth limit while pruning branches which would
         * give too many total moves.
         *
         * n is current depth
         * depthPhase1 is current max depth
         * minDistPhase1[n + 1] is the pruning value which gives a lower bound
         * on the moves necessary after the current move
         *
         * the sequence of moves are stored as ax[] and po[] which together represents each move.
         * ax[n] is the axis, 0 to 2
         * po[n] is the power, 1 to 15 (which combination of moves on the axis)
         */
        do { // loop for choice of node while busy
            if ((n + minDistPhase1[n + 1] < depthPhase1) && !busy) {
                // Dig deeper
                // Initialize next move, avoid previous axis
                if (ax[n] != 0)
                    ax[++n] = 0;
                else
                    ax[++n] = 1;
                po[n] = 1;
            } else if (++po[n] > 15) { // increment power
                do {// increment axis
                    if (++ax[n] > 2) {

                        if (clock() - tStart > timeOut)
                            return "Error 8";

                        if (n == 0) {
                            if (depthPhase1 >= maxDepth)
                                return "Error 7";
                            else {
                                // Start over with greater depth
                                depthPhase1++;
                                ax[n] = 0;
                                po[n] = 1;
                                busy = false;
                                break;
                            }
                        } else {
                            // Decrease current depth
                            n--;
                            busy = true;
                            break;
                        }

                    } else {
                        po[n] = 1;
                        busy = false;
                    }
                } while (n != 0 && (ax[n - 1] == ax[n]));
            } else
                busy = false;
        } while (busy);

        // +++++++++++++ compute new coordinates and new minDistPhase1 ++++++++++
        // if minDistPhase1 =0, the H subgroup is reached
        mv = 16 * ax[n] + po[n];
        if (mv > CoordCube::N_MOVE)
            printf("n: %d ax[n]: %d po[n]: %d mv: %d ", n, ax[n], po[n], mv);
        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] = std::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);
}