diff --git a/worlds/witness/__init__.py b/worlds/witness/__init__.py index 6d6407d1..36cddf82 100644 --- a/worlds/witness/__init__.py +++ b/worlds/witness/__init__.py @@ -1,7 +1,7 @@ """ Archipelago init file for The Witness """ -import typing +from typing import Dict, Optional from BaseClasses import Region, Location, MultiWorld, Item, Entrance, Tutorial from .hints import get_always_hint_locations, get_always_hint_items, get_priority_hint_locations, \ @@ -113,7 +113,7 @@ class WitnessWorld(World): pool_size: int = len(self.locat.CHECK_LOCATION_TABLE) - len(self.locat.EVENT_LOCATION_TABLE) - 1 # Fill mandatory items and remove precollected and/or starting items from the pool. - item_pool: dict[str, int] = self.items.get_mandatory_items() + item_pool: Dict[str, int] = self.items.get_mandatory_items() for precollected_item_name in [item.name for item in self.multiworld.precollected_items[self.player]]: if precollected_item_name in item_pool: @@ -250,7 +250,7 @@ class WitnessLocation(Location): game: str = "The Witness" check_hex: int = -1 - def __init__(self, player: int, name: str, address: typing.Optional[int], parent, ch_hex: int = -1): + def __init__(self, player: int, name: str, address: Optional[int], parent, ch_hex: int = -1): super().__init__(player, name, address, parent) self.check_hex = ch_hex diff --git a/worlds/witness/items.py b/worlds/witness/items.py index 8079acf4..7519f960 100644 --- a/worlds/witness/items.py +++ b/worlds/witness/items.py @@ -3,7 +3,7 @@ Defines progression, junk and event items for The Witness """ import copy from dataclasses import dataclass -from typing import Optional +from typing import Optional, Dict, List from BaseClasses import Item, MultiWorld, ItemClassification from .Options import get_option_value, is_option_enabled, the_witness_options @@ -39,12 +39,12 @@ class StaticWitnessItems: """ Class that handles Witness items independent of world settings """ - item_data: dict[str, ItemData] = {} - item_groups: dict[str, list[str]] = {} + item_data: Dict[str, ItemData] = {} + item_groups: Dict[str, List[str]] = {} # Useful items that are treated specially at generation time and should not be automatically added to the player's # item list during get_progression_items. - special_usefuls: list[str] = ["Puzzle Skip"] + special_usefuls: List[str] = ["Puzzle Skip"] def __init__(self): for item_name, definition in StaticWitnessLogic.all_items.items(): @@ -76,8 +76,8 @@ class StaticWitnessItems: classification, local_only) @staticmethod - def get_item_to_door_mappings() -> dict[int, list[int]]: - output: dict[int, list[int]] = {} + def get_item_to_door_mappings() -> Dict[int, List[int]]: + output: Dict[int, List[int]] = {} for item_name, item_data in {name: data for name, data in StaticWitnessItems.item_data.items() if isinstance(data.definition, DoorItemDefinition)}.items(): item = StaticWitnessItems.item_data[item_name] @@ -99,7 +99,7 @@ class WitnessPlayerItems: self._locations: WitnessPlayerLocations = locat # Duplicate the static item data, then make any player-specific adjustments to classification. - self.item_data: dict[str, ItemData] = copy.copy(StaticWitnessItems.item_data) + self.item_data: Dict[str, ItemData] = copy.copy(StaticWitnessItems.item_data) # Remove all progression items that aren't actually in the game. self.item_data = {name: data for (name, data) in self.item_data.items() @@ -119,7 +119,7 @@ class WitnessPlayerItems: item_data.classification = ItemClassification.useful # Build the mandatory item list. - self._mandatory_items: dict[str, int] = {} + self._mandatory_items: Dict[str, int] = {} # Add progression items to the mandatory item list. for item_name, item_data in {name: data for (name, data) in self.item_data.items() @@ -148,20 +148,20 @@ class WitnessPlayerItems: self.item_data[location_name] = ItemData(None, ItemDefinition(0, ItemCategory.EVENT), ItemClassification.progression, False) - def get_mandatory_items(self) -> dict[str, int]: + def get_mandatory_items(self) -> Dict[str, int]: """ Returns the list of items that must be in the pool for the game to successfully generate. """ return self._mandatory_items - def get_filler_items(self, quantity: int) -> dict[str, int]: + def get_filler_items(self, quantity: int) -> Dict[str, int]: """ Generates a list of filler items of the given length. """ if quantity <= 0: return {} - output: dict[str, int] = {} + output: Dict[str, int] = {} remaining_quantity = quantity # Add joke items. @@ -174,7 +174,7 @@ class WitnessPlayerItems: filler_weight = 1 - trap_weight # Add filler items to the list. - filler_items: dict[str, float] + filler_items: Dict[str, float] filler_items = {name: data.definition.weight if isinstance(data.definition, WeightedItemDefinition) else 1 for (name, data) in self.item_data.items() if data.definition.category is ItemCategory.FILLER} filler_items = {name: base_weight * filler_weight / sum(filler_items.values()) @@ -188,16 +188,16 @@ class WitnessPlayerItems: for name, base_weight in trap_items.items() if base_weight > 0}) # Get the actual number of each item by scaling the float weight values to match the target quantity. - int_weights: list[int] = build_weighted_int_list(filler_items.values(), remaining_quantity) + int_weights: List[int] = build_weighted_int_list(filler_items.values(), remaining_quantity) output.update(zip(filler_items.keys(), int_weights)) return output - def get_early_items(self) -> list[str]: + def get_early_items(self) -> List[str]: """ Returns items that are ideal for placing on extremely early checks, like the tutorial gate. """ - output: list[str] = [] + output: List[str] = [] if "shuffle_symbols" not in the_witness_options.keys() \ or is_option_enabled(self._world, self._player_id, "shuffle_symbols"): if get_option_value(self._world, self._player_id, "shuffle_doors") > 0: @@ -231,25 +231,25 @@ class WitnessPlayerItems: # Sort the output for consistency across versions if the implementation changes but the logic does not. return sorted(output) - def get_door_ids_in_pool(self) -> list[int]: + def get_door_ids_in_pool(self) -> List[int]: """ Returns the total set of all door IDs that are controlled by items in the pool. """ - output: list[int] = [] + output: List[int] = [] for item_name, item_data in {name: data for name, data in self.item_data.items() if isinstance(data.definition, DoorItemDefinition)}.items(): output += [int(hex_string, 16) for hex_string in item_data.definition.panel_id_hexes] return output - def get_symbol_ids_not_in_pool(self) -> list[int]: + def get_symbol_ids_not_in_pool(self) -> List[int]: """ Returns the item IDs of symbol items that were defined in the configuration file but are not in the pool. """ return [data.ap_code for name, data in StaticWitnessItems.item_data.items() if name not in self.item_data.keys() and data.definition.category is ItemCategory.SYMBOL] - def get_progressive_item_ids_in_pool(self) -> dict[int, list[int]]: - output: dict[int, list[int]] = {} + def get_progressive_item_ids_in_pool(self) -> Dict[int, List[int]]: + output: Dict[int, List[int]] = {} for item_name, quantity in {name: quantity for name, quantity in self._mandatory_items.items()}.items(): item = self.item_data[item_name] if isinstance(item.definition, ProgressiveItemDefinition): diff --git a/worlds/witness/player_logic.py b/worlds/witness/player_logic.py index 919247e8..38943773 100644 --- a/worlds/witness/player_logic.py +++ b/worlds/witness/player_logic.py @@ -16,7 +16,7 @@ When the world has parsed its options, a second function is called to finalize t """ import copy -from typing import Set, Dict, cast +from typing import Set, Dict, cast, List from logging import warning from BaseClasses import MultiWorld @@ -421,7 +421,7 @@ class WitnessPlayerLogic: self.MULTI_LISTS = dict() self.PROG_ITEMS_ACTUALLY_IN_THE_GAME_NO_MULTI = set() self.PROG_ITEMS_ACTUALLY_IN_THE_GAME = set() - self.DOOR_ITEMS_BY_ID: dict[str, list[int]] = {} + self.DOOR_ITEMS_BY_ID: Dict[str, List[int]] = {} self.STARTING_INVENTORY = set() self.DIFFICULTY = get_option_value(world, player, "puzzle_randomization") diff --git a/worlds/witness/static_logic.py b/worlds/witness/static_logic.py index 52d25fa5..8dc2a05d 100644 --- a/worlds/witness/static_logic.py +++ b/worlds/witness/static_logic.py @@ -1,5 +1,6 @@ from dataclasses import dataclass from enum import Enum +from typing import Dict, List from .utils import define_new_region, parse_lambda, lazy, get_items, get_sigma_normal_logic, get_sigma_expert_logic,\ get_vanilla_logic @@ -16,7 +17,7 @@ class ItemCategory(Enum): EVENT = 7 -CATEGORY_NAME_MAPPINGS: dict[str, ItemCategory] = { +CATEGORY_NAME_MAPPINGS: Dict[str, ItemCategory] = { "Symbols:": ItemCategory.SYMBOL, "Doors:": ItemCategory.DOOR, "Lasers:": ItemCategory.LASER, @@ -35,12 +36,12 @@ class ItemDefinition: @dataclass(frozen=True) class ProgressiveItemDefinition(ItemDefinition): - child_item_names: list[str] + child_item_names: List[str] @dataclass(frozen=True) class DoorItemDefinition(ItemDefinition): - panel_id_hexes: list[str] + panel_id_hexes: List[str] @dataclass(frozen=True) @@ -178,8 +179,8 @@ class StaticWitnessLogicObj: class StaticWitnessLogic: # Item data parsed from WitnessItems.txt - all_items: dict[str, ItemDefinition] = {} - _progressive_lookup: dict[str, str] = {} + all_items: Dict[str, ItemDefinition] = {} + _progressive_lookup: Dict[str, str] = {} ALL_REGIONS_BY_NAME = dict() STATIC_CONNECTIONS_BY_REGION_NAME = dict() @@ -200,7 +201,7 @@ class StaticWitnessLogic: Parses currently defined items from WitnessItems.txt """ - lines: list[str] = get_items() + lines: List[str] = get_items() current_category: ItemCategory = ItemCategory.SYMBOL for line in lines: @@ -217,7 +218,7 @@ class StaticWitnessLogic: item_code = int(line_split[0]) item_name = line_split[1] - arguments: list[str] = line_split[2].split(",") if len(line_split) >= 3 else [] + arguments: List[str] = line_split[2].split(",") if len(line_split) >= 3 else [] if current_category in [ItemCategory.DOOR, ItemCategory.LASER]: # Map doors to IDs. diff --git a/worlds/witness/utils.py b/worlds/witness/utils.py index 7528e49f..72dc10fd 100644 --- a/worlds/witness/utils.py +++ b/worlds/witness/utils.py @@ -1,11 +1,10 @@ from functools import lru_cache from math import floor -from typing import * -from fractions import Fraction +from typing import List, Collection from pkgutil import get_data -def build_weighted_int_list(inputs: Collection[float], total: int) -> list[int]: +def build_weighted_int_list(inputs: Collection[float], total: int) -> List[int]: """ Converts a list of floats to a list of ints of a given length, using the Largest Remainder Method. """ @@ -15,11 +14,11 @@ def build_weighted_int_list(inputs: Collection[float], total: int) -> list[int]: scaled_input = [x * scale_factor for x in inputs] # Generate whole number counts, always rounding down. - rounded_output: list[int] = [floor(x) for x in scaled_input] + rounded_output: List[int] = [floor(x) for x in scaled_input] rounded_sum = sum(rounded_output) # If the output's total is insufficient, increment the value that has the largest remainder until we meet our goal. - remainders: list[float] = [real - rounded for real, rounded in zip(scaled_input, rounded_output)] + remainders: List[float] = [real - rounded for real, rounded in zip(scaled_input, rounded_output)] while rounded_sum < total: max_remainder = max(remainders) if max_remainder == 0: