Witness: Fix type hints being incompatible with 3.8 (#1991)

* Fixed 3.8 typing in init

* Fixed 3.8 typing in items

* Fixed 3.8 typing in player logic

* Fixed 3.8 typing in static_logic

* Fix 3.8 typing in utils

* Fixed fault import
This commit is contained in:
NewSoupVi 2023-07-20 02:10:48 +02:00 committed by GitHub
parent 1e72851b28
commit 6797216eb8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 37 additions and 37 deletions

View File

@ -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

View File

@ -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):

View File

@ -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")

View File

@ -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.

View File

@ -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: