Пример #1
0
def test_requirement_as_set_2():
    req = RequirementAnd([
        Requirement.trivial(),
        _req("A"),
    ])
    assert req.as_set(None) == RequirementSet([
        RequirementList([_req("A")]),
    ])
Пример #2
0
def test_requirement_as_set_5():
    req = RequirementAnd([
        _req("A"),
        _req("B"),
        _req("C"),
    ])
    assert req.as_set(None) == RequirementSet([
        RequirementList([_req("A"), _req("B"), _req("C")]),
    ])
Пример #3
0
    def _potential_nodes_from(
            self, node: Node) -> Iterator[Tuple[Node, RequirementSet]]:
        extra_requirement = _extra_requirement_for_node(
            self._game, self.node_context(), node)
        requirement_to_leave = node.requirement_to_leave(
            self._state.node_context())

        for target_node, requirement in self._game.world_list.potential_nodes_from(
                node, self.node_context()):
            if target_node is None:
                continue

            if requirement_to_leave != Requirement.trivial():
                requirement = RequirementAnd(
                    [requirement, requirement_to_leave])

            if extra_requirement is not None:
                requirement = RequirementAnd([requirement, extra_requirement])

            yield target_node, requirement.as_set(
                self._state.resource_database)
Пример #4
0
    def calculate_reach(cls, logic: Logic,
                        initial_state: State) -> "ResolverReach":

        checked_nodes: Dict[Node, int] = {}
        database = initial_state.resource_database
        context = initial_state.node_context()

        # Keys: nodes to check
        # Value: how much energy was available when visiting that node
        nodes_to_check: Dict[Node, int] = {
            initial_state.node: initial_state.energy
        }

        reach_nodes: Dict[Node, int] = {}
        requirements_by_node: Dict[Node,
                                   Set[RequirementList]] = defaultdict(set)

        path_to_node: Dict[Node, Tuple[Node, ...]] = {}
        path_to_node[initial_state.node] = tuple()

        while nodes_to_check:
            node = next(iter(nodes_to_check))
            energy = nodes_to_check.pop(node)

            if node.heal:
                energy = initial_state.maximum_energy

            checked_nodes[node] = energy
            if node != initial_state.node:
                reach_nodes[node] = energy

            requirement_to_leave = node.requirement_to_leave(context)

            for target_node, requirement in logic.game.world_list.potential_nodes_from(
                    node, context):
                if target_node is None:
                    continue

                if checked_nodes.get(target_node,
                                     math.inf) <= energy or nodes_to_check.get(
                                         target_node, math.inf) <= energy:
                    continue

                if requirement_to_leave != Requirement.trivial():
                    requirement = RequirementAnd(
                        [requirement, requirement_to_leave])

                # Check if the normal requirements to reach that node is satisfied
                satisfied = requirement.satisfied(initial_state.resources,
                                                  energy, database)
                if satisfied:
                    # If it is, check if we additional requirements figured out by backtracking is satisfied
                    satisfied = logic.get_additional_requirements(
                        node).satisfied(initial_state.resources, energy,
                                        initial_state.resource_database)

                if satisfied:
                    nodes_to_check[target_node] = energy - requirement.damage(
                        initial_state.resources, database)
                    path_to_node[target_node] = path_to_node[node] + (node, )

                elif target_node:
                    # If we can't go to this node, store the reason in order to build the satisfiable requirements.
                    # Note we ignore the 'additional requirements' here because it'll be added on the end.
                    requirements_by_node[target_node].update(
                        requirement.as_set(
                            initial_state.resource_database).alternatives)

        # Discard satisfiable requirements of nodes reachable by other means
        for node in set(reach_nodes.keys()).intersection(
                requirements_by_node.keys()):
            requirements_by_node.pop(node)

        if requirements_by_node:
            satisfiable_requirements = frozenset.union(*[
                RequirementSet(requirements).union(
                    logic.get_additional_requirements(node)).alternatives
                for node, requirements in requirements_by_node.items()
            ])
        else:
            satisfiable_requirements = frozenset()

        return ResolverReach(reach_nodes, path_to_node,
                             satisfiable_requirements, logic)