Example #1
0
 def __search(self, notes: List[str], cube: Cube, depth: int,
              estimate: int) -> Tuple[int, str]:
     """A function to actually perform the search to the current search depth
     by using recursion. Also contains the pruning if the minimum distance
     increases"""
     if self.__checked % 10000 == 0:
         print(f"Depth: {depth:2d}, checked: {self.__checked:,}+, " +
               f"(pruned: {self.__skipped:,}+)",
               end="\r")
     if len(notes) >= depth or estimate <= 0:
         if cube.is_solved:
             return (len(notes), " ".join(notes))
         return (-1, "")
     for move in cube.moves:
         if Cube.skip_move(notes, move):
             self.__skipped += 1
             continue
         new_cube = copy.deepcopy(cube)
         new_cube.twist_by_notation(move)
         new_estimate = self.__tables.get_distance(self.coordinate(cube))
         if new_estimate != -1:
             if estimate < new_estimate:
                 self.__skipped += 1
                 continue
             estimate = new_estimate + 1
         self.__checked += 1
         result = self.__search(notes + [move], new_cube, depth,
                                estimate - 1)
         if result[0] > 0:
             return result
     return (-1, "")
Example #2
0
    def __search(self, phase, notes: List[str], cube: Cube,
                 depth: int) -> Tuple[int, str]:
        """A function to actually perform the search to the current search depth
        by using recursion.

        TODO: Also contains the pruning if the minimum distance increases.

        Return a tuple with the amount of moves as the first item and the
        solution as a notation str as the second item.

        In case a valid solution was not found the amount of moves is negative.
        (currently always -1)"""
        if self.__checked % 10000 == 0:
            print(f"Depth: {depth:2d}, checked: {self.__checked:,}+ " +
                  f"(pruned: {self.__skipped:,}+)",
                  end="\r")
        if depth <= len(notes):
            if phase == 1 and cube.is_domino or cube.is_solved:
                return (len(notes), " ".join(notes))
            return (-1, "")
        for move in Cube.moves if phase == 1 else self.phase2_moves:
            if Cube.skip_move(notes, move):
                self.__skipped += 1
                continue
            new_cube = copy.deepcopy(cube)
            new_cube.twist_by_notation(move)
            self.__checked += 1
            result = self.__search(phase, notes + [move], new_cube, depth)
            if result[0] > 0:
                return result
        return (-1, "")
Example #3
0
    def generation_search(self, notes: List[str], cube: Cube, depth: int,
                          distance: int) -> None:
        """A function to search all of the patterns indexes to generate the
        pruning tables required by the Korf's algorithm to solve any cube in
        less than about 10^12 years.

        Unfortunately this function currently takes about 10^13 years with depth
        20 to finish on a modern desktop computer."""
        # FIXME: Optimize to run in less than a week.
        # FIXME: Pruning while generating doesn't seem to work correctly.
        if distance >= depth:
            self.__tables.set_distance(self.coordinate(cube), distance)
            return
        for move in cube.moves:
            if Cube.skip_move(notes, move):
                continue
            new_cube = copy.deepcopy(cube)
            new_cube.twist_by_notation(move)
            estimate = self.__tables.get_distance(self.coordinate(new_cube))
            if estimate != -1 and estimate - depth < distance:
                # print(f"Depth: {depth}, distance: {distance}, move: {move}")
                continue
            self.generation_search(notes + [move], new_cube, depth,
                                   distance + 1)