78 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
		
		
			
		
	
	
			78 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
|   | from typing import Dict, FrozenSet, Tuple, cast, List, Counter as _Counter | ||
|  | from BaseClasses import CollectionState | ||
|  | from zilliandomizer.logic_components.locations import Location | ||
|  | from zilliandomizer.randomizer import Randomizer | ||
|  | from zilliandomizer.logic_components.items import Item, items | ||
|  | from .region import ZillionLocation | ||
|  | from .item import ZillionItem | ||
|  | from .id_maps import item_name_to_id | ||
|  | 
 | ||
|  | zz_empty = items[4] | ||
|  | 
 | ||
|  | # TODO: unit tests for these | ||
|  | 
 | ||
|  | 
 | ||
|  | def set_randomizer_locs(cs: CollectionState, p: int, zz_r: Randomizer) -> int: | ||
|  |     """
 | ||
|  |     sync up zilliandomizer locations with archipelago locations | ||
|  | 
 | ||
|  |     returns a hash of the player and of the set locations with their items | ||
|  |     """
 | ||
|  |     z_world = cs.world.worlds[p] | ||
|  |     my_locations = cast(List[ZillionLocation], getattr(z_world, "my_locations")) | ||
|  | 
 | ||
|  |     _hash = p | ||
|  |     for z_loc in my_locations: | ||
|  |         zz_name = z_loc.zz_loc.name | ||
|  |         zz_item = z_loc.item.zz_item \ | ||
|  |             if isinstance(z_loc.item, ZillionItem) and z_loc.item.player == p \ | ||
|  |             else zz_empty | ||
|  |         zz_r.locations[zz_name].item = zz_item | ||
|  |         _hash += hash(zz_name) ^ hash(zz_item) | ||
|  |     return _hash | ||
|  | 
 | ||
|  | 
 | ||
|  | def item_counts(cs: CollectionState, p: int) -> Tuple[Tuple[str, int], ...]: | ||
|  |     """
 | ||
|  |     the zilliandomizer items that player p has collected | ||
|  | 
 | ||
|  |     ((item_name, count), (item_name, count), ...) | ||
|  |     """
 | ||
|  |     return tuple((item_name, cs.item_count(item_name, p)) for item_name in item_name_to_id) | ||
|  | 
 | ||
|  | 
 | ||
|  | LogicCacheType = Dict[int, Tuple[_Counter[Tuple[str, int]], FrozenSet[Location]]] | ||
|  | 
 | ||
|  | 
 | ||
|  | def cs_to_zz_locs(cs: CollectionState, p: int, zz_r: Randomizer, id_to_zz_item: Dict[int, Item]) -> FrozenSet[Location]: | ||
|  |     """
 | ||
|  |     given an Archipelago `CollectionState`, | ||
|  |     returns frozenset of accessible zilliandomizer locations | ||
|  |     """
 | ||
|  |     # caching this function because it would be slow | ||
|  |     logic_cache: LogicCacheType = getattr(cs.world, "zillion_logic_cache", {}) | ||
|  |     _hash = set_randomizer_locs(cs, p, zz_r) | ||
|  |     counts = item_counts(cs, p) | ||
|  |     _hash += hash(counts) | ||
|  | 
 | ||
|  |     if _hash in logic_cache and logic_cache[_hash][0] == cs.prog_items: | ||
|  |         # print("cache hit") | ||
|  |         return logic_cache[_hash][1] | ||
|  | 
 | ||
|  |     # print("cache miss") | ||
|  |     have_items: List[Item] = [] | ||
|  |     for name, count in counts: | ||
|  |         have_items.extend([id_to_zz_item[item_name_to_id[name]]] * count) | ||
|  |     # have_req is the result of converting AP CollectionState to zilliandomizer collection state | ||
|  |     have_req = zz_r.make_ability(have_items) | ||
|  | 
 | ||
|  |     # This `get_locations` is where the core of the logic comes in. | ||
|  |     # It takes a zilliandomizer collection state (a set of the abilities that I have) | ||
|  |     # and returns list of all the zilliandomizer locations I can access with those abilities. | ||
|  |     tr = frozenset(zz_r.get_locations(have_req)) | ||
|  | 
 | ||
|  |     # save result in cache | ||
|  |     logic_cache[_hash] = (cs.prog_items.copy(), tr) | ||
|  | 
 | ||
|  |     return tr |