mirror of
				https://github.com/MarioSpore/Grinch-AP.git
				synced 2025-10-21 20:21:32 -06:00 
			
		
		
		
	
		
			
	
	
		
			50 lines
		
	
	
		
			1.8 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
		
		
			
		
	
	
			50 lines
		
	
	
		
			1.8 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
|   | from __future__ import annotations | ||
|  | 
 | ||
|  | from typing import TYPE_CHECKING, Callable, Hashable, TypeVar | ||
|  | 
 | ||
|  | if TYPE_CHECKING: | ||
|  |     from .bot_ai import BotAI | ||
|  | 
 | ||
|  | T = TypeVar("T") | ||
|  | 
 | ||
|  | 
 | ||
|  | class CacheDict(dict): | ||
|  | 
 | ||
|  |     def retrieve_and_set(self, key: Hashable, func: Callable[[], T]) -> T: | ||
|  |         """ Either return the value at a certain key,
 | ||
|  |         or set the return value of a function to that key, then return that value. """
 | ||
|  |         if key not in self: | ||
|  |             self[key] = func() | ||
|  |         return self[key] | ||
|  | 
 | ||
|  | 
 | ||
|  | class property_cache_once_per_frame(property): | ||
|  |     """This decorator caches the return value for one game loop,
 | ||
|  |     then clears it if it is accessed in a different game loop. | ||
|  |     Only works on properties of the bot object, because it requires | ||
|  |     access to self.state.game_loop | ||
|  | 
 | ||
|  |     This decorator compared to the above runs a little faster, however you should only use this decorator if you are sure that you do not modify the mutable once it is calculated and cached. | ||
|  | 
 | ||
|  |     Copied and modified from https://tedboy.github.io/flask/_modules/werkzeug/utils.html#cached_property | ||
|  |     # """ | ||
|  | 
 | ||
|  |     def __init__(self, func: Callable[[BotAI], T], name=None): | ||
|  |         # pylint: disable=W0231 | ||
|  |         self.__name__ = name or func.__name__ | ||
|  |         self.__frame__ = f"__frame__{self.__name__}" | ||
|  |         self.func = func | ||
|  | 
 | ||
|  |     def __set__(self, obj: BotAI, value: T): | ||
|  |         obj.cache[self.__name__] = value | ||
|  |         obj.cache[self.__frame__] = obj.state.game_loop | ||
|  | 
 | ||
|  |     def __get__(self, obj: BotAI, _type=None) -> T: | ||
|  |         value = obj.cache.get(self.__name__, None) | ||
|  |         bot_frame = obj.state.game_loop | ||
|  |         if value is None or obj.cache[self.__frame__] < bot_frame: | ||
|  |             value = self.func(obj) | ||
|  |             obj.cache[self.__name__] = value | ||
|  |             obj.cache[self.__frame__] = bot_frame | ||
|  |         return value |