def step(self):
     if len(self.conditions) > 1:
         self.determineParameters()
         curLocs = []
         while self.firstPhaseIndex < len(self.firstPhaseItemLocs):
             self.cache.reset()
             newCurLocs = [loc for loc in self.currentLocations() if loc not in curLocs]
             curLocs += newCurLocs
             cond = self.nextMetCondition()
             if cond is not None:
                 self.log.debug('step. cond item='+cond[0])
                 self.conditions.remove(cond)
                 break
             itemLoc = self.firstPhaseItemLocs[self.firstPhaseIndex]
             self.collect(itemLoc, container=self.firstPhaseContainer)
             self.firstPhaseIndex += 1
         self.log.debug('step. curLocs='+getLocListStr(curLocs))
         restrictedItemTypes = [cond[0] for cond in self.conditions]
         self.log.debug('step. restrictedItemTypes='+str(restrictedItemTypes))
         basePool = self.container.itemPool[:]
         itemPool = []
         self.log.debug('step. basePool: {}'.format(getItemListStr(basePool)))
         while len(itemPool) < len(curLocs):
             item = random.choice(basePool)
             if item.Type not in restrictedItemTypes or\
                random.random() < self.restrictedItemProba or\
                self.restrictedItemProba == 0 and not any(item for item in basePool if item.Type not in restrictedItemTypes):
                 itemPool.append(item)
                 basePool.remove(item)
         self.log.debug('step. itemPool='+getItemListStr(itemPool))
         cont = ItemLocContainer(self.container.sm, itemPool, curLocs)
         self.container.transferCollected(cont)
         filler = FillerRandomItems(self.ap, self.graph, self.restrictions, cont, self.endDate)
         (stuck, itemLocs, prog) = filler.generateItems()
         if stuck:
             if len(filler.errorMsg) > 0:
                 self.errorMsg += '\n'+filler.errorMsg
             return False
         for itemLoc in itemLocs:
             if itemLoc.Location in self.container.unusedLocations:
                 self.log.debug("step. POST COLLECT "+itemLoc.Item.Type+" at "+itemLoc.Location.Name)
                 self.container.collect(itemLoc)
     else:
         # merge collected of 1st phase and 2nd phase so far for seed to be solvable by random fill
         self.container.itemLocations += self.firstPhaseItemLocs
         self.log.debug("step. LAST FILL. cont: "+self.container.dump())
         filler = FillerRandomNoCopy(self.startAP, self.graph, self.restrictions, self.container, self.endDate, diffSteps=100)
         (stuck, itemLocs, prog) = filler.generateItems()
         if len(filler.errorMsg) > 0:
             self.errorMsg += '\n'+filler.errorMsg
         if stuck:
             return False
     return True
 def prepareFirstPhase(self):
     self.changedKnows = {}
     # forces IceZebSkip if necessary to finish with 10-10-5
     if Knows.IceZebSkip.bool == False or Knows.IceZebSkip.difficulty > self.maxDiff:
         self.changedKnows['IceZebSkip'] = Knows.IceZebSkip
         Knows.IceZebSkip = SMBool(True, 0, [])
     # hack knows to remove those > maxDiff
     for attr,k in Knows.__dict__.items():
         if isKnows(attr) and k.bool == True and k.difficulty > self.maxDiff:
             self.log.debug("prepareFirstPhase. disabling knows "+attr)
             self.changedKnows[attr] = k
             setattr(Knows, attr, SMBool(False, 0))
     # set max diff to god (for hard rooms/hellruns/bosses)
     self.settings.maxDiff = god
     # prepare 1st phase container
     itemCond = isChozoItem
     locCond = lambda loc: loc.isChozo() or loc.isBoss()
     # this will create a new smbm with new knows functions
     cont = self.baseContainer.slice(itemCond, locCond)
     secondPhaseItems = [item for item in self.baseContainer.itemPool if item not in cont.itemPool]
     contLocs = self.baseContainer.extractLocs(cont.unusedLocations)
     secondPhaseLocs = [loc for loc in self.baseContainer.unusedLocations if loc not in contLocs]
     self.log.debug("prepareFirstPhase. secondPhaseItems="+getItemListStr(secondPhaseItems))
     self.log.debug("prepareFirstPhase. secondPhaseLocs="+getLocListStr(secondPhaseLocs))
     self.secondPhaseContainer = ItemLocContainer(cont.sm, secondPhaseItems, secondPhaseLocs)
     return self.fillerFactory.createFirstPhaseFiller(cont)
Example #3
0
 def possibleLocations(self, item, ap, emptyContainer, bossesKilled=True):
     assert len(emptyContainer.currentItems) == 0, "Invalid call to possibleLocations. emptyContainer had collected items"
     emptyContainer.sm.resetItems()
     self.log.debug('possibleLocations. item='+item.Type)
     if bossesKilled:
         itemLambda = lambda it: it.Type != item.Type
     else:
         itemLambda = lambda it: it.Type != item.Type and it.Category != 'Boss'
     allBut = emptyContainer.getItems(itemLambda)
     self.log.debug('possibleLocations. allBut='+getItemListStr(allBut))
     emptyContainer.sm.addItems([it.Type for it in allBut])
     ret = [loc for loc in self.currentLocations(ap, emptyContainer, post=True) if self.restrictions.canPlaceAtLocation(item, loc, emptyContainer)]
     self.log.debug('possibleLocations='+getLocListStr(ret))
     emptyContainer.sm.resetItems()
     return ret
Example #4
0
    def checkPool(self, forbidden=None):
        self.log.debug("checkPool. forbidden=" + str(forbidden) +
                       ", self.forbiddenItems=" + str(self.forbiddenItems))
        if not self.graphSettings.isMinimizer(
        ) and not self.settings.isPlandoRando() and len(
                self.allLocations) > len(self.locations):
            # invalid graph with looped areas
            self.log.debug(
                "checkPool: not all areas are connected, but minimizer param is off / not a plando rando"
            )
            return False
        ret = True
        if forbidden is not None:
            pool = self.getItemPool(forbidden)
        else:
            pool = self.getItemPool()
        # get restricted locs
        totalAvailLocs = []
        comeBack = {}
        try:
            container = ItemLocContainer(self.sm, pool, self.locations)
        except AssertionError as e:
            # invalid graph altogether
            self.log.debug(
                "checkPool: AssertionError when creating ItemLocContainer: {}".
                format(e))
            return False
        # restrict item pool in chozo: game should be finishable with chozo items only
        contPool = []
        if self.restrictions.isChozo():
            container.restrictItemPool(isChozoItem)
            missile = container.getNextItemInPool('Missile')
            if missile is not None:
                # add missile (if zeb skip not known)
                contPool.append(missile)
        contPool += [item for item in pool if item in container.itemPool]
        # give us everything and beat every boss to see what we can access
        self.disableBossChecks()
        self.sm.resetItems()
        self.sm.addItems([item.Type
                          for item in contPool])  # will add bosses as well
        self.log.debug('pool={}'.format(getItemListStr(container.itemPool)))
        locs = self.services.currentLocations(self.startAP,
                                              container,
                                              post=True)
        self.areaGraph.useCache(True)
        for loc in locs:
            ap = loc.accessPoint
            if ap not in comeBack:
                # we chose Golden Four because it is always there.
                # Start APs might not have comeback transitions
                # possible start AP issues are handled in checkStart
                comeBack[ap] = self.areaGraph.canAccess(
                    self.sm, ap, 'Golden Four', self.settings.maxDiff)
            if comeBack[ap]:
                totalAvailLocs.append(loc)
        self.areaGraph.useCache(False)
        self.lastRestricted = [
            loc for loc in self.locations if loc not in totalAvailLocs
        ]
        self.log.debug("restricted=" +
                       str([loc.Name for loc in self.lastRestricted]))

        # check if all inter-area APs can reach each other
        interAPs = [
            ap for ap in self.areaGraph.getAccessibleAccessPoints(self.startAP)
            if not ap.isInternal() and not ap.isLoop()
        ]
        for startAp in interAPs:
            availAccessPoints = self.areaGraph.getAvailableAccessPoints(
                startAp, self.sm, self.settings.maxDiff)
            for ap in interAPs:
                if not ap in availAccessPoints:
                    self.log.debug(
                        "checkPool: ap {} non accessible from {}".format(
                            ap.Name, startAp.Name))
                    ret = False
        if not ret:
            self.log.debug("checkPool. inter-area APs check failed")
        # cleanup
        self.sm.resetItems()
        self.restoreBossChecks()
        # check if we can reach/beat all bosses
        if ret:
            for loc in self.lastRestricted:
                if loc.Name in self.bossesLocs:
                    ret = False
                    self.log.debug("unavail Boss: " + loc.Name)
            if ret:
                # revive bosses
                self.sm.addItems([
                    item.Type for item in contPool if item.Category != 'Boss'
                ])
                maxDiff = self.settings.maxDiff
                # see if phantoon doesn't block himself, and if we can reach draygon if she's alive
                ret = self.areaGraph.canAccess(self.sm, self.startAP, 'PhantoonRoomIn', maxDiff)\
                      and self.areaGraph.canAccess(self.sm, self.startAP, 'DraygonRoomIn', maxDiff)
                if ret:
                    # see if we can beat bosses with this equipment (infinity as max diff for a "onlyBossesLeft" type check
                    beatableBosses = sorted([
                        loc.Name for loc in self.services.currentLocations(
                            self.startAP, container, diff=infinity)
                        if loc.isBoss()
                    ])
                    self.log.debug("checkPool. beatableBosses=" +
                                   str(beatableBosses))
                    ret = beatableBosses == Bosses.Golden4()
                    if ret:
                        # check that we can then kill mother brain
                        self.sm.addItems(Bosses.Golden4())
                        beatableMotherBrain = [
                            loc.Name for loc in self.services.currentLocations(
                                self.startAP, container, diff=infinity)
                            if loc.Name == 'Mother Brain'
                        ]
                        ret = len(beatableMotherBrain) > 0
                        self.log.debug(
                            "checkPool. beatable Mother Brain={}".format(ret))
                else:
                    self.log.debug('checkPool. locked by Phantoon or Draygon')
                self.log.debug('checkPool. boss access sanity check: ' +
                               str(ret))

        if self.restrictions.isChozo() or self.restrictions.isScavenger():
            # in chozo or scavenger, we cannot put other items than NoEnergy in the restricted locations,
            # we would be forced to put majors in there, which can make seed generation fail:
            # don't put more restricted major locations than removed major items
            # FIXME something to do there for chozo/ultra sparse, it gives us up to 3 more spots for nothing items
            restrictedLocs = self.restrictedLocs + [
                loc for loc in self.lastRestricted
                if loc not in self.restrictedLocs
            ]
            nRestrictedMajor = sum(1 for loc in restrictedLocs
                                   if self.restrictions.isLocMajor(loc))
            nNothingMajor = sum(1 for item in pool
                                if self.restrictions.isItemMajor(item)
                                and item.Category == 'Nothing')
            ret &= nRestrictedMajor <= nNothingMajor
            self.log.debug('checkPool. nRestrictedMajor=' +
                           str(nRestrictedMajor) + ', nNothingMajor=' +
                           str(nNothingMajor))
        self.log.debug('checkPool. result: ' + str(ret))
        return ret