def test_prevent_redundant(): res_a, id_req_a = make_req_a() res_b, id_req_b = make_req_b() the_set = RequirementSet([ RequirementList(0, [id_req_a]), RequirementList(0, [id_req_a, id_req_b]), ]) assert the_set.alternatives == frozenset([RequirementList(0, [id_req_a])])
def test_requirement_as_set_1(): req = RequirementAnd([ _req("A"), RequirementOr([_req("B"), _req("C")]), RequirementOr([_req("D"), _req("E")]), ]) assert req.as_set(None) == 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")]), ])
def _replace(alternative: RequirementList) -> RequirementList: if alternative.get(resource) is not None: return RequirementList.without_misc_resources( database=database, items=[ (individual if individual.resource != database.difficulty_resource else IndividualRequirement(database.difficulty_resource, new_difficulty, False)) for individual in alternative.values() ] ) else: return alternative
def test_set_as_str_things(echoes_resource_database): item = echoes_resource_database.get_item_by_name req_set = RequirementSet([ RequirementList([ ResourceRequirement(item("Screw Attack"), 1, False), ResourceRequirement(item("Space Jump Boots"), 1, False), ]), RequirementList([ ResourceRequirement(item("Power Bomb"), 1, False), ]), ]) assert req_set.as_str == "(Power Bomb ≥ 1) or (Screw Attack ≥ 1, Space Jump Boots ≥ 1)"
def build_requirement_set(self) -> Optional[RequirementSet]: return RequirementSet([ RequirementList.without_misc_resources( [row.current_individual for row in element.rows], self.resource_database) for element in self._elements ])
def test_simplify_requirement_set_static(): res_a, id_req_a = make_req_a() res_b, id_req_b = make_req_b() the_set = RequirementOr([ RequirementAnd([id_req_a]), RequirementAnd([id_req_b]), ]) simple_1 = the_set.patch_requirements({res_a: 0, res_b: 0}, 1) simple_2 = the_set.patch_requirements({res_a: 0, res_b: 1}, 1) simple_3 = the_set.patch_requirements({res_a: 1, res_b: 1}, 1) assert simple_1.as_set.alternatives == frozenset() assert simple_2.as_set.alternatives == frozenset([RequirementList([])]) assert simple_3.as_set.alternatives == frozenset([RequirementList([])])
def test_requirement_template_nested(database): # Setup use_a = RequirementTemplate(database, "Use A") use_b = RequirementTemplate(database, "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 # Assert assert as_set == RequirementSet([ RequirementList([_req("A")]), RequirementList([_req("B")]), ])
def pickups_to_solve_list(pickup_pool: List[PickupEntry], requirement_list: RequirementList, state: State): pickups = [] resources = copy.copy(state.resources) pickups_for_this = list(pickup_pool) for individual in sorted(requirement_list.values()): if individual.satisfied(resources, state.energy): continue # FIXME: this picks Dark Beam to provide Dark Ammo # Create another copy of the list so we can remove elements while iterating for pickup in list(pickups_for_this): new_resources = resource_info.convert_resource_gain_to_current_resources( pickup.resource_gain(resources)) pickup_progression = resource_info.convert_resource_gain_to_current_resources( pickup.progression) if new_resources.get(individual.resource, 0) + pickup_progression.get( individual.resource, 0) > 0: pickups.append(pickup) pickups_for_this.remove(pickup) resource_info.add_resources_into_another( resources, new_resources) if individual.satisfied(resources, state.energy): break if not individual.satisfied(resources, state.energy): return None return pickups
def test_simplify_requirement_set_static(): res_a, id_req_a = make_req_a() res_b, id_req_b = make_req_b() the_set = RequirementSet([ RequirementList(0, [id_req_a]), RequirementList(0, [id_req_b]), ]) simple_1 = the_set.simplify({res_a: 0, res_b: 0}) simple_2 = the_set.simplify({res_a: 0, res_b: 1}) simple_3 = the_set.simplify({res_a: 1, res_b: 1}) assert simple_1.alternatives == frozenset() assert simple_2.alternatives == frozenset([RequirementList(0, [])]) assert simple_3.alternatives == frozenset([RequirementList(0, [])])
def read_area(self, data: Dict) -> Area: name = data["name"] nodes = read_array(data["nodes"], self.read_node) nodes_by_name = {node.name: node for node in nodes} connections = {} for i, origin_data in enumerate(data["nodes"]): origin = nodes[i] connections[origin] = {} extra_requirement = None if is_resource_node( origin) and self.add_self_as_requirement_to_resources: extra_requirement = RequirementList.with_single_resource( origin.resource()) for target_name, target_requirements in origin_data[ "connections"].items(): the_set = read_requirement_set(target_requirements, self.resource_database) if extra_requirement is not None: the_set = the_set.union(RequirementSet([extra_requirement ])) if the_set != RequirementSet.impossible(): connections[origin][nodes_by_name[target_name]] = the_set return Area(name, data["asset_id"], data["default_node_index"], nodes, connections)
def requirements_to_leave(self, patches: GamePatches, current_resources: CurrentResources) -> RequirementSet: return RequirementSet([ RequirementList(0, [ IndividualRequirement(patches.translator_gates[self.gate], 1, False), IndividualRequirement(self.scan_visor, 1, False), ]) ])
def requirements_to_leave( self, patches: GamePatches, current_resources: CurrentResources) -> RequirementSet: return RequirementSet([ RequirementList(0, [ IndividualRequirement(self.pickup_node.pickup_index, 1, False), ]) ])
def test_requirement_as_set_3(): req = RequirementOr([ Requirement.impossible(), _req("A"), ]) assert req.as_set(None) == RequirementSet([ RequirementList([_req("A")]), ])
def test_requirement_as_set_2(): req = RequirementAnd([ Requirement.trivial(), _req("A"), ]) assert req.as_set(None) == RequirementSet([ RequirementList([_req("A")]), ])
def test_get_pickups_that_solves_unreachable(echoes_game_description, mocker): def item(name): return search.find_resource_info_with_long_name( echoes_game_description.resource_database.item, name) mock_req_lists: MagicMock = mocker.patch( "randovania.generator.filler.pickup_list._requirement_lists_without_satisfied_resources" ) pickups_left = [] reach = MagicMock() reach.state.resources = {} reach.state.energy = 100 possible_set = MagicMock() reach.unreachable_nodes_with_requirements.return_value = { "foo": possible_set } uncollected_resource_nodes = [MagicMock()] mock_req_lists.return_value = { RequirementList([ ResourceRequirement(item("Dark Visor"), 1, False), ResourceRequirement(item("Missile"), 5, False), ]), RequirementList([ ResourceRequirement(item("Screw Attack"), 1, False), ]), RequirementList([ ResourceRequirement(item("Power Bomb"), 1, False), ResourceRequirement(item("Boost Ball"), 1, False), ]), RequirementList([ ResourceRequirement(item("Spider Ball"), 1, False), ResourceRequirement(item("Boost Ball"), 1, False), ]), } # Run result = pickup_list.get_pickups_that_solves_unreachable( pickups_left, reach, uncollected_resource_nodes) # Assert mock_req_lists.assert_called_once_with( reach.state, [possible_set], [uncollected_resource_nodes[0].resource.return_value]) assert result == tuple()
def test_requirement_as_set_5(): req = RequirementAnd([ _req("A"), _req("B"), _req("C"), ]) assert req.as_set == RequirementSet([ RequirementList([_req("A"), _req("B"), _req("C")]), ])
def test_requirement_as_set_4(): req = RequirementOr([ Requirement.impossible(), _req("A"), Requirement.trivial(), ]) assert req.as_set == RequirementSet([ RequirementList([]), ])
def read_requirement_list( data: List[Dict], resource_database: ResourceDatabase, ) -> Optional[RequirementList]: individuals = read_array( data, lambda x: read_individual_requirement( x, resource_database=resource_database)) return RequirementList.without_misc_resources(individuals, resource_database)
def requirements_to_leave(self, patches: GamePatches, current_resources: CurrentResources) -> RequirementSet: if current_resources.get("add_self_as_requirement_to_resources") == 1: return RequirementSet([ RequirementList(0, [ IndividualRequirement(self.event, 1, False), ]) ]) else: return RequirementSet.trivial()
def requirements_to_leave( self, patches: GamePatches, current_resources: CurrentResources) -> RequirementSet: items = [IndividualRequirement(self.scan_visor, 1, False)] if self.required_translator is not None: items.append( IndividualRequirement(self.required_translator, 1, False)) return RequirementSet([RequirementList(0, items)])
def requirements_to_leave(self, patches: GamePatches, current_resources: CurrentResources) -> RequirementSet: # FIXME: using non-resource as key in CurrentResources if current_resources.get("add_self_as_requirement_to_resources") == 1: return RequirementSet([ RequirementList(0, [ IndividualRequirement(self.pickup_index, 1, False), ]) ]) else: return RequirementSet.trivial()
def _extra_requirement_for_node(game: GameDescription, node: Node) -> Optional[RequirementSet]: extra_requirement = None if is_resource_node(node): node_resource = node.resource() if node_resource in game.dangerous_resources: extra_requirement = RequirementSet( [RequirementList.with_single_resource(node_resource)]) return extra_requirement
def test_list_dangerous_resources(input_data, output_data): # setup req_list = RequirementList( (ResourceRequirement(_make_resource(str(item[0])), 1, item[1]) for item in input_data)) expected_result = {_make_resource(str(item)) for item in output_data} # run result = set(req_list.dangerous_resources) # assert assert result == expected_result
def test_requirement_set_constructor(echoes_resource_database): item = echoes_resource_database.get_item_by_name req_set = RequirementSet([ RequirementList([ ResourceRequirement(item("Dark Visor"), 1, False), ResourceRequirement(item("Missile"), 5, False), ResourceRequirement(item("Seeker Launcher"), 1, False), ]), RequirementList([ ResourceRequirement(item("Screw Attack"), 1, False), ResourceRequirement(item("Space Jump Boots"), 1, False), ]), RequirementList([ ResourceRequirement(item("Power Bomb"), 1, False), ResourceRequirement(item("Boost Ball"), 1, False), ]), ]) extract = [ sorted((req.resource.long_name, req.amount) for req in req_list.items) 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), ], ]
def _simplify_requirement_list(self: RequirementList, state: State) -> Optional[RequirementList]: items = [] for item in self.values(): if item.negate: return None if item.satisfied(state.resources, state.resource_database): continue if not isinstance(item.resource, PickupIndex): # An empty RequirementList is considered satisfied, so we don't have to add the trivial resource items.append(item) return RequirementList(self.difficulty_level, items)
def test_list_dangerous_resources(input_data, output_data): # setup req_list = RequirementList(0, (IndividualRequirement( SimpleResourceInfo(item[0], str(item[0]), str(item[0]), ""), 1, item[1]) for item in input_data)) expected_result = { SimpleResourceInfo(item, str(item), str(item), "") for item in output_data } # run result = set(req_list.dangerous_resources) # assert assert result == expected_result
def test_minimum_satisfied_difficulty(database: ResourceDatabase, resources, expected_level): res_a, id_req_a = make_req_a() res_b, id_req_b = make_req_b() res_c, id_req_c = make_req_c() the_set = RequirementSet([ RequirementList(0, [id_req_a]), RequirementList(1, [ id_req_b, IndividualRequirement(database.difficulty_resource, 1, False) ]), RequirementList(2, [ id_req_c, IndividualRequirement(database.difficulty_resource, 2, False) ]), ]) res = { database.get_by_type_and_index(ResourceType.ITEM, x): 1 for x in resources } res[database.difficulty_resource] = 10 diff = the_set.minimum_satisfied_difficulty(res, 99) assert diff == expected_level
def test_set_hash(echoes_resource_database): req_set_a = RequirementSet([ RequirementList([ ResourceRequirement( echoes_resource_database.get_item_by_name("Power Bomb"), 1, False), ]), ]) req_set_b = RequirementSet([ RequirementList([ ResourceRequirement( echoes_resource_database.get_item_by_name("Power Bomb"), 1, False), ]), ]) 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
def test_trivial_merge(): trivial = RequirementSet.trivial() impossible = RequirementSet.impossible() res_a, id_req_a = make_req_a() the_set = RequirementSet([ RequirementList(0, [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
def _simplify_requirement_list(self: RequirementList, state: State, dangerous_resources: FrozenSet[ResourceInfo], ) -> Optional[RequirementList]: items = [] for item in self.values(): if item.negate: return None if item.satisfied(state.resources, state.energy): continue if item.resource not in dangerous_resources: # An empty RequirementList is considered satisfied, so we don't have to add the trivial resource items.append(item) return RequirementList(items)