Exemplo n.º 1
0
    def _on_show_path_to_here(self):
        target: QtWidgets.QTreeWidgetItem = self.possible_locations_tree.currentItem(
        )
        if target is None:
            return
        node: Optional[Node] = getattr(target, "node", None)
        if node is not None:
            reach = ResolverReach.calculate_reach(
                self.logic, self.state_for_current_configuration())
            path = reach.path_to_node.get(node, [])

            wl = self.logic.game.world_list
            text = [
                f"<p><span style='font-weight:600;'>Path to {node.name}</span></p><ul>"
            ]
            for p in path:
                text.append("<li>{}</li>".format(
                    wl.node_name(p,
                                 with_world=True,
                                 distinguish_dark_aether=True)))
            text.append("</ul>")

            dialog = ScrollLabelDialog("".join(text), "Path to node", self)
            dialog.exec_()
        else:
            QtWidgets.QMessageBox.warning(
                self, "Invalid target",
                "Can't find a path to {}. Please select a node.".format(
                    target.text(0)))
Exemplo n.º 2
0
    def update_locations_tree_for_reachable_nodes(self):
        # Calculate which nodes are in reach right now
        state = self.state_for_current_configuration()
        if state is None:
            nodes_in_reach = set()
        else:
            reach = ResolverReach.calculate_reach(self.logic, state)
            nodes_in_reach = set(reach.nodes)
            nodes_in_reach.add(state.node)

        for world in self.game_description.world_list.worlds:
            for area in world.areas:
                area_is_visible = False
                for node in area.nodes:
                    is_collected = node in self._collected_nodes
                    is_visible = node in nodes_in_reach and not (
                        self._hide_collected_resources and is_collected)

                    if self._show_only_resource_nodes:
                        is_visible = is_visible and node.is_resource_node

                    node_item = self._node_to_item[node]
                    node_item.setHidden(not is_visible)
                    if node.is_resource_node:
                        node_item.setCheckState(
                            0, Qt.Checked if is_collected else Qt.Unchecked)

                    area_is_visible = area_is_visible or is_visible
                self._asset_id_to_item[area.area_asset_id].setHidden(
                    not area_is_visible)
Exemplo n.º 3
0
 def current_nodes_in_reach(self, state: Optional[State]):
     if state is None:
         nodes_in_reach = set()
     else:
         reach = ResolverReach.calculate_reach(self.logic, state)
         nodes_in_reach = set(reach.nodes)
         nodes_in_reach.add(state.node)
     return nodes_in_reach
Exemplo n.º 4
0
    def update_locations_tree_for_reachable_nodes(self):
        # Calculate which nodes are in reach right now
        state = self.state_for_current_configuration()
        if state is None:
            nodes_in_reach = set()
        else:
            reach = ResolverReach.calculate_reach(self.logic, state)
            nodes_in_reach = set(reach.nodes)
            nodes_in_reach.add(state.node)

        for world in self.game_description.world_list.worlds:
            for area in world.areas:
                area_is_visible = False
                for node in area.nodes:
                    is_collected = node in self._collected_nodes
                    is_visible = node in nodes_in_reach and not (
                        self._hide_collected_resources and is_collected)

                    if self._show_only_resource_nodes:
                        is_visible = is_visible and node.is_resource_node

                    node_item = self._node_to_item[node]
                    node_item.setHidden(not is_visible)
                    if node.is_resource_node:
                        resource_node: ResourceNode = node
                        node_item.setDisabled(not resource_node.can_collect(
                            state.patches, state.resources))
                        node_item.setCheckState(
                            0, Qt.Checked if is_collected else Qt.Unchecked)

                    area_is_visible = area_is_visible or is_visible
                self._asset_id_to_item[area.area_asset_id].setHidden(
                    not area_is_visible)

        # Persist the current state
        with self.persistence_path.joinpath("state.json").open(
                "w") as state_file:
            json.dump(
                {
                    "actions": [node.index for node in self._actions],
                    "collected_pickups": {
                        pickup.name: quantity
                        for pickup, quantity in
                        self._collected_pickups.items()
                    }
                }, state_file)
Exemplo n.º 5
0
def _inner_advance_depth(
    state: State,
    logic: Logic,
    status_update: Callable[[str], None],
) -> Tuple[Optional[State], bool]:

    if logic.game.victory_condition.satisfied(state.resources,
                                              state.resource_database):
        return state, True

    reach = ResolverReach.calculate_reach(logic, state)
    debug.log_new_advance(state, reach)
    status_update("Resolving... {} total resources".format(len(
        state.resources)))

    has_action = False
    for action in reach.satisfiable_actions(state):
        new_result = _inner_advance_depth(state=state.act_on_node(
            action, path=reach.path_to_node[action]),
                                          logic=logic,
                                          status_update=status_update)

        # We got a positive result. Send it back up
        if new_result[0] is not None:
            return new_result
        else:
            has_action = True

    debug.log_rollback(state, has_action)
    if not has_action:
        logic.additional_requirements[
            state.
            node] = _simplify_requirement_set_for_additional_requirements(
                reach.satisfiable_as_requirement_set, state)

    return None, has_action
Exemplo n.º 6
0
async def _inner_advance_depth(
    state: State,
    logic: Logic,
    status_update: Callable[[str], None],
    *,
    reach: Optional[ResolverReach] = None,
) -> Tuple[Optional[State], bool]:
    """

    :param state:
    :param logic:
    :param status_update:
    :param reach: A precalculated reach for the given state
    :return:
    """

    if logic.game.victory_condition.satisfied(state.resources, state.energy):
        return state, True

    # Yield back to the asyncio runner, so cancel can do something
    await asyncio.sleep(0)

    if reach is None:
        reach = ResolverReach.calculate_reach(logic, state)

    debug.log_new_advance(state, reach)
    status_update("Resolving... {} total resources".format(len(
        state.resources)))

    for action, energy in reach.possible_actions(state):
        if _should_check_if_action_is_safe(state, action,
                                           logic.game.dangerous_resources,
                                           logic.game.world_list.all_nodes):

            potential_state = state.act_on_node(
                action, path=reach.path_to_node[action], new_energy=energy)
            potential_reach = ResolverReach.calculate_reach(
                logic, potential_state)

            # If we can go back to where we were, it's a simple safe node
            if state.node in potential_reach.nodes:
                new_result = await _inner_advance_depth(
                    state=potential_state,
                    logic=logic,
                    status_update=status_update,
                    reach=potential_reach,
                )

                if not new_result[1]:
                    debug.log_rollback(state, True, True)

                # If a safe node was a dead end, we're certainly a dead end as well
                return new_result

    debug.log_checking_satisfiable_actions()
    has_action = False
    for action, energy in reach.satisfiable_actions(
            state, logic.game.victory_condition):
        new_result = await _inner_advance_depth(
            state=state.act_on_node(action,
                                    path=reach.path_to_node[action],
                                    new_energy=energy),
            logic=logic,
            status_update=status_update,
        )

        # We got a positive result. Send it back up
        if new_result[0] is not None:
            return new_result
        else:
            has_action = True

    debug.log_rollback(state, has_action, False)
    additional_requirements = reach.satisfiable_as_requirement_set

    if has_action:
        additional = set()
        for resource_node in reach.collectable_resource_nodes(state):
            additional |= logic.get_additional_requirements(
                resource_node).alternatives

        additional_requirements = additional_requirements.union(
            RequirementSet(additional))

    logic.additional_requirements[
        state.node] = _simplify_additional_requirement_set(
            additional_requirements, state, logic.game.dangerous_resources)
    return None, has_action