Beispiel #1
0
    def solve(self):

        if not self.filename_exists:
            raise SolveError("%s does not exist" % self.filename)

        if "TBD" in self.state_target:
            tbd = True
        else:
            tbd = False

        while True:
            self.ida_graph_node = None
            (state, cost_to_goal) = self.ida_heuristic()

            if tbd:
                log.info(
                    "%s: solve() state %s vs state_target %s, cost_to_goal %d"
                    % (self, state, pformat(self.state_target), cost_to_goal)
                )

            if state in self.state_target:
                break

            steps = self.steps(state)

            if steps:
                for step in steps:
                    self.parent.rotate(step)
            else:
                # self.parent.print_cube()
                raise NoSteps("%s: state %s does not have steps" % (self, state))
Beispiel #2
0
    def solve(self) -> None:

        if not self.filename_exists:
            raise SolveError(f"{self.filename} does not exist")

        if "TBD" in self.state_target:
            tbd = True
        else:
            tbd = False

        while True:
            self.ida_graph_node = None
            (state, cost_to_goal) = self.ida_heuristic()

            if tbd:
                logger.info(
                    f"{self}: solve() state {state} vs state_target {self.state_target}, cost_to_goal {cost_to_goal}"
                )

            if state in self.state_target:
                break

            steps = self.steps(state)

            if steps:
                for step in steps:
                    self.parent.rotate(step)
            else:
                raise NoSteps(f"{self}: state {state} does not have steps")
    def solve(self):

        if not self.filename_exists:
            raise SolveError("%s does not exist" % self.filename)

        if 'TBD' in self.state_target:
            tbd = True
        else:
            tbd = False

        while True:
            (state, _) = self.ida_heuristic(0)

            if tbd:
                log.info("%s: solve() state %s vs state_target %s" %
                         (self, state, pformat(self.state_target)))

            if state in self.state_target:
                break

            steps = self.steps(state)

            if steps:
                for step in steps:
                    self.parent.rotate(step)
            else:
                self.parent.print_cube()
                raise NoSteps("%s: state %s does not have steps" %
                              (self, state))
    def stage_final_four_edges_in_x_plane(self):
        original_state = self.state[:]
        original_solution = self.solution[:]
        done = False

        # Traverse a table of moves that place L4E in one of three planes
        # and then rotate that plane to the x-plane
        for min_unpaired_count in (0, -1):
            for pre_steps in pre_steps_to_try:
                self.state = original_state[:]
                self.solution = original_solution[:]
                steps = None

                for step in pre_steps:
                    self.rotate(step)

                if self.x_plane_edges_are_l4e() and self.x_plane_edges_unpaired_count() > min_unpaired_count:
                    # if pre_steps:
                    #    log.info("%s: %s puts L4E group in x-plane" % (self, "".join(pre_steps)))
                    # else:
                    #    log.info("%s: L4E group in x-plane" % self)
                    done = True
                    break

                elif (self.y_plane_edges_are_l4e() and self.y_plane_edges_unpaired_count() > min_unpaired_count):
                    # if pre_steps:
                    #    log.info("%s: %s puts L4E group in y-plane, moving to x-plane" % (self, "".join(pre_steps)))
                    # else:
                    #    log.info("%s: L4E group in y-plane, moving to x-plane" % self)
                    self.rotate("z")
                    done = True
                    break

                elif (self.z_plane_edges_are_l4e() and self.z_plane_edges_unpaired_count() > min_unpaired_count):
                    # if pre_steps:
                    #    log.info("%s: %s puts L4E group in z-plane" % (self, "".join(pre_steps)))
                    # else:
                    #    log.info("%s: L4E group in z-plane, moving to x-plane" % self)
                    self.rotate("x")
                    done = True
                    break

            if done:
                break

        if not done:
            msg = "Could not stage L4E in x-plane"
            log.warning(msg)
            self.enable_print_cube = True
            self.print_cube()
            raise SolveError(msg)
    def steps_cost(self, state_to_find):

        # compute the hash_index for state_to_find, look that many bytes into the
        # file/self.conten and retrieve a single hex character. This hex character
        # is the number of steps required to solve the corresponding state.
        hash_raw = hashxx(state_to_find.encode('utf-8'))
        hash_index = int(hash_raw % self.bucketcount)

        result = int(chr(self.content[hash_index]), 16)

        # This should never be zero
        if not result:
            #log.warning("%s: state_to_find %s, hash_raw %s. hash_index %s, result is %s" % (self, state_to_find, hash_raw, hash_index, result))
            raise SolveError(
                "%s: state_to_find %s, hash_raw %s. hash_index %s, result is %s"
                % (self, state_to_find, hash_raw, hash_index, result))

        return result
    def stage_final_four_edges_in_x_plane(self):
        original_state = self.state[:]
        original_solution = self.solution[:]

        # Traverse a table of moves that place L4E in one of three planes
        # and then rotate that plane to the x-plane
        for pre_steps in pre_steps_to_try:
            self.state = original_state[:]
            self.solution = original_solution[:]
            steps = None

            for step in pre_steps:
                self.rotate(step)

            if self.x_plane_edges_are_l4e() and self.x_plane_edges_unpaired_count() > 0:
                # if pre_steps:
                #    log.info("%s: %s puts L4E group in x-plane" % (self, "".join(pre_steps)))
                # else:
                #    log.info("%s: L4E group in x-plane" % self)
                break

            elif (
                self.y_plane_edges_are_l4e() and self.y_plane_edges_unpaired_count() > 0
            ):
                # if pre_steps:
                #    log.info("%s: %s puts L4E group in y-plane, moving to x-plane" % (self, "".join(pre_steps)))
                # else:
                #    log.info("%s: L4E group in y-plane, moving to x-plane" % self)
                self.rotate("z")
                break

            elif (
                self.z_plane_edges_are_l4e() and self.z_plane_edges_unpaired_count() > 0
            ):
                # if pre_steps:
                #    log.info("%s: %s puts L4E group in z-plane" % (self, "".join(pre_steps)))
                # else:
                #    log.info("%s: L4E group in z-plane, moving to x-plane" % self)
                self.rotate("x")
                break
        else:
            raise SolveError("Could not stage L4E in x-plane")
    def heuristic(self, pt_state):
        if pt_state in self.state_target:
            return 0
        else:
            result = self.steps_cost(pt_state)

            if result == 0:
                #log.warning("%s: pt_state %s cost is 0 but this is not a state_target" % (self, pt_state))
                self.parent.enable_print_cube = True
                #self.parent.print_cube()
                raise NoPruneTableState(
                    "%s: pt_state %s cost is 0 but this is not a state_target"
                    % (self, pt_state))

            return result

        self.parent.print_cube()
        raise SolveError(
            "%s does not have max_depth and does not have steps for %s, state_width %d"
            % (self, pt_state, self.state_width))
    def heuristic(self):
        pt_state = self.state()

        if pt_state in self.state_target:
            return 0

        else:
            pt_steps_cost = self.steps_cost(pt_state)

            if pt_steps_cost:
                return pt_steps_cost

            elif self.max_depth:
                # This is the exception to the rule but some prune tables such
                # as lookup-table-6x6x6-step23-UD-oblique-edge-pairing-LFRB-only.txt
                # are partial tables so use the max_depth of the table +1
                return self.max_depth + 1

        self.parent.print_cube()
        raise SolveError(
            "%s does not have max_depth and does not have steps for %s, state_width %d"
            % (self, pt_state, self.state_width))
    def solve(self):

        if not self.filename_exists:
            raise SolveError("%s does not exist" % self.filename)

        if 'TBD' in self.state_target:
            tbd = True
        else:
            tbd = False

        while True:
            state = self.state()

            if tbd:
                log.info("%s: solve() state %s vs state_target %s" %
                         (self, state, pformat(self.state_target)))

            if state in self.state_target:
                break

            steps = self.steps(state)

            if steps:
                #log.info("%s: PRE solve() state %s found %s" % (self, state, ' '.join(steps)))
                #self.parent.print_cube()
                #log.info("%s: %d steps" % (self, len(steps)))

                for step in steps:
                    self.parent.rotate(step)

                #log.info("%s: POST solve()" % self)
                #self.parent.print_cube()

            else:
                self.parent.print_cube()
                raise NoSteps("%s: state %s does not have steps" %
                              (self, state))
    def pair_x_plane_edges_in_l4e(self):

        if not self.x_plane_edges_are_l4e():
            raise SolveError("There must be a L4E group of edges in the x-plane")

        if self.x_plane_edges_paired():
            log.info(
                "%s: x-plane edges already paired, %d steps in"
                % (self, self.get_solution_len_minus_rotates(self.solution))
            )
            return

        original_state = self.state[:]
        original_solution = self.solution[:]
        original_solution_len = len(self.solution)
        original_paired_edges_count = self.get_paired_edges_count()

        # The 4 paired edges are in the x-plane
        only_colors = []
        for square_index in (36, 40, 86, 90):
            partner_index = edges_partner_555[square_index]
            square_value = self.state[square_index]
            partner_value = self.state[partner_index]
            wing_str = wing_str_map[square_value + partner_value]
            only_colors.append(wing_str)

        # Old way where we would IDA
        """
        self.lt_edges_x_plane_edges_only.only_colors = only_colors
        self.lt_edges_x_plane.only_colors = only_colors

        # Recolor the centers in the x-plane to LFRB since LFRB was used to build our tables
        centers_recolor = {
            self.state[38] : "L",
            self.state[63] : "F",
            self.state[88] : "R",
            self.state[113] : "B",
        }

        for x in LFRB_centers_555:
            self.state[x] = centers_recolor[self.state[x]]

        # Recolor the edges to they are all oriented using their original orientation.
        # We do this because our tables were built will all edges at their original orientation.
        self.edges_flip_to_original_orientation()

        # Now we can solve
        self.lt_edges_x_plane.solve()
        """

        # Recolor the edges to they are all oriented using their original orientation.
        # We do this because our tables were built will all edges at their original orientation.
        self.edges_flip_to_original_orientation()

        # Now we can solve
        self.lt_edges_x_plane_centers_solved.only_colors = only_colors
        self.lt_edges_x_plane_centers_solved.solve()

        # Put the cube back the way it was (to undo all of the recoloring we did) and apply the solution
        l4e_solution = self.solution[original_solution_len:]
        self.state = original_state[:]
        self.solution = original_solution[:]

        for step in l4e_solution:
            self.rotate(step)

        # self.print_cube()
        assert self.x_plane_edges_paired(), "4-edges in x-plane should have paired"
        self.solution.append(
            "COMMENT_%d_steps_555_L4E_paired"
            % self.get_solution_len_minus_rotates(self.solution[original_solution_len:])
        )
        log.info(
            "%s: x-plane edges paired in %d steps, %d steps in"
            % (
                self,
                len(l4e_solution),
                self.get_solution_len_minus_rotates(self.solution),
            )
        )
    def stage_second_four_edges_555(self):
        """
        The 1st 4-edges have been staged to LB, LF, RF, RB. Stage the next four
        edges to UB, UF, DF, DB (this in turn stages the final four edges).

        Since there are 8-edges there are 70 different combinations of edges we can
        choose to stage to UB, UF, DF, DB. Walk through all 70 combinations and see
        which one leads to the shortest solution.
        """

        # return if they are already staged
        if self.y_plane_edges_are_l4e() and self.z_plane_edges_are_l4e():
            return

        first_four_wing_strs = list(self.get_x_plane_wing_strs())
        wing_strs_for_second_four = []

        log.info("first_four_wing_strs %s" % pformat(first_four_wing_strs))

        for wing_str in wing_strs_all:
            if wing_str not in first_four_wing_strs:
                wing_strs_for_second_four.append(wing_str)

        log.info("wing_strs_for_second_four %s" % pformat(wing_strs_for_second_four))
        assert len(wing_strs_for_second_four) == 8

        # Remember what things looked like
        original_state = self.state[:]
        original_solution = self.solution[:]
        original_solution_len = len(self.solution)

        min_solution_len = None
        min_solution_steps = None

        for pre_steps in pre_steps_to_try:
            self.state = original_state[:]
            self.solution = original_solution[:]

            for step in pre_steps:
                self.rotate(step)

            post_pre_steps_state = self.state[:]
            post_pre_steps_solution = self.solution[:]
            states_to_find = []

            for wing_strs in itertools.combinations(wing_strs_for_second_four, 4):
                states_to_find.append(self.lt_edges_stage_second_four.state(wing_strs))

            log.info("%s: %d states_to_find" % (self, len(states_to_find)))
            results = self.lt_edges_stage_second_four.binary_search_multiple(
                states_to_find
            )
            len_results = len(results)
            # log.info(results)
            log.info("%s: %d states found" % (self, len(results)))

            # We sort the keys of the dict so that the order is the same everytime, this isn't
            # required but makes troubleshooting easier.
            for (line_number, key) in enumerate(sorted(results.keys())):
                steps = results[key]
                self.state = post_pre_steps_state[:]
                self.solution = post_pre_steps_solution[:]

                for step in steps.split():
                    self.rotate(step)

                solution_steps = self.solution[original_solution_len:]
                solution_len = len(solution_steps)

                if min_solution_len is None or solution_len < min_solution_len:
                    log.info(
                        "%s: %d/%d 2nd 4-edges can be staged in %d steps %s (NEW MIN)"
                        % (
                            self,
                            line_number + 1,
                            len_results,
                            solution_len,
                            " ".join(solution_steps),
                        )
                    )
                    min_solution_len = solution_len
                    min_solution_steps = solution_steps
                else:
                    log.info(
                        "%s: %d/%d 2nd 4-edges can be staged in %d steps"
                        % (self, line_number + 1, len_results, solution_len)
                    )

            if min_solution_len is not None:
                self.state = original_state[:]
                self.solution = original_solution[:]

                for step in min_solution_steps:
                    self.rotate(step)
                break

        self.state = original_state[:]
        self.solution = original_solution[:]

        if min_solution_len is None:
            raise SolveError("Could not find 4-edges to stage")
        else:
            for step in min_solution_steps:
                self.rotate(step)

        self.solution.append(
            "COMMENT_%d_steps_555_second_L4E_edges_staged"
            % self.get_solution_len_minus_rotates(self.solution[original_solution_len:])
        )
        log.info(
            "%s: 2nd 4-edges staged to x-plane, %d steps in"
            % (self, self.get_solution_len_minus_rotates(self.solution))
        )
    def stage_first_four_edges_555(self):
        """
        There are 495 different permutations of 4-edges out of 12-edges, use the one
        that gives us the shortest solution for getting 4-edges staged to LB, LF, RF, RB
        """

        # return if they are already staged
        if self.x_plane_edges_are_l4e():
            log.info("%s: first L4E group in x-plane" % self)
            return

        if self.y_plane_edges_are_l4e():
            log.info("%s: first L4E group in y-plane, moving to x-plane" % self)
            self.rotate("z")
            return

        if self.z_plane_edges_are_l4e():
            log.info("%s: first L4E group in z-plane, moving to x-plane" % self)
            self.rotate("x")
            return

        min_solution_len = None
        min_solution_steps = None

        # The table for staging the 1st 4-edges would have 364,058,145 if built to completion.
        # Building that table the entire way is difficult though because this is a table where
        # the centers must be kept solved...so this involves building out a HUGE table and only
        # keeping the entries where the centers are solved.  To build one deep enough to find
        # all 364,058,145 entries needed that also have solved centers would probably take a
        # few months and more drive space than I have access to.
        #
        # To avoid building such a massive table we only build the table out 10-deep which gives
        # us a few million entries.  We then try all 495 permutations of 4-edges out of 12-edges
        # looking for one that does have a hit.  Most of the time this is all that is needed and
        # we can find a hit.  On the off chance that we cannot though we need a way to find a solution
        # so what we do is try all outer layer moves up to 3 moves deep and see if any of those
        # sequences put the cube in a state such that one of the 495 edge permutations does find
        # a hit. I have yet to find a cube that cannot be solved with this approach but if I did
        # the pre_steps_to_try could be expanded to 4-deep.

        # Remember what things looked like
        original_state = self.state[:]
        original_solution = self.solution[:]
        original_solution_len = len(self.solution)

        min_solution_len = None
        min_solution_steps = None

        for pre_steps in pre_steps_to_try:
            self.state = original_state[:]
            self.solution = original_solution[:]

            for step in pre_steps:
                self.rotate(step)

            post_pre_steps_state = self.state[:]
            post_pre_steps_solution = self.solution[:]
            states_to_find = []

            for wing_strs in itertools.combinations(wing_strs_all, 4):
                states_to_find.append(self.lt_edges_stage_first_four.state(wing_strs))

            log.info("%s: %d states_to_find" % (self, len(states_to_find)))
            results = self.lt_edges_stage_first_four.binary_search_multiple(states_to_find)
            len_results = len(results)
            log.info("%s: %d states found" % (self, len(results)))

            # We sort the keys of the dict so that the order is the same everytime, this isn't
            # required but makes troubleshooting easier.
            for (line_number, key) in enumerate(sorted(results.keys())):
                steps = results[key]
                self.state = post_pre_steps_state[:]
                self.solution = post_pre_steps_solution[:]

                for step in steps.split():
                    self.rotate(step)

                self.stage_final_four_edges_in_x_plane()
                solution_steps = self.solution[original_solution_len:]
                solution_len = self.get_solution_len_minus_rotates(solution_steps)

                # Technically we only need 4 edges to be pairable for the next phase but 5 is nice because it gives
                # the next phase some wiggle room...it can choose the best 4-edge tuple.
                if min_solution_len is None or solution_len < min_solution_len:
                    log.info(
                        "%s: %d/%d 1st 4-edges can be staged in %d steps %s (NEW MIN)"
                        % (
                            self,
                            line_number + 1,
                            len_results,
                            solution_len,
                            " ".join(solution_steps),
                        )
                    )
                    min_solution_len = solution_len
                    min_solution_steps = solution_steps
                else:
                    log.info(
                        "%s: %d/%d 1st 4-edges can be staged in %d steps"
                        % (self, line_number + 1, len_results, solution_len)
                    )

            if min_solution_len is not None:
                self.state = original_state[:]
                self.solution = original_solution[:]

                for step in min_solution_steps:
                    self.rotate(step)
                break

        if not self.x_plane_edges_are_l4e():
            raise SolveError("There should be an L4E group in x-plane but there is not")

        # self.print_cube()
        self.solution.append(
            "COMMENT_%d_steps_555_first_L4E_edges_staged"
            % self.get_solution_len_minus_rotates(self.solution[original_solution_len:])
        )
        log.info(
            "%s: 1st 4-edges staged to x-plane, %d steps in"
            % (self, self.get_solution_len_minus_rotates(self.solution))
        )