def test_add_elevator_connections_to_patches_random(echoes_game_data): # Setup game = data_reader.decode_data(echoes_game_data) permalink = dataclasses.replace(Permalink.default(), layout_configuration=dataclasses.replace( LayoutConfiguration.default(), elevators=LayoutElevators.RANDOMIZED)) expected = dataclasses.replace(GamePatches.with_game(game), elevator_connection={ 589851: AreaLocation(1039999561, 1868895730), 1572998: AreaLocation(1039999561, 3479543630), 1966093: AreaLocation(2252328306, 408633584), 2097251: AreaLocation(1119434212, 3331021649), 136970379: AreaLocation(2252328306, 2068511343), 3342446: AreaLocation(1039999561, 3205424168), 3538975: AreaLocation(1119434212, 2806956034), 152: AreaLocation(1006255871, 2889020216), 393260: AreaLocation(464164546, 3145160350), 524321: AreaLocation(464164546, 900285955), 589949: AreaLocation(1006255871, 2278776548), 122: AreaLocation(464164546, 3528156989), 1245307: AreaLocation(1006255871, 1345979968), 2949235: AreaLocation(1006255871, 1287880522), 129: AreaLocation(1006255871, 2918020398), 2162826: AreaLocation(1006255871, 1660916974), 4522032: AreaLocation(1006255871, 3455543403), 38: AreaLocation(1119434212, 1473133138), 1245332: AreaLocation(2252328306, 2399252740), 1638535: AreaLocation(2252328306, 2556480432), }) # Run result = base_patches_factory.add_elevator_connections_to_patches( permalink.layout_configuration, Random(permalink.seed_number), GamePatches.with_game(game), ) # Assert assert result == expected
def test_add_elevator_connections_to_patches_vanilla(echoes_game_data): # Setup game = data_reader.decode_data(echoes_game_data) permalink = Permalink.default() # Run result = base_patches_factory.add_elevator_connections_to_patches( permalink.layout_configuration, Random(permalink.seed_number), GamePatches.with_game(game)) # Assert assert result == GamePatches.with_game(game)
def __init__(self, layout_configuration: LayoutConfiguration): super().__init__() self.setupUi(self) set_default_window_icon(self) self.layout_configuration = layout_configuration self.game_description = data_reader.decode_data( layout_configuration.game_data, True) self.logic, self._initial_state = logic_bootstrap( layout_configuration, self.game_description, GamePatches.with_game(self.game_description)) self.resource_filter_check.stateChanged.connect( self.update_locations_tree_for_reachable_nodes) self.hide_collected_resources_check.stateChanged.connect( self.update_locations_tree_for_reachable_nodes) self.undo_last_action_button.clicked.connect(self._undo_last_action) self.configuration_label.setText( "Trick Level: {}; Elevators: Vanilla; Item Loss: {}".format( layout_configuration.trick_level.value, layout_configuration.starting_resources.configuration.value, )) self.setup_pickups_box() self.setup_possible_locations_tree() self._starting_nodes = { node for node in self.game_description.world_list.all_nodes if node.is_resource_node and node.resource() in self._initial_state.resources } self._add_new_action(self._initial_state.node)
def _create_test_layout_description( configuration: LayoutConfiguration, pickup_mapping: Iterable[int], ) -> LayoutDescription: """ Creates a LayoutDescription for the given configuration, with the patches being for the given pickup_mapping :param configuration: :param pickup_mapping: :return: """ game = data_reader.decode_data(configuration.game_data) pickup_database = game.pickup_database return LayoutDescription( version=VERSION, permalink=Permalink( seed_number=0, spoiler=True, patcher_configuration=PatcherConfiguration.default(), layout_configuration=configuration, ), patches=GamePatches.with_game(game).assign_new_pickups([ (PickupIndex(i), pickup_database.original_pickup_mapping[PickupIndex(new_index)]) for i, new_index in enumerate(pickup_mapping) ]), solver_path=())
def test_run_filler(mock_retcon_playthrough_filler: MagicMock, echoes_game_description, pickup ): # Setup configuration = LayoutConfiguration.default() rng = Random(5000) status_update = MagicMock() item_pool = [pickup] patches = GamePatches.with_game(echoes_game_description) logbook_nodes = [node for node in echoes_game_description.world_list.all_nodes if isinstance(node, LogbookNode)] mock_retcon_playthrough_filler.return_value = patches.assign_hint( logbook_nodes[0].resource(), Hint(HintType.LOCATION, None, PickupIndex(0)) ).assign_pickup_assignment({PickupIndex(1): pickup}) # Run result_patches, remaining_items = runner.run_filler(configuration, echoes_game_description, item_pool, patches, rng, status_update) # Assert assert len(result_patches.hints) == len(logbook_nodes) assert [hint for hint in patches.hints.values() if hint.item_precision is None or hint.location_precision is None] == [] assert remaining_items == [pickup]
def create_base_patches( configuration: LayoutConfiguration, rng: Random, game: GameDescription, ) -> GamePatches: """ :param configuration: :param rng: :param game: :return: """ # TODO: we shouldn't need the seed_number! patches = GamePatches.with_game(game) patches = add_elevator_connections_to_patches(configuration, rng, patches) # Gates patches = patches.assign_gate_assignment( gate_assignment_for_configuration(configuration, game.resource_database, rng)) # Starting Location patches = patches.assign_starting_location( starting_location_for_configuration(configuration, game, rng)) # Hints if rng is not None: patches = add_default_hints_to_patches(rng, patches, game.world_list) return patches
def test_basic_search_with_translator_gate(has_translator: bool, echoes_resource_database): # Setup scan_visor = echoes_resource_database.get_by_type_and_index( ResourceType.ITEM, 10) node_a = GenericNode("Node A", True, 0) node_b = GenericNode("Node B", True, 1) node_c = GenericNode("Node C", True, 2) translator_node = TranslatorGateNode("Translator Gate", True, 3, TranslatorGate(1), scan_visor) world_list = WorldList([ World("Test World", 1, [ Area( "Test Area A", False, 10, 0, [node_a, node_b, node_c, translator_node], { node_a: { node_b: RequirementSet.trivial(), translator_node: RequirementSet.trivial(), }, node_b: { node_a: RequirementSet.trivial(), }, node_c: { translator_node: RequirementSet.trivial(), }, translator_node: { node_a: RequirementSet.trivial(), node_c: RequirementSet.trivial(), }, }) ]) ]) game = GameDescription(0, "", DockWeaknessDatabase([], [], [], []), echoes_resource_database, RequirementSet.impossible(), None, {}, world_list) patches = GamePatches.with_game(game) patches = patches.assign_gate_assignment({TranslatorGate(1): scan_visor}) initial_state = State({scan_visor: 1 if has_translator else 0}, (), 99, node_a, patches, None, echoes_resource_database) # Run reach = reach_with_all_safe_resources(game, initial_state) # Assert if has_translator: assert set( reach.safe_nodes) == {node_a, node_b, translator_node, node_c} else: assert set(reach.safe_nodes) == {node_a, node_b}
def pretty_print_area(area: Area): world_list = _gd.world_list print(area.name) print("Asset id: {}".format(area.area_asset_id)) for node in area.nodes: print(">", node.name, type(node)) for target_node, requirements in world_list.potential_nodes_from(node, GamePatches.with_game(_gd)): if target_node is None: print(" > None?") else: print(" >", n(target_node)) requirements.pretty_print(" ") print()
def _create_base_patches( rng: Random, game: GameDescription, permalink: Permalink, available_pickups: List[PickupEntry], ) -> GamePatches: patches = GamePatches.with_game(game) patches = _add_elevator_connections_to_patches(permalink, patches) patches = patches.assign_starting_location( _starting_location_for_configuration(permalink.layout_configuration, game, rng)) patches = _sky_temple_key_distribution_logic(permalink, patches, available_pickups) return patches
def test_create_patches(mock_random: MagicMock, mock_calculate_item_pool: MagicMock, mock_sky_temple_key_distribution_logic: MagicMock, mock_retcon_playthrough_filler: MagicMock, mock_indices_for_unassigned_pickups: MagicMock, empty_patches ): # Setup seed_number: int = 91319 game = default_prime2_game_description() status_update: Union[MagicMock, Callable[[str], None]] = MagicMock() configuration = LayoutConfiguration.from_params(trick_level=LayoutTrickLevel.NO_TRICKS, sky_temple_keys=LayoutSkyTempleKeyMode.FULLY_RANDOM, elevators=LayoutRandomizedFlag.VANILLA, pickup_quantities={}, starting_location=StartingLocation.default(), starting_resources=StartingResources.from_item_loss(False), ) permalink = Permalink( seed_number=seed_number, spoiler=True, patcher_configuration=PatcherConfiguration.default(), layout_configuration=configuration, ) mock_calculate_item_pool.return_value = list(sorted(game.pickup_database.original_pickup_mapping.values())) mock_sky_temple_key_distribution_logic.return_value.starting_location = game.starting_location mock_sky_temple_key_distribution_logic.return_value.custom_initial_items = None filler_patches = mock_retcon_playthrough_filler.return_value # Run result = generator._create_patches(permalink, game, status_update) # Assert mock_random.assert_called_once_with(permalink.as_str) mock_calculate_item_pool.assert_called_once_with(permalink, game) mock_sky_temple_key_distribution_logic.assert_called_once_with(permalink, GamePatches.with_game(game), ANY) mock_retcon_playthrough_filler.assert_called_once_with(ANY, ANY, ANY, mock_random.return_value, status_update) mock_indices_for_unassigned_pickups.assert_called_once_with(mock_random.return_value, game, filler_patches.pickup_assignment, ANY) filler_patches.assign_new_pickups.assert_called_once_with(mock_indices_for_unassigned_pickups.return_value) assert result == filler_patches.assign_new_pickups.return_value
def _test_data(): data = default_data.decode_default_prime2() game = data_reader.decode_data(data) configuration = LayoutConfiguration.from_params() permalink = Permalink( seed_number=15000, spoiler=True, patcher_configuration=PatcherConfiguration.default(), layout_configuration=configuration, ) patches = GamePatches.with_game(game) patches = patches.assign_gate_assignment( base_patches_factory.gate_assignment_for_configuration( configuration, game.resource_database, Random(15000))) game, state = logic_bootstrap(configuration, game, patches) return game, state, permalink
def test_retcon_filler_integration(): layout_configuration = LayoutConfiguration.default() rng = Random("fixed-seed!") status_update = MagicMock() game = data_reader.decode_data(layout_configuration.game_data) patches = GamePatches.with_game(game) available_pickups = game.pickup_database.all_useful_pickups logic, state = logic_bootstrap(layout_configuration, game, patches) logic.game.simplify_connections(state.resources) filler_patches = retcon.retcon_playthrough_filler(logic, state, tuple(available_pickups), rng, status_update) assert filler_patches == patches
def validate_command_logic(args): debug._DEBUG_LEVEL = args.debug data = prime_database.decode_data_file(args) game = data_reader.decode_data(data) if args.layout_file is not None: description = LayoutDescription.from_file(Path(args.layout_file)) configuration = description.permalink.layout_configuration patches = description.patches else: configuration = LayoutConfiguration.default() patches = GamePatches.with_game(game).assign_pickup_assignment( game.pickup_database.original_pickup_mapping) final_state_by_resolve = resolver.resolve(configuration=configuration, game=game, patches=patches) print(final_state_by_resolve)
def test_reach_size_from_start(echoes_game_description): # Setup configuration = LayoutConfiguration.from_params( trick_level_configuration=TrickLevelConfiguration( LayoutTrickLevel.HYPERMODE), ) patches = GamePatches.with_game(echoes_game_description) patches = patches.assign_gate_assignment( base_patches_factory.gate_assignment_for_configuration( configuration, echoes_game_description.resource_database, Random(15000))) game, state = logic_bootstrap(configuration, echoes_game_description, patches) # Run reach = GeneratorReach.reach_from_state(game, state) # Assert assert len(list(reach.nodes)) == 26 assert len(list(reach.safe_nodes)) == 4
def _test_data(): data = default_data.decode_default_prime2() game = data_reader.decode_data(data, False) configuration = LayoutConfiguration.from_params( trick_level=LayoutTrickLevel.NO_TRICKS, sky_temple_keys=LayoutSkyTempleKeyMode.FULLY_RANDOM, elevators=LayoutRandomizedFlag.VANILLA, pickup_quantities={}, starting_location=StartingLocation.default(), starting_resources=StartingResources.default(), ) permalink = Permalink( seed_number=15000, spoiler=True, patcher_configuration=PatcherConfiguration.default(), layout_configuration=configuration, ) logic, state = logic_bootstrap(configuration, game, GamePatches.with_game(game)) return logic, state, permalink
def _create_patches( permalink: Permalink, game: GameDescription, status_update: Callable[[str], None], ) -> GamePatches: rng = Random(permalink.as_str) configuration = permalink.layout_configuration categories = { "translator", "major", "energy_tank", "sky_temple_key", "temple_key" } item_pool = tuple(sorted(calculate_item_pool(permalink, game))) available_pickups = list( shuffle(rng, calculate_available_pickups(item_pool, categories, None))) if configuration.starting_location.configuration != StartingLocationConfiguration.SHIP: raise GenerationFailure("The only supported StartingLocation is SHIP", permalink) if configuration.starting_resources.configuration == StartingResourcesConfiguration.CUSTOM: raise GenerationFailure("Custom StartingResources is unsupported", permalink) patches = GamePatches.with_game(game) patches = _add_elevator_connections_to_patches(permalink, patches) patches = _sky_temple_key_distribution_logic(permalink, patches, available_pickups) logic, state = logic_bootstrap(configuration, game, patches) logic.game.simplify_connections(state.resources) filler_patches = retcon_playthrough_filler(logic, state, tuple(available_pickups), rng, status_update) return filler_patches.assign_new_pickups( _indices_for_unassigned_pickups(rng, game, filler_patches.pickup_assignment, item_pool))
def _patches_with_data(request, echoes_game_data, echoes_item_database): game = data_reader.decode_data(echoes_game_data) data = { "starting_location": "Temple Grounds/Landing Site", "starting_items": {}, "elevators": { "Temple Grounds/Temple Transport C": "Great Temple/Temple Transport C", "Temple Grounds/Transport to Agon Wastes": "Agon Wastes/Transport to Temple Grounds", "Temple Grounds/Transport to Torvus Bog": "Torvus Bog/Transport to Temple Grounds", "Temple Grounds/Temple Transport B": "Great Temple/Temple Transport B", "Temple Grounds/Sky Temple Gateway": "Great Temple/Sky Temple Energy Controller", "Temple Grounds/Transport to Sanctuary Fortress": "Sanctuary Fortress/Transport to Temple Grounds", "Temple Grounds/Temple Transport A": "Great Temple/Temple Transport A", "Great Temple/Temple Transport A": "Temple Grounds/Temple Transport A", "Great Temple/Temple Transport C": "Temple Grounds/Temple Transport C", "Great Temple/Temple Transport B": "Temple Grounds/Temple Transport B", "Great Temple/Sky Temple Energy Controller": "Temple Grounds/Sky Temple Gateway", "Agon Wastes/Transport to Temple Grounds": "Temple Grounds/Transport to Agon Wastes", "Agon Wastes/Transport to Torvus Bog": "Torvus Bog/Transport to Agon Wastes", "Agon Wastes/Transport to Sanctuary Fortress": "Sanctuary Fortress/Transport to Agon Wastes", "Torvus Bog/Transport to Temple Grounds": "Temple Grounds/Transport to Torvus Bog", "Torvus Bog/Transport to Agon Wastes": "Agon Wastes/Transport to Torvus Bog", "Torvus Bog/Transport to Sanctuary Fortress": "Sanctuary Fortress/Transport to Torvus Bog", "Sanctuary Fortress/Transport to Temple Grounds": "Temple Grounds/Transport to Sanctuary Fortress", "Sanctuary Fortress/Transport to Agon Wastes": "Agon Wastes/Transport to Sanctuary Fortress", "Sanctuary Fortress/Transport to Torvus Bog": "Torvus Bog/Transport to Sanctuary Fortress" }, "translators": {}, "locations": { world.name: { game.world_list.node_name(node): "Nothing" for node in world.all_nodes if node.is_resource_node and isinstance(node, PickupNode) } for world in sorted(game.world_list.worlds, key=lambda w: w.name) }, "hints": {}, "_locations_internal": "", } patches = GamePatches.with_game(game) if request.param.get("starting_item"): item_name = request.param.get("starting_item") patches = patches.assign_extra_initial_items({ find_resource_info_with_long_name(game.resource_database.item, item_name): 1, }) data["starting_items"][item_name] = 1 if request.param.get("elevator"): elevator_id, elevator_source = request.param.get("elevator") elevator_connection = copy.copy(patches.elevator_connection) elevator_connection[elevator_id] = game.starting_location patches = dataclasses.replace(patches, elevator_connection=elevator_connection) data["elevators"][elevator_source] = "Temple Grounds/Landing Site" if request.param.get("translator"): gates = {} for index, gate_name, translator in request.param.get("translator"): gates[TranslatorGate(index)] = find_resource_info_with_long_name( game.resource_database.item, translator) data["translators"][gate_name] = translator patches = patches.assign_gate_assignment(gates) if request.param.get("pickup"): data["_locations_internal"], pickup_name = request.param.get("pickup") pickup = pickup_creator.create_major_item( echoes_item_database.major_items[pickup_name], MajorItemState(), True, game.resource_database, None, False) patches = patches.assign_new_pickups([(PickupIndex(5), pickup)]) data["locations"]["Temple Grounds"][ 'Transport to Agon Wastes/Pickup (Missile)'] = pickup_name if request.param.get("hint"): asset, hint = request.param.get("hint") patches = patches.assign_hint(LogbookAsset(asset), Hint.from_json(hint)) data["hints"][str(asset)] = hint return data, patches
def test_create_elevators_field_elevators_for_a_seed(vanilla_gateway: bool, echoes_resource_database, empty_patches): # Setup game = data_reader.decode_data(default_data.decode_default_prime2()) patches = GamePatches.with_game(game) elevator_connection = copy.copy(patches.elevator_connection) elevator_connection[589851] = AreaLocation(464164546, 900285955) elevator_connection[1572998] = AreaLocation(1039999561, 3479543630) if not vanilla_gateway: elevator_connection[136970379] = AreaLocation(2252328306, 3619928121) patches = dataclasses.replace(patches, elevator_connection=elevator_connection) # Run result = patcher_file._create_elevators_field(patches, game) # Assert expected = [ {"instance_id": 589851, "origin_location": {"world_asset_id": 1006255871, "area_asset_id": 2918020398}, "target_location": {"world_asset_id": 464164546, "area_asset_id": 900285955}, "room_name": "Transport to Sanctuary Spider side"}, {"instance_id": 1572998, "origin_location": {"world_asset_id": 1006255871, "area_asset_id": 1660916974}, "target_location": {"world_asset_id": 1039999561, "area_asset_id": 3479543630}, "room_name": "Transport to Torvus Temple Access"}, {"instance_id": 1966093, "origin_location": {"world_asset_id": 1006255871, "area_asset_id": 2889020216}, "target_location": {"world_asset_id": 1039999561, "area_asset_id": 1868895730}, "room_name": "Transport to Torvus Entrance"}, {"instance_id": 2097251, "origin_location": {"world_asset_id": 1006255871, "area_asset_id": 1287880522}, "target_location": {"world_asset_id": 2252328306, "area_asset_id": 2399252740}, "room_name": "Transport to Temple Transport Violet"}, {"instance_id": 136970379, "origin_location": {"world_asset_id": 1006255871, "area_asset_id": 2278776548}, "target_location": {"world_asset_id": 2252328306, "area_asset_id": 2068511343 if vanilla_gateway else 3619928121}, "room_name": "Sky Temple Gateway" if vanilla_gateway else "Transport to Sanctum"}, {"instance_id": 3342446, "origin_location": {"world_asset_id": 1006255871, "area_asset_id": 3455543403}, "target_location": {"world_asset_id": 464164546, "area_asset_id": 3528156989}, "room_name": "Transport to Sanctuary Entrance"}, {"instance_id": 3538975, "origin_location": {"world_asset_id": 1006255871, "area_asset_id": 1345979968}, "target_location": {"world_asset_id": 2252328306, "area_asset_id": 408633584}, "room_name": "Transport to Temple Transport Emerald"}, {"instance_id": 152, "origin_location": {"world_asset_id": 2252328306, "area_asset_id": 408633584}, "target_location": {"world_asset_id": 1006255871, "area_asset_id": 1345979968}, "room_name": "Transport to Sanctuary Quadrant"}, {"instance_id": 393260, "origin_location": {"world_asset_id": 2252328306, "area_asset_id": 2556480432}, "target_location": {"world_asset_id": 1006255871, "area_asset_id": 2918020398}, "room_name": "Transport to Torvus Quadrant"}, {"instance_id": 524321, "origin_location": {"world_asset_id": 2252328306, "area_asset_id": 2399252740}, "target_location": {"world_asset_id": 1006255871, "area_asset_id": 1287880522}, "room_name": "Transport to Agon Quadrant"}, {"instance_id": 589949, "origin_location": {"world_asset_id": 2252328306, "area_asset_id": 2068511343}, "target_location": {"world_asset_id": 1006255871, "area_asset_id": 2278776548}, "room_name": "Sky Temple Energy Controller"}, {"instance_id": 122, "origin_location": {"world_asset_id": 1119434212, "area_asset_id": 1473133138}, "target_location": {"world_asset_id": 1006255871, "area_asset_id": 1660916974}, "room_name": "Transport to Agon Gate"}, {"instance_id": 1245307, "origin_location": {"world_asset_id": 1119434212, "area_asset_id": 2806956034}, "target_location": {"world_asset_id": 1039999561, "area_asset_id": 3479543630}, "room_name": "Transport to Torvus Temple Access"}, {"instance_id": 2949235, "origin_location": {"world_asset_id": 1119434212, "area_asset_id": 3331021649}, "target_location": {"world_asset_id": 464164546, "area_asset_id": 900285955}, "room_name": "Transport to Sanctuary Spider side"}, {"instance_id": 129, "origin_location": {"world_asset_id": 1039999561, "area_asset_id": 1868895730}, "target_location": {"world_asset_id": 1006255871, "area_asset_id": 2889020216}, "room_name": "Transport to Torvus Gate"}, {"instance_id": 2162826, "origin_location": {"world_asset_id": 1039999561, "area_asset_id": 3479543630}, "target_location": {"world_asset_id": 1119434212, "area_asset_id": 2806956034}, "room_name": "Transport to Agon Portal Access"}, {"instance_id": 4522032, "origin_location": {"world_asset_id": 1039999561, "area_asset_id": 3205424168}, "target_location": {"world_asset_id": 464164546, "area_asset_id": 3145160350}, "room_name": "Transport to Sanctuary Vault side"}, {"instance_id": 38, "origin_location": {"world_asset_id": 464164546, "area_asset_id": 3528156989}, "target_location": {"world_asset_id": 1006255871, "area_asset_id": 3455543403}, "room_name": "Transport to Sanctuary Gate"}, {"instance_id": 1245332, "origin_location": {"world_asset_id": 464164546, "area_asset_id": 900285955}, "target_location": {"world_asset_id": 1119434212, "area_asset_id": 3331021649}, "room_name": "Transport to Agon Temple Access"}, {"instance_id": 1638535, "origin_location": {"world_asset_id": 464164546, "area_asset_id": 3145160350}, "target_location": {"world_asset_id": 1039999561, "area_asset_id": 3205424168}, "room_name": "Transport to Lower Torvus Access"} ] assert result == expected