コード例 #1
0
def test_expand_alternatives_3(blank_resource_db):
    db = blank_resource_db
    a = RequirementSet.trivial()
    b = make_single_set(make_req_a(db))
    expected = RequirementSet.trivial()

    assert a.expand_alternatives(b) == expected
コード例 #2
0
ファイル: debug.py プロジェクト: randovania/randovania
def log_skip_action_missing_requirement(node: Node, game: "GameDescription", requirement_set: RequirementSet):
    if _DEBUG_LEVEL > 1:
        if node in _last_printed_additional and _last_printed_additional[node] == requirement_set:
            print("{}* Skip {}, same additional".format(_indent(), n(node, world_list=game.world_list)))
        else:
            print("{}* Skip {}, missing additional:".format(_indent(), n(node, world_list=game.world_list)))
            requirement_set.pretty_print(_indent(-1))
            _last_printed_additional[node] = requirement_set
コード例 #3
0
def test_set_dangerous_resources():
    # setup
    list_a = MagicMock()
    list_b = MagicMock()
    list_a.dangerous_resources = [1, 2, 3]
    list_b.dangerous_resources = ["a", "b", "c"]

    req_set = RequirementSet([])
    req_set.alternatives = frozenset([list_a, list_b])

    # Run
    result = set(req_set.dangerous_resources)

    # Assert
    assert result == {1, 2, 3, "a", "b", "c"}
コード例 #4
0
def test_expand_alternatives_1(blank_resource_db):
    db = blank_resource_db
    a = RequirementSet.impossible()
    b = make_single_set(make_req_a(db))
    expected = make_single_set(make_req_a(db))

    assert a.expand_alternatives(b) == expected
コード例 #5
0
def test_expand_alternatives_4(blank_resource_db):
    db = blank_resource_db
    a = make_single_set(make_req_a(db))
    b = make_single_set(make_req_b(db))
    expected = RequirementSet([
        RequirementList([make_req_a(db)[1]]),
        RequirementList([make_req_b(db)[1]])
    ])

    assert a.expand_alternatives(b) == expected
コード例 #6
0
def test_prevent_redundant(blank_game_description):
    db = blank_game_description.resource_database
    res_a, id_req_a = make_req_a(db)
    res_b, id_req_b = make_req_b(db)

    the_set = RequirementSet([
        RequirementList([id_req_a]),
        RequirementList([id_req_a, id_req_b]),
    ])

    assert the_set.alternatives == frozenset([RequirementList([id_req_a])])
コード例 #7
0
    def reach_from_state(
        cls,
        game: GameDescription,
        initial_state: State,
    ) -> "GeneratorReach":

        reach = cls(game, initial_state, graph_module.RandovaniaGraph.new())
        game.world_list.ensure_has_node_cache()
        reach._expand_graph(
            [GraphPath(None, initial_state.node, RequirementSet.trivial())])
        return reach
コード例 #8
0
def test_requirement_as_set_3(database):
    def _req(name: str):
        id_req = ResourceRequirement.simple(database.get_item(name))
        return id_req

    req = RequirementOr([
        Requirement.impossible(),
        _req("A"),
    ])
    assert req.as_set(database) == RequirementSet([
        RequirementList([_req("A")]),
    ])
コード例 #9
0
def test_set_hash(echoes_resource_database):
    req_set_a = RequirementSet([
        RequirementList([
            ResourceRequirement.simple(
                echoes_resource_database.get_item_by_name("Power Bomb")),
        ]),
    ])
    req_set_b = RequirementSet([
        RequirementList([
            ResourceRequirement.simple(
                echoes_resource_database.get_item_by_name("Power Bomb")),
        ]),
    ])

    assert req_set_a == req_set_b
    assert req_set_a is not req_set_b

    hash_a = hash(req_set_a)
    hash_b = hash(req_set_b)
    assert hash_a == hash_b

    assert hash_a == req_set_a._cached_hash
コード例 #10
0
ファイル: resolver.py プロジェクト: randovania/randovania
def _simplify_additional_requirement_set(
    requirements: RequirementSet,
    state: State,
    dangerous_resources: FrozenSet[ResourceInfo],
) -> RequirementSet:
    new_alternatives = [
        _simplify_requirement_list(alternative, state, dangerous_resources)
        for alternative in requirements.alternatives
    ]
    return RequirementSet(alternative for alternative in new_alternatives

                          # RequirementList.simplify may return None
                          if alternative is not None)
コード例 #11
0
def test_set_as_str_things(echoes_resource_database):
    item = echoes_resource_database.get_item_by_name

    req_set = RequirementSet([
        RequirementList([
            ResourceRequirement.simple(item("Screw Attack")),
            ResourceRequirement.simple(item("Space Jump Boots")),
        ]),
        RequirementList([
            ResourceRequirement.simple(item("Power Bomb")),
        ]),
    ])

    assert req_set.as_str == "(Power Bomb ≥ 1) or (Screw Attack ≥ 1, Space Jump Boots ≥ 1)"
コード例 #12
0
def test_requirement_as_set_1(database):
    def _req(name: str):
        id_req = ResourceRequirement.simple(database.get_item(name))
        return id_req

    req = RequirementAnd([
        _req("A"),
        RequirementOr([_req("B"), _req("C")]),
        RequirementOr([_req("D"), _req("E")]),
    ])
    assert req.as_set(database) == RequirementSet([
        RequirementList([_req("A"), _req("B"), _req("D")]),
        RequirementList([_req("A"), _req("B"), _req("E")]),
        RequirementList([_req("A"), _req("C"), _req("D")]),
        RequirementList([_req("A"), _req("C"), _req("E")]),
    ])
コード例 #13
0
def test_trivial_merge(blank_game_description):
    db = blank_game_description.resource_database
    res_a, id_req_a = make_req_a(db)
    trivial = RequirementSet.trivial()
    impossible = RequirementSet.impossible()

    the_set = RequirementSet([
        RequirementList([id_req_a]),
    ])

    assert trivial.union(trivial) == trivial
    assert trivial.union(the_set) == the_set
    assert the_set.union(trivial) == the_set
    assert trivial.union(impossible) == impossible
    assert impossible.union(the_set) == impossible
    assert the_set.union(impossible) == impossible
    assert the_set.union(the_set) == the_set
コード例 #14
0
def test_requirement_template_nested(database):
    def _req(name: str):
        id_req = ResourceRequirement.simple(database.get_item(name))
        return id_req

    # Setup
    use_a = RequirementTemplate("Use A")
    use_b = RequirementTemplate("Use B")

    database.requirement_template["Use A"] = _req("A")
    database.requirement_template["Use B"] = RequirementOr([use_a, _req("B")])

    # Run
    as_set = use_b.as_set(database)

    # Assert
    assert as_set == RequirementSet([
        RequirementList([_req("A")]),
        RequirementList([_req("B")]),
    ])
    assert hash(use_a) != hash(use_b)
コード例 #15
0
def test_requirement_set_constructor(echoes_resource_database):
    item = echoes_resource_database.get_item_by_name

    req_set = RequirementSet([
        RequirementList([
            ResourceRequirement.simple(item("Dark Visor")),
            ResourceRequirement.create(item("Missile"), 5, False),
            ResourceRequirement.simple(item("Seeker Launcher")),
        ]),
        RequirementList([
            ResourceRequirement.simple(item("Screw Attack")),
            ResourceRequirement.simple(item("Space Jump Boots")),
        ]),
        RequirementList([
            ResourceRequirement.simple(item("Power Bomb")),
            ResourceRequirement.simple(item("Boost Ball")),
        ]),
    ])
    extract = [
        sorted((req.resource.long_name, req.amount)
               for req in req_list.values())
        for req_list in req_set.alternatives
    ]

    assert sorted(extract) == [
        [
            ("Boost Ball", 1),
            ("Power Bomb", 1),
        ],
        [
            ("Dark Visor", 1),
            ("Missile", 5),
            ("Seeker Launcher", 1),
        ],
        [
            ("Screw Attack", 1),
            ("Space Jump Boots", 1),
        ],
    ]
コード例 #16
0
 def satisfiable_as_requirement_set(self) -> RequirementSet:
     return RequirementSet(self._satisfiable_requirements)
コード例 #17
0
 def as_set(self, database: ResourceDatabase) -> RequirementSet:
     result = RequirementSet.trivial()
     for item in self.items:
         result = result.union(item.as_set(database))
     return result
コード例 #18
0
def test_expand_alternatives_2():
    a = RequirementSet.impossible()
    b = RequirementSet.trivial()
    expected = RequirementSet.trivial()

    assert a.expand_alternatives(b) == expected
コード例 #19
0
 def as_set(self, database: ResourceDatabase) -> RequirementSet:
     return RequirementSet([RequirementList([self])])
コード例 #20
0
ファイル: logic.py プロジェクト: randovania/randovania
 def __init__(self, game: GameDescription,
              configuration: BaseConfiguration):
     self.game = game
     self.configuration = configuration
     self.additional_requirements = [RequirementSet.trivial()] * len(
         game.world_list.all_nodes)
コード例 #21
0
ファイル: resolver.py プロジェクト: randovania/randovania
async def _inner_advance_depth(
    state: State,
    logic: Logic,
    status_update: Callable[[str], None],
    *,
    reach: Optional[ResolverReach] = None,
    max_attempts: Optional[int] = None,
) -> Tuple[Optional[State], bool]:
    """

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

    if logic.victory_condition.satisfied(state.resources, state.energy,
                                         state.resource_database):
        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)

    _check_attempts(max_attempts)
    debug.log_new_advance(state, reach)
    status_update("Resolving... {} total resources".format(
        state.resources.num_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.iterate_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,
                    max_attempts=max_attempts,
                )

                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.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,
            max_attempts=max_attempts,
        )

        # 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.set_additional_requirements(
        state.node,
        _simplify_additional_requirement_set(additional_requirements, state,
                                             logic.game.dangerous_resources))
    return None, has_action
コード例 #22
0
def test_impossible_requirement_as_set():
    assert Requirement.impossible().as_set(None) == RequirementSet.impossible()
コード例 #23
0
def test_empty_requirement_set_satisfied():
    assert not RequirementSet([]).satisfied(_empty_col(), 99, None)
コード例 #24
0
def make_single_set(
        id_req: Tuple[ResourceInfo, ResourceRequirement]) -> RequirementSet:
    return RequirementSet([RequirementList([id_req[1]])])
コード例 #25
0
def test_trivial_requirement_as_set():
    assert Requirement.trivial().as_set(None) == RequirementSet.trivial()
コード例 #26
0
    def calculate_reach(cls,
                        logic: Logic,
                        initial_state: State) -> "ResolverReach":

        all_nodes = logic.game.world_list.all_nodes
        checked_nodes: Dict[int, 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[int, int] = {
            initial_state.node.node_index: initial_state.energy
        }

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

        path_to_node: dict[int, list[int]] = {
            initial_state.node.node_index: [],
        }

        while nodes_to_check:
            node_index = next(iter(nodes_to_check))
            node = all_nodes[node_index]
            energy = nodes_to_check.pop(node_index)

            if node.heal:
                energy = initial_state.maximum_energy

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

            requirement_to_leave = node.requirement_to_leave(context)

            for target_node, requirement in logic.game.world_list.potential_nodes_from(node, context):
                target_node_index = target_node.node_index

                if checked_nodes.get(target_node_index, math.inf) <= energy or nodes_to_check.get(target_node_index,
                                                                                            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_index] = energy - requirement.damage(initial_state.resources, database)
                    path_to_node[target_node_index] = list(path_to_node[node_index])
                    path_to_node[target_node_index].append(node_index)

                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_index].update(
                        requirement.as_set(initial_state.resource_database).alternatives)

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

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

        return ResolverReach(reach_nodes, path_to_node,
                             satisfiable_requirements,
                             logic)
コード例 #27
0
def test_set_as_str_trivial():
    assert RequirementSet.trivial().as_str == "Trivial"
コード例 #28
0
def test_set_as_str_impossible():
    assert RequirementSet.impossible().as_str == "Impossible"
コード例 #29
0
 def as_set(self, database: ResourceDatabase) -> "RequirementSet":
     alternatives = set()
     for item in self.items:
         alternatives |= item.as_set(database).alternatives
     return RequirementSet(alternatives)