optimize sweep_for_events, some has_ functions and some minor things
This commit is contained in:
		
							parent
							
								
									cac5795e01
								
							
						
					
					
						commit
						b5048d99b9
					
				| 
						 | 
					@ -5,13 +5,13 @@ from enum import Enum, unique
 | 
				
			||||||
import logging
 | 
					import logging
 | 
				
			||||||
import json
 | 
					import json
 | 
				
			||||||
from collections import OrderedDict, Counter, deque
 | 
					from collections import OrderedDict, Counter, deque
 | 
				
			||||||
 | 
					from typing import Union, Optional
 | 
				
			||||||
 | 
					import secrets
 | 
				
			||||||
 | 
					import random
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from EntranceShuffle import door_addresses, indirect_connections
 | 
					from EntranceShuffle import door_addresses, indirect_connections
 | 
				
			||||||
from Utils import int16_as_bytes
 | 
					from Utils import int16_as_bytes
 | 
				
			||||||
from typing import Union, Optional
 | 
					from Items import item_name_groups
 | 
				
			||||||
 | 
					 | 
				
			||||||
import secrets
 | 
					 | 
				
			||||||
import random
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class World(object):
 | 
					class World(object):
 | 
				
			||||||
| 
						 | 
					@ -429,7 +429,7 @@ class CollectionState(object):
 | 
				
			||||||
        self.world = parent
 | 
					        self.world = parent
 | 
				
			||||||
        self.reachable_regions = {player: set() for player in range(1, parent.players + 1)}
 | 
					        self.reachable_regions = {player: set() for player in range(1, parent.players + 1)}
 | 
				
			||||||
        self.blocked_connections = {player: set() for player in range(1, parent.players + 1)}
 | 
					        self.blocked_connections = {player: set() for player in range(1, parent.players + 1)}
 | 
				
			||||||
        self.events = []
 | 
					        self.events = set()
 | 
				
			||||||
        self.path = {}
 | 
					        self.path = {}
 | 
				
			||||||
        self.locations_checked = set()
 | 
					        self.locations_checked = set()
 | 
				
			||||||
        self.stale = {player: True for player in range(1, parent.players + 1)}
 | 
					        self.stale = {player: True for player in range(1, parent.players + 1)}
 | 
				
			||||||
| 
						 | 
					@ -492,23 +492,19 @@ class CollectionState(object):
 | 
				
			||||||
        return spot.can_reach(self)
 | 
					        return spot.can_reach(self)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def sweep_for_events(self, key_only: bool = False, locations=None):
 | 
					    def sweep_for_events(self, key_only: bool = False, locations=None):
 | 
				
			||||||
        # this may need improvement
 | 
					 | 
				
			||||||
        if locations is None:
 | 
					        if locations is None:
 | 
				
			||||||
            locations = self.world.get_filled_locations()
 | 
					            locations = self.world.get_filled_locations()
 | 
				
			||||||
        new_locations = True
 | 
					        new_locations = True
 | 
				
			||||||
        checked_locations = 0
 | 
					 | 
				
			||||||
        while new_locations:
 | 
					        while new_locations:
 | 
				
			||||||
            reachable_events = [location for location in locations if location.event and
 | 
					            reachable_events = {location for location in locations if location.event and
 | 
				
			||||||
                                (not key_only or (not self.world.keyshuffle[
 | 
					                                (not key_only or (not self.world.keyshuffle[
 | 
				
			||||||
                                    location.item.player] and location.item.smallkey) or (not self.world.bigkeyshuffle[
 | 
					                                    location.item.player] and location.item.smallkey) or (not self.world.bigkeyshuffle[
 | 
				
			||||||
                                    location.item.player] and location.item.bigkey))
 | 
					                                    location.item.player] and location.item.bigkey))
 | 
				
			||||||
                                and location.can_reach(self)]
 | 
					                                and location.can_reach(self)}
 | 
				
			||||||
            for event in reachable_events:
 | 
					            new_locations = reachable_events - self.events
 | 
				
			||||||
                if event not in self.events:
 | 
					            for event in new_locations:
 | 
				
			||||||
                    self.events.append(event)
 | 
					                self.events.add(event)
 | 
				
			||||||
                    self.collect(event.item, True, event)
 | 
					                self.collect(event.item, True, event)
 | 
				
			||||||
            new_locations = len(reachable_events) > checked_locations
 | 
					 | 
				
			||||||
            checked_locations = len(reachable_events)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def has(self, item, player: int, count: int = 1):
 | 
					    def has(self, item, player: int, count: int = 1):
 | 
				
			||||||
        return self.prog_items[item, player] >= count
 | 
					        return self.prog_items[item, player] >= count
 | 
				
			||||||
| 
						 | 
					@ -532,11 +528,10 @@ class CollectionState(object):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def has_crystals(self, count: int, player: int) -> bool:
 | 
					    def has_crystals(self, count: int, player: int) -> bool:
 | 
				
			||||||
        found: int = 0
 | 
					        found: int = 0
 | 
				
			||||||
        for itemname, itemplayer in self.prog_items:
 | 
					        for crystalnumber in range(1, 8):
 | 
				
			||||||
            if itemplayer == player and itemname.startswith('Crystal '):
 | 
					            found += self.prog_items[f"Crystal {crystalnumber}", player]
 | 
				
			||||||
                found += 1
 | 
					            if found >= count:
 | 
				
			||||||
                if found >= count:
 | 
					                return True
 | 
				
			||||||
                    return True
 | 
					 | 
				
			||||||
        return False
 | 
					        return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def can_lift_rocks(self, player: int):
 | 
					    def can_lift_rocks(self, player: int):
 | 
				
			||||||
| 
						 | 
					@ -546,17 +541,18 @@ class CollectionState(object):
 | 
				
			||||||
        return self.has_bottles(1, player)
 | 
					        return self.has_bottles(1, player)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def bottle_count(self, player: int) -> int:
 | 
					    def bottle_count(self, player: int) -> int:
 | 
				
			||||||
        return len(
 | 
					        found: int = 0
 | 
				
			||||||
            tuple(item for (item, itemplayer) in self.prog_items if itemplayer == player and item.startswith('Bottle')))
 | 
					        for bottlename in item_name_groups["Bottles"]:
 | 
				
			||||||
 | 
					            found += self.prog_items[bottlename, player]
 | 
				
			||||||
 | 
					        return found
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def has_bottles(self, bottles: int, player: int):
 | 
					    def has_bottles(self, bottles: int, player: int) -> bool:
 | 
				
			||||||
        """Version of bottle_count that allows fast abort"""
 | 
					        """Version of bottle_count that allows fast abort"""
 | 
				
			||||||
        found: int = 0
 | 
					        found: int = 0
 | 
				
			||||||
        for itemname, itemplayer in self.prog_items:
 | 
					        for bottlename in item_name_groups["Bottles"]:
 | 
				
			||||||
            if itemplayer == player and itemname.startswith('Bottle'):
 | 
					            found += self.prog_items[bottlename, player]
 | 
				
			||||||
                found += 1
 | 
					            if found >= bottles:
 | 
				
			||||||
                if found >= bottles:
 | 
					                return True
 | 
				
			||||||
                    return True
 | 
					 | 
				
			||||||
        return False
 | 
					        return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def has_hearts(self, player: int, count: int) -> int:
 | 
					    def has_hearts(self, player: int, count: int) -> int:
 | 
				
			||||||
| 
						 | 
					@ -995,6 +991,9 @@ class Location(object):
 | 
				
			||||||
        world = self.parent_region.world if self.parent_region and self.parent_region.world else None
 | 
					        world = self.parent_region.world if self.parent_region and self.parent_region.world else None
 | 
				
			||||||
        return world.get_name_string_for_object(self) if world else f'{self.name} (Player {self.player})'
 | 
					        return world.get_name_string_for_object(self) if world else f'{self.name} (Player {self.player})'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __hash__(self):
 | 
				
			||||||
 | 
					        return hash((self.name, self.player))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Item(object):
 | 
					class Item(object):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										2
									
								
								Fill.py
								
								
								
								
							
							
						
						
									
										2
									
								
								Fill.py
								
								
								
								
							| 
						 | 
					@ -209,7 +209,7 @@ def fill_restrictive(world, base_state: CollectionState, locations, itempool, si
 | 
				
			||||||
                            if location.item and not location.event:
 | 
					                            if location.item and not location.event:
 | 
				
			||||||
                                placements.append(location)
 | 
					                                placements.append(location)
 | 
				
			||||||
                    raise FillError(f'No more spots to place {item_to_place}, locations {locations} are invalid. '
 | 
					                    raise FillError(f'No more spots to place {item_to_place}, locations {locations} are invalid. '
 | 
				
			||||||
                                    f'\nAlready placed {len(placements)}: {", ".join(placements)}')
 | 
					                                    f'Already placed {len(placements)}: {", ".join(placements)}')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                world.push_item(spot_to_fill, item_to_place, False)
 | 
					                world.push_item(spot_to_fill, item_to_place, False)
 | 
				
			||||||
                locations.remove(spot_to_fill)
 | 
					                locations.remove(spot_to_fill)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										2
									
								
								Items.py
								
								
								
								
							
							
						
						
									
										2
									
								
								Items.py
								
								
								
								
							| 
						 | 
					@ -1,9 +1,9 @@
 | 
				
			||||||
import logging
 | 
					import logging
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from BaseClasses import Item
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def ItemFactory(items, player):
 | 
					def ItemFactory(items, player):
 | 
				
			||||||
 | 
					    from BaseClasses import Item
 | 
				
			||||||
    ret = []
 | 
					    ret = []
 | 
				
			||||||
    singleton = False
 | 
					    singleton = False
 | 
				
			||||||
    if isinstance(items, str):
 | 
					    if isinstance(items, str):
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										2
									
								
								Rom.py
								
								
								
								
							
							
						
						
									
										2
									
								
								Rom.py
								
								
								
								
							| 
						 | 
					@ -348,6 +348,8 @@ def _populate_sprite_table():
 | 
				
			||||||
                if sprite.valid:
 | 
					                if sprite.valid:
 | 
				
			||||||
                    _sprite_table[sprite.name.lower()] = sprite
 | 
					                    _sprite_table[sprite.name.lower()] = sprite
 | 
				
			||||||
                    _sprite_table[os.path.basename(file).split(".")[0].lower()] = sprite  # alias for filename base
 | 
					                    _sprite_table[os.path.basename(file).split(".")[0].lower()] = sprite  # alias for filename base
 | 
				
			||||||
 | 
					                else:
 | 
				
			||||||
 | 
					                    logging.debug(f"Spritefile {file} could not be loaded as a valid sprite.")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            with concurrent.futures.ThreadPoolExecutor() as pool:
 | 
					            with concurrent.futures.ThreadPoolExecutor() as pool:
 | 
				
			||||||
                for dir in [local_path('data/sprites/alttpr'), local_path('data/sprites/custom')]:
 | 
					                for dir in [local_path('data/sprites/alttpr'), local_path('data/sprites/custom')]:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -17,17 +17,18 @@
 | 
				
			||||||
# To test if your yaml is valid or not, you can use this website:
 | 
					# To test if your yaml is valid or not, you can use this website:
 | 
				
			||||||
# http://www.yamllint.com/
 | 
					# http://www.yamllint.com/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
description: Your Description Here # Used to describe your yaml. Useful if you have multiple files
 | 
					description: easy template # Used to describe your yaml. Useful if you have multiple files
 | 
				
			||||||
name: YourName # Your name in-game. Spaces and underscores will be replaced with dashes
 | 
					name: YourName # Your name in-game. Spaces will be replaced with underscores and there is a 16 character limit
 | 
				
			||||||
glitches_required: # Determine the logic required to complete the seed
 | 
					glitches_required: # Determine the logic required to complete the seed
 | 
				
			||||||
  none: 1 # No glitches required
 | 
					  none: 1 # No glitches required
 | 
				
			||||||
  minor_glitches: 0 # Puts fake flipper, waterwalk, super bunny shenanigans, and etc into logic
 | 
					  minor_glitches: 0 # Puts fake flipper, waterwalk, super bunny shenanigans, and etc into logic
 | 
				
			||||||
  overworld_glitches: 0 # Assumes the player has knowledge of both overworld major glitches (boots clips, mirror clips) and minor glitches (fake flipper, super bunny shenanigans, water walk and etc.)
 | 
					  overworld_glitches: 0 # Assumes the player has knowledge of both overworld major glitches (boots clips, mirror clips) and minor glitches (fake flipper, super bunny shenanigans, water walk and etc.)
 | 
				
			||||||
  no_logic: 0 # Items are places completely at random and with no regard for logic. Your fire rod could be on Trinexx
 | 
					  no_logic: 0 # Items are places completely at random and with no regard for logic. Your fire rod could be on Trinexx
 | 
				
			||||||
meta_ignore: # Nullify options specified in the meta.yaml file. Adding an option here guarantees it will not occur in your seed, even if the .yaml file specifies it
 | 
					meta_ignore: # Nullify options specified in the meta.yaml file. Adding an option here guarantees it will not occur in your seed, even if the .yaml file specifies it
 | 
				
			||||||
  world_state:
 | 
					  mode:
 | 
				
			||||||
    - inverted # Never play inverted seeds
 | 
					    - inverted # Never play inverted seeds
 | 
				
			||||||
    - retro # Never play retro seeds
 | 
					  retro:
 | 
				
			||||||
 | 
					    - on # Never play retro seeds
 | 
				
			||||||
  weapons:
 | 
					  weapons:
 | 
				
			||||||
    - swordless # Never play a swordless seed
 | 
					    - swordless # Never play a swordless seed
 | 
				
			||||||
map_shuffle: # Shuffle dungeon maps into the world and other dungeons, including other players' worlds
 | 
					map_shuffle: # Shuffle dungeon maps into the world and other dungeons, including other players' worlds
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue