Example #1
0
    def solution(self, facelets, maxDepth, timeOut, useSeparator):
        """
        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
        """

        # +++++++++++++++++++++check for wrong input +++++++++++++++++++++++++++++
        count = [0] * 6
        try:
            for i in xrange(54):
                assert facelets[i] in colors
                count[colors[facelets[i]]] += 1
        except Exception as e:
            return "Error 1"

        for i in xrange(6):
            if count[i] != 9:
                return "Error 1"

        fc = FaceCube(facelets)
        cc = fc.toCubieCube()
        s = cc.verify()
        if s != 0:
            return "Error %s" % abs(s)

        # +++++++++++++++++++++++ initialization +++++++++++++++++++++++++++++++++
        c = CoordCube(cc)

        self.po[0] = 0
        self.ax[0] = 0
        self.flip[0] = c.flip
        self.twist[0] = c.twist
        self.parity[0] = c.parity
        self.slice[0] = c.FRtoBR / 24
        self.URFtoDLF[0] = c.URFtoDLF
        self.FRtoBR[0] = c.FRtoBR
        self.URtoUL[0] = c.URtoUL
        self.UBtoDF[0] = c.UBtoDF

        self.minDistPhase1[1] = 1  # else failure for depth=1, n=0
        mv = 0
        n = 0
        busy = False
        depthPhase1 = 1

        tStart = time.time()

        # +++++++++++++++++++ Main loop ++++++++++++++++++++++++++++++++++++++++++
        while True:
            while True:
                if depthPhase1 - n > self.minDistPhase1[n + 1] and not busy:
                    if self.ax[n] == 0 and self.ax[
                            n] == 3:  # Initialize next move
                        n += 1
                        self.ax[n] = 1
                    else:
                        n += 1
                        self.ax[n] = 0
                    self.po[n] = 1
                else:
                    self.po[n] += 1
                    if self.po[n] > 3:
                        while True:
                            # increment axis
                            self.ax[n] += 1
                            if self.ax[n] > 5:

                                if time.time() - tStart > timeOut:
                                    return "Error 8"

                                if n == 0:
                                    if depthPhase1 >= maxDepth:
                                        return "Error 7"
                                    else:
                                        depthPhase1 += 1
                                        self.ax[n] = 0
                                        self.po[n] = 1
                                        busy = False
                                        break
                                else:
                                    n -= 1
                                    busy = True
                                    break

                            else:
                                self.po[n] = 1
                                busy = False

                            if not (n != 0 and
                                    (self.ax[n - 1] == self.ax[n]
                                     or self.ax[n - 1] - 3 == self.ax[n])):
                                break
                    else:
                        busy = False
                if not busy:
                    break

            # +++++++++++++ compute new coordinates and new minDistPhase1 ++++++++++
            # if minDistPhase1 =0, the H subgroup is reached
            mv = 3 * self.ax[n] + self.po[n] - 1
            self.flip[n + 1] = CoordCube.flipMove[self.flip[n]][mv]
            self.twist[n + 1] = CoordCube.twistMove[self.twist[n]][mv]
            self.slice[n +
                       1] = CoordCube.FRtoBR_Move[self.slice[n] * 24][mv] / 24
            self.minDistPhase1[n + 1] = max(
                getPruning(
                    CoordCube.Slice_Flip_Prun,
                    CoordCube.N_SLICE1 * self.flip[n + 1] + self.slice[n + 1]),
                getPruning(
                    CoordCube.Slice_Twist_Prun,
                    CoordCube.N_SLICE1 * self.twist[n + 1] +
                    self.slice[n + 1]))
            # ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

            if self.minDistPhase1[n + 1] == 0 and n >= depthPhase1 - 5:
                self.minDistPhase1[
                    n + 1] = 10  # instead of 10 any value >5 is possible
                if n == depthPhase1 - 1:
                    s = self.totalDepth(depthPhase1, maxDepth)
                    if s >= 0:
                        if (s == depthPhase1 or
                            (self.ax[depthPhase1 - 1] != self.ax[depthPhase1]
                             and self.ax[depthPhase1 - 1] !=
                             self.ax[depthPhase1] + 3)):
                            return self.solutionToString(
                                s, depthPhase1
                            ) if useSeparator else self.solutionToString(s)
Example #2
0
    def solution(self, facelets, maxDepth, timeOut, useSeparator):
        """
        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
        """

        # +++++++++++++++++++++check for wrong input +++++++++++++++++++++++++++++
        count = [0] * 6
        try:
            for i in xrange(54):
                assert facelets[i] in colors
                count[colors[facelets[i]]] += 1
        except Exception as e:
            return "Error 1"

        for i in xrange(6):
            if count[i] != 9:
                return "Error 1"

        fc = FaceCube(facelets)
        cc = fc.toCubieCube()
        s = cc.verify()
        if s != 0:
            return "Error %s" % abs(s)

        # +++++++++++++++++++++++ initialization +++++++++++++++++++++++++++++++++
        c = CoordCube(cc)

        self.po[0] = 0
        self.ax[0] = 0
        self.flip[0] = c.flip
        self.twist[0] = c.twist
        self.parity[0] = c.parity
        self.slice[0] = c.FRtoBR / 24
        self.URFtoDLF[0] = c.URFtoDLF
        self.FRtoBR[0] = c.FRtoBR
        self.URtoUL[0] = c.URtoUL
        self.UBtoDF[0] = c.UBtoDF

        self.minDistPhase1[1] = 1   # else failure for depth=1, n=0
        mv = 0
        n = 0
        busy = False
        depthPhase1 = 1

        tStart = time.time()

        # +++++++++++++++++++ Main loop ++++++++++++++++++++++++++++++++++++++++++
        while True:
            while True:
                if depthPhase1 - n > self.minDistPhase1[n + 1] and not busy:
                    if self.ax[n] == 0 and self.ax[n] == 3:   # Initialize next move
                        n += 1
                        self.ax[n] = 1
                    else:
                        n += 1
                        self.ax[n] = 0
                    self.po[n] = 1
                else:
                    self.po[n] += 1
                    if self.po[n] > 3:
                        while True:
                            # increment axis
                            self.ax[n] += 1
                            if self.ax[n] > 5:

                                if time.time() - tStart > timeOut:
                                    return "Error 8"

                                if n == 0:
                                    if depthPhase1 >= maxDepth:
                                        return "Error 7"
                                    else:
                                        depthPhase1 += 1
                                        self.ax[n] = 0
                                        self.po[n] = 1
                                        busy = False
                                        break
                                else:
                                    n -= 1
                                    busy = True
                                    break

                            else:
                                self.po[n] = 1
                                busy = False

                            if not (n != 0 and (self.ax[n - 1] == self.ax[n] or self.ax[n - 1] - 3 == self.ax[n])):
                                break
                    else:
                        busy = False
                if not busy:
                    break

            # +++++++++++++ compute new coordinates and new minDistPhase1 ++++++++++
            # if minDistPhase1 =0, the H subgroup is reached
            mv = 3 * self.ax[n] + self.po[n] - 1
            self.flip[n + 1] = CoordCube.flipMove[self.flip[n]][mv]
            self.twist[n + 1] = CoordCube.twistMove[self.twist[n]][mv]
            self.slice[n + 1] = CoordCube.FRtoBR_Move[self.slice[n] * 24][mv] / 24
            self.minDistPhase1[n + 1] = max(
                getPruning(
                    CoordCube.Slice_Flip_Prun,
                    CoordCube.N_SLICE1 * self.flip[n + 1] + self.slice[n + 1]
                ),
                getPruning(
                    CoordCube.Slice_Twist_Prun,
                    CoordCube.N_SLICE1 * self.twist[n + 1] + self.slice[n + 1]
                )
            )
            # ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

            if self.minDistPhase1[n + 1] == 0 and n >= depthPhase1 - 5:
                self.minDistPhase1[n + 1] = 10  # instead of 10 any value >5 is possible
                if n == depthPhase1 - 1:
                    s = self.totalDepth(depthPhase1, maxDepth)
                    if s >= 0:
                        if (s == depthPhase1
                            or (
                                self.ax[depthPhase1 - 1] != self.ax[depthPhase1]
                                and self.ax[depthPhase1 - 1] != self.ax[depthPhase1] + 3)):
                            return self.solutionToString(s, depthPhase1) if useSeparator else self.solutionToString(s)
Example #3
0
    def totalDepth(self, depthPhase1, maxDepth):
        """
        Apply phase2 of algorithm and return the combined phase1 and phase2 depth. In phase2, only the moves
        U,D,R2,F2,L2 and B2 are allowed.
        """

        mv = 0
        d1 = 0
        d2 = 0
        maxDepthPhase2 = min(10, maxDepth -
                             depthPhase1)  # Allow only max 10 moves in phase2
        for i in xrange(depthPhase1):
            mv = 3 * self.ax[i] + self.po[i] - 1
            self.URFtoDLF[i +
                          1] = CoordCube.URFtoDLF_Move[self.URFtoDLF[i]][mv]
            self.FRtoBR[i + 1] = CoordCube.FRtoBR_Move[self.FRtoBR[i]][mv]
            self.parity[i + 1] = CoordCube.parityMove[self.parity[i]][mv]

        d1 = getPruning(CoordCube.Slice_URFtoDLF_Parity_Prun,
                        (CoordCube.N_SLICE2 * self.URFtoDLF[depthPhase1] +
                         self.FRtoBR[depthPhase1]) * 2 +
                        self.parity[depthPhase1])
        if d1 > maxDepthPhase2:
            return -1

        for i in xrange(depthPhase1):
            mv = 3 * self.ax[i] + self.po[i] - 1
            self.URtoUL[i + 1] = CoordCube.URtoUL_Move[self.URtoUL[i]][mv]
            self.UBtoDF[i + 1] = CoordCube.UBtoDF_Move[self.UBtoDF[i]][mv]

        self.URtoDF[depthPhase1] = CoordCube.MergeURtoULandUBtoDF[
            self.URtoUL[depthPhase1]][self.UBtoDF[depthPhase1]]

        d2 = getPruning(CoordCube.Slice_URtoDF_Parity_Prun,
                        (CoordCube.N_SLICE2 * self.URtoDF[depthPhase1] +
                         self.FRtoBR[depthPhase1]) * 2 +
                        self.parity[depthPhase1])
        if d2 > maxDepthPhase2:
            return -1

        self.minDistPhase2[depthPhase1] = max(d1, d2)
        if self.minDistPhase2[depthPhase1] == 0:  # already solved
            return depthPhase1

        # now set up search

        depthPhase2 = 1
        n = depthPhase1
        busy = False
        self.po[depthPhase1] = 0
        self.ax[depthPhase1] = 0
        self.minDistPhase2[n + 1] = 1  # else failure for depthPhase2=1, n=0
        # +++++++++++++++++++ end initialization +++++++++++++++++++++++++++++++++

        while True:
            while True:
                if depthPhase1 + depthPhase2 - n > self.minDistPhase2[
                        n + 1] and not busy:

                    if self.ax[n] == 0 or self.ax[
                            n] == 3:  # Initialize next move
                        n += 1
                        self.ax[n] = 1
                        self.po[n] = 2
                    else:
                        n += 1
                        self.ax[n] = 0
                        self.po[n] = 1
                else:
                    if self.ax[n] == 0 or self.ax[n] == 3:
                        self.po[n] += 1
                        _ = (self.po[n] > 3)
                    else:
                        self.po[n] += 2
                        _ = (self.po[n] > 3)
                    if _:
                        while True:
                            # increment axis
                            self.ax[n] += 1
                            if self.ax[n] > 5:
                                if n == depthPhase1:
                                    if depthPhase2 >= maxDepthPhase2:
                                        return -1
                                    else:
                                        depthPhase2 += 1
                                        self.ax[n] = 0
                                        self.po[n] = 1
                                        busy = False
                                        break
                                else:
                                    n -= 1
                                    busy = True
                                    break
                            else:
                                if self.ax[n] == 0 or self.ax[n] == 3:
                                    self.po[n] = 1
                                else:
                                    self.po[n] = 2
                                busy = False

                            if not (n != depthPhase1 and
                                    (self.ax[n - 1] == self.ax[n]
                                     or self.ax[n - 1] - 3 == self.ax[n])):
                                break

                    else:
                        busy = False

                if not busy:
                    break

            # +++++++++++++ compute new coordinates and new minDist ++++++++++
            mv = 3 * self.ax[n] + self.po[n] - 1

            self.URFtoDLF[n +
                          1] = CoordCube.URFtoDLF_Move[self.URFtoDLF[n]][mv]
            self.FRtoBR[n + 1] = CoordCube.FRtoBR_Move[self.FRtoBR[n]][mv]
            self.parity[n + 1] = CoordCube.parityMove[self.parity[n]][mv]
            self.URtoDF[n + 1] = CoordCube.URtoDF_Move[self.URtoDF[n]][mv]

            self.minDistPhase2[n + 1] = max(
                getPruning(CoordCube.Slice_URtoDF_Parity_Prun,
                           (CoordCube.N_SLICE2 * self.URtoDF[n + 1] +
                            self.FRtoBR[n + 1]) * 2 + self.parity[n + 1]),
                getPruning(CoordCube.Slice_URFtoDLF_Parity_Prun,
                           (CoordCube.N_SLICE2 * self.URFtoDLF[n + 1] +
                            self.FRtoBR[n + 1]) * 2 + self.parity[n + 1]))
            # ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

            if self.minDistPhase2[n + 1] == 0:
                break

        return depthPhase1 + depthPhase2
Example #4
0
    def totalDepth(self, depthPhase1, maxDepth):
        """
        Apply phase2 of algorithm and return the combined phase1 and phase2 depth. In phase2, only the moves
        U,D,R2,F2,L2 and B2 are allowed.
        """

        mv = 0
        d1 = 0
        d2 = 0
        maxDepthPhase2 = min(10, maxDepth - depthPhase1)    # Allow only max 10 moves in phase2
        for i in xrange(depthPhase1):
            mv = 3 * self.ax[i] + self.po[i] - 1
            self.URFtoDLF[i + 1] = CoordCube.URFtoDLF_Move[self.URFtoDLF[i]][mv]
            self.FRtoBR[i + 1] = CoordCube.FRtoBR_Move[self.FRtoBR[i]][mv]
            self.parity[i + 1] = CoordCube.parityMove[self.parity[i]][mv]

        d1 = getPruning(
            CoordCube.Slice_URFtoDLF_Parity_Prun,
            (CoordCube.N_SLICE2 * self.URFtoDLF[depthPhase1] + self.FRtoBR[depthPhase1]) * 2 + self.parity[depthPhase1]
        )
        if d1 > maxDepthPhase2:
            return -1

        for i in xrange(depthPhase1):
            mv = 3 * self.ax[i] + self.po[i] - 1
            self.URtoUL[i + 1] = CoordCube.URtoUL_Move[self.URtoUL[i]][mv]
            self.UBtoDF[i + 1] = CoordCube.UBtoDF_Move[self.UBtoDF[i]][mv]

        self.URtoDF[depthPhase1] = CoordCube.MergeURtoULandUBtoDF[self.URtoUL[depthPhase1]][self.UBtoDF[depthPhase1]]

        d2 = getPruning(
            CoordCube.Slice_URtoDF_Parity_Prun,
            (CoordCube.N_SLICE2 * self.URtoDF[depthPhase1] + self.FRtoBR[depthPhase1]) * 2 + self.parity[depthPhase1]
        )
        if d2 > maxDepthPhase2:
            return -1

        self.minDistPhase2[depthPhase1] = max(d1, d2)
        if self.minDistPhase2[depthPhase1] == 0:    # already solved
            return depthPhase1

        # now set up search

        depthPhase2 = 1
        n = depthPhase1
        busy = False
        self.po[depthPhase1] = 0
        self.ax[depthPhase1] = 0
        self.minDistPhase2[n + 1] = 1   # else failure for depthPhase2=1, n=0
        # +++++++++++++++++++ end initialization +++++++++++++++++++++++++++++++++

        while True:
            while True:
                if depthPhase1 + depthPhase2 - n > self.minDistPhase2[n + 1] and not busy:

                    if self.ax[n] == 0 or self.ax[n] == 3:    # Initialize next move
                        n += 1
                        self.ax[n] = 1
                        self.po[n] = 2
                    else:
                        n += 1
                        self.ax[n] = 0
                        self.po[n] = 1
                else:
                    if self.ax[n] == 0 or self.ax[n] == 3:
                        self.po[n] += 1
                        _ = (self.po[n] > 3)
                    else:
                        self.po[n] += 2
                        _ = (self.po[n] > 3)
                    if _:
                        while True:
                            # increment axis
                            self.ax[n] += 1
                            if self.ax[n] > 5:
                                if n == depthPhase1:
                                    if depthPhase2 >= maxDepthPhase2:
                                        return -1
                                    else:
                                        depthPhase2 += 1
                                        self.ax[n] = 0
                                        self.po[n] = 1
                                        busy = False
                                        break
                                else:
                                    n -= 1
                                    busy = True
                                    break
                            else:
                                if self.ax[n] == 0 or self.ax[n] == 3:
                                    self.po[n] = 1
                                else:
                                    self.po[n] = 2
                                busy = False

                            if not (n != depthPhase1 and (self.ax[n - 1] == self.ax[n] or self.ax[n - 1] - 3 == self.ax[n])):
                                break

                    else:
                        busy = False

                if not busy:
                    break

            # +++++++++++++ compute new coordinates and new minDist ++++++++++
            mv = 3 * self.ax[n] + self.po[n] - 1

            self.URFtoDLF[n + 1] = CoordCube.URFtoDLF_Move[self.URFtoDLF[n]][mv]
            self.FRtoBR[n + 1] = CoordCube.FRtoBR_Move[self.FRtoBR[n]][mv]
            self.parity[n + 1] = CoordCube.parityMove[self.parity[n]][mv]
            self.URtoDF[n + 1] = CoordCube.URtoDF_Move[self.URtoDF[n]][mv]

            self.minDistPhase2[n + 1] = max(
                getPruning(
                    CoordCube.Slice_URtoDF_Parity_Prun,
                    (CoordCube.N_SLICE2 * self.URtoDF[n + 1] + self.FRtoBR[n + 1]) * 2 + self.parity[n + 1]
                ),
                getPruning(
                    CoordCube.Slice_URFtoDLF_Parity_Prun,
                    (CoordCube.N_SLICE2 * self.URFtoDLF[n + 1] + self.FRtoBR[n + 1]) * 2 + self.parity[n + 1]
                )
            )
            # ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

            if self.minDistPhase2[n + 1] == 0:
                break

        return depthPhase1 + depthPhase2