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
							 |