# object to handle the smbools and optimize them from logic.cache import Cache from logic.smbool import SMBool, smboolFalse from logic.helpers import Bosses from logic.logic import Logic from utils.doorsmanager import DoorsManager from utils.parameters import Knows, isKnows import logging import sys class SMBoolManager(object): items = ['ETank', 'Missile', 'Super', 'PowerBomb', 'Bomb', 'Charge', 'Ice', 'HiJump', 'SpeedBooster', 'Wave', 'Spazer', 'SpringBall', 'Varia', 'Plasma', 'Grapple', 'Morph', 'Reserve', 'Gravity', 'XRayScope', 'SpaceJump', 'ScrewAttack', 'Nothing', 'NoEnergy', 'MotherBrain', 'Hyper'] + Bosses.Golden4() countItems = ['Missile', 'Super', 'PowerBomb', 'ETank', 'Reserve'] def __init__(self, player=0, maxDiff=sys.maxsize, onlyBossLeft = False): self._items = { } self._counts = { } self.player = player self.maxDiff = maxDiff self.onlyBossLeft = onlyBossLeft # cache related self.cacheKey = 0 self.computeItemsPositions() Cache.reset() Logic.factory('vanilla') self.helpers = Logic.HelpersGraph(self) self.doorsManager = DoorsManager() self.createFacadeFunctions() self.createKnowsFunctions(player) self.resetItems() def computeItemsPositions(self): # compute index in cache key for each items self.itemsPositions = {} maxBitsForCountItem = 7 # 128 values with 7 bits for (i, item) in enumerate(self.countItems): pos = i*maxBitsForCountItem bitMask = (2<<(maxBitsForCountItem-1))-1 bitMask = bitMask << pos self.itemsPositions[item] = (pos, bitMask) for (i, item) in enumerate(self.items, (i+1)*maxBitsForCountItem+1): if item in self.countItems: continue self.itemsPositions[item] = (i, 1<> pos if value != 0: msg += " {}: {}".format(item, value) print("items:{}".format(msg)) def isEmpty(self): for item in self.items: if self.haveItem(item): return False for item in self.countItems: if self.itemCount(item) > 0: return False return True def getItems(self): # get a dict of collected items and how many (to be displayed on the solver spoiler) itemsDict = {} for item in self.items: itemsDict[item] = 1 if self._items[item] == True else 0 for item in self.countItems: itemsDict[item] = self._counts[item] return itemsDict def withItem(self, item, func): self.addItem(item) ret = func(self) self.removeItem(item) return ret def resetItems(self): self._items = { item : smboolFalse for item in self.items } self._counts = { item : 0 for item in self.countItems } self.cacheKey = 0 Cache.update(self.cacheKey) def addItem(self, item): # a new item is available self._items[item] = SMBool(True, items=[item]) if self.isCountItem(item): count = self._counts[item] + 1 self._counts[item] = count self.computeNewCacheKey(item, count) else: self.computeNewCacheKey(item, 1) Cache.update(self.cacheKey) def addItems(self, items): if len(items) == 0: return for item in items: self._items[item] = SMBool(True, items=[item]) if self.isCountItem(item): count = self._counts[item] + 1 self._counts[item] = count self.computeNewCacheKey(item, count) else: self.computeNewCacheKey(item, 1) Cache.update(self.cacheKey) def removeItem(self, item): # randomizer removed an item (or the item was added to test a post available) if self.isCountItem(item): count = self._counts[item] - 1 self._counts[item] = count if count == 0: self._items[item] = smboolFalse self.computeNewCacheKey(item, count) else: self._items[item] = smboolFalse self.computeNewCacheKey(item, 0) Cache.update(self.cacheKey) def createFacadeFunctions(self): for fun in dir(self.helpers): if fun != 'smbm' and fun[0:2] != '__': setattr(self, fun, getattr(self.helpers, fun)) def traverse(self, doorName): return self.doorsManager.traverse(self, doorName) def createKnowsFunctions(self, player): # for each knows we have a function knowsKnows (ex: knowsAlcatrazEscape()) which # take no parameter for knows in Knows.__dict__: if isKnows(knows): if player in Knows.knowsDict and knows in Knows.knowsDict[player].__dict__: setattr(self, 'knows'+knows, lambda knows=knows: SMBool(Knows.knowsDict[player].__dict__[knows].bool, Knows.knowsDict[player].__dict__[knows].difficulty, knows=[knows])) else: # if knows not in preset, use default values setattr(self, 'knows'+knows, lambda knows=knows: SMBool(Knows.__dict__[knows].bool, Knows.__dict__[knows].difficulty, knows=[knows])) def isCountItem(self, item): return item in self.countItems def itemCount(self, item): # return integer #self.state.item_count(item, self.player) return self._counts[item] def haveItem(self, item): #return self.state.has(item, self.player) return self._items[item] wand = staticmethod(SMBool.wand) wandmax = staticmethod(SMBool.wandmax) wor = staticmethod(SMBool.wor) wnot = staticmethod(SMBool.wnot) def itemCountOk(self, item, count, difficulty=0): if self.itemCount(item) >= count: if item in ['ETank', 'Reserve']: item = str(count)+'-'+item return SMBool(True, difficulty, items = [item]) else: return smboolFalse def energyReserveCountOk(self, count, difficulty=0): if self.energyReserveCount() >= count: nEtank = self.itemCount('ETank') if nEtank > count: nEtank = int(count) items = str(nEtank)+'-ETank' nReserve = self.itemCount('Reserve') if nEtank < count: nReserve = int(count) - nEtank items += ' - '+str(nReserve)+'-Reserve' return SMBool(True, difficulty, items = [items]) else: return smboolFalse class SMBoolManagerPlando(SMBoolManager): def __init__(self): super(SMBoolManagerPlando, self).__init__() def addItem(self, item): # a new item is available already = self.haveItem(item) isCount = self.isCountItem(item) if isCount or not already: self._items[item] = SMBool(True, items=[item]) else: # handle duplicate major items (plandos) self._items['dup_'+item] = True if isCount: count = self._counts[item] + 1 self._counts[item] = count self.computeNewCacheKey(item, count) else: self.computeNewCacheKey(item, 1) Cache.update(self.cacheKey) def removeItem(self, item): # randomizer removed an item (or the item was added to test a post available) if self.isCountItem(item): count = self._counts[item] - 1 self._counts[item] = count if count == 0: self._items[item] = smboolFalse self.computeNewCacheKey(item, count) else: dup = 'dup_'+item if self._items.get(dup, None) is None: self._items[item] = smboolFalse self.computeNewCacheKey(item, 0) else: del self._items[dup] self.computeNewCacheKey(item, 1) Cache.update(self.cacheKey)