Example #1
0
 def fillRestrictedLocations(self):
     def getPred(itemType, loc):
         return lambda item: (itemType is None or item.Type == itemType) and self.restrictions.canPlaceAtLocation(item, loc, self.container)
     locs = self.restrictedLocs
     self.log.debug("fillRestrictedLocations. locs="+getLocListStr(locs))
     for loc in locs:
         itemLocation = ItemLocation(None, loc)
         if loc.BossItemType is not None:
             itemLocation.Item = self.container.getNextItemInPoolMatching(getPred(loc.BossItemType, loc))
         elif self.container.hasItemInPool(getPred('Nothing', loc)):
             itemLocation.Item = self.container.getNextItemInPoolMatching(getPred('Nothing', loc))
         elif self.container.hasItemInPool(getPred('NoEnergy', loc)):
             itemLocation.Item = self.container.getNextItemInPoolMatching(getPred('NoEnergy', loc))
         elif self.container.countItems(getPred('Missile', loc)) > 3:
             itemLocation.Item = self.container.getNextItemInPoolMatching(getPred('Missile', loc))
         elif self.container.countItems(getPred('Super', loc)) > 2:
             itemLocation.Item = self.container.getNextItemInPoolMatching(getPred('Super', loc))
         elif self.container.countItems(getPred('PowerBomb', loc)) > 1:
             itemLocation.Item = self.container.getNextItemInPoolMatching(getPred('PowerBomb', loc))
         elif self.container.countItems(getPred('Reserve', loc)) > 1:
             itemLocation.Item = self.container.getNextItemInPoolMatching(getPred('Reserve', loc))
         elif self.container.countItems(getPred('ETank', loc)) > 3:
             itemLocation.Item = self.container.getNextItemInPoolMatching(getPred('ETank', loc))
         else:
             raise RuntimeError("Cannot fill restricted locations")
         self.log.debug("Fill: {}/{} at {}".format(itemLocation.Item.Type, itemLocation.Item.Class, itemLocation.Location.Name))
         self.container.collect(itemLocation, False)
Example #2
0
    def collectPair(self, pairItemLocDict):
        # choose a pair of items which create progression
        keys = list(pairItemLocDict.keys())
        key = random.choice(keys)

        # collect them
        availableLocs = pairItemLocDict[key]
        self.collect(ItemLocation(key[0], availableLocs[0][0]))
        self.collect(ItemLocation(key[1], availableLocs[1][0]))
Example #3
0
 def fill(locs, getPred):
     self.log.debug("fillRestrictedLocations. locs=" +
                    getLocListStr(locs))
     for loc in locs:
         loc.restricted = True
         itemLocation = ItemLocation(None, loc)
         if self.container.hasItemInPool(getPred('Nothing')):
             itemLocation.Item = self.container.getNextItemInPoolMatching(
                 getPred('Nothing'))
         elif self.container.hasItemInPool(getPred('NoEnergy')):
             itemLocation.Item = self.container.getNextItemInPoolMatching(
                 getPred('NoEnergy'))
         elif self.container.countItems(getPred('Missile')) > 3:
             itemLocation.Item = self.container.getNextItemInPoolMatching(
                 getPred('Missile'))
         elif self.container.countItems(getPred('Super')) > 2:
             itemLocation.Item = self.container.getNextItemInPoolMatching(
                 getPred('Super'))
         elif self.container.countItems(getPred('PowerBomb')) > 1:
             itemLocation.Item = self.container.getNextItemInPoolMatching(
                 getPred('PowerBomb'))
         elif self.container.countItems(getPred('Reserve')) > 1:
             itemLocation.Item = self.container.getNextItemInPoolMatching(
                 getPred('Reserve'))
         elif self.container.countItems(getPred('ETank')) > 3:
             itemLocation.Item = self.container.getNextItemInPoolMatching(
                 getPred('ETank'))
         else:
             raise RuntimeError("Cannot fill restricted locations")
         self.log.debug("Fill: {} at {}".format(
             itemLocation.Item.Type, itemLocation.Location.Name))
         self.container.collect(itemLocation, False)
Example #4
0
 def processEarlyMorph(self, ap, container, comebackCheck, itemLocDict,
                       curLocs):
     morph = container.getNextItemInPool('Morph')
     if morph is not None:
         self.log.debug("processEarlyMorph. morph not placed yet")
         morphLocItem = next(
             (item for item in itemLocDict if item.Type == morph.Type),
             None)
         if morphLocItem is not None:
             morphLocs = itemLocDict[morphLocItem]
             itemLocDict.clear()
             itemLocDict[morphLocItem] = morphLocs
         elif len(curLocs) >= 2:
             self.log.debug(
                 "processEarlyMorph. early morph placement check")
             # we have to place morph early, it's still not placed, and not detected as placeable
             # let's see if we can place it anyway in the context of a combo
             morphLocs = self.getPlacementLocs(ap, container, comebackCheck,
                                               morph, curLocs)
             if len(morphLocs) > 0:
                 # copy our context to do some destructive checks
                 containerCpy = copy.copy(container)
                 # choose a morph item location in that context
                 morphItemLoc = ItemLocation(
                     morph,
                     random.choice(containerCpy.extractLocs(morphLocs)))
                 # acquire morph in new context and see if we can still open new locs
                 newAP = self.collect(ap, containerCpy, morphItemLoc)
                 (ild, poss) = self.getPossiblePlacements(
                     newAP, containerCpy, comebackCheck)
                 if poss:
                     # it's possible, only offer morph as possibility
                     itemLocDict.clear()
                     itemLocDict[morph] = morphLocs
 def chooseItemLoc(self, itemLocDict, isProg, progressionItemLocs, ap,
                   container):
     # if late morph, redo the late morph check if morph is the
     # only possibility since we can rollback
     canRollback = len(container.currentItems) > 0
     if self.restrictions.isLateMorph() and canRollback and len(
             itemLocDict) == 1:
         item, locList = list(itemLocDict.items())[0]
         if item.Type == 'Morph':
             morphLocs = self.restrictions.lateMorphCheck(
                 container, locList)
             if morphLocs is not None:
                 itemLocDict[item] = morphLocs
             else:
                 return None
     # if a boss is available, choose it right away
     for item, locs in itemLocDict.items():
         if item.Category == 'Boss':
             assert len(locs) == 1 and locs[0].Name == item.Name
             return ItemLocation(item, locs[0])
     # late doors check for random door colors
     if self.restrictions.isLateDoors(
     ) and random.random() < self.lateDoorsProb:
         self.processLateDoors(itemLocDict, ap, container)
     self.progressionItemLocs = progressionItemLocs
     self.ap = ap
     self.container = container
     return super(ItemThenLocChoiceProgSpeed,
                  self).chooseItemLoc(itemLocDict, isProg)
    def step(self):
        # here a step is not an item collection but a whole fill attempt
        date = time.process_time()
        while not self.container.isPoolEmpty() and date <= self.endDate:
            item = random.choice(self.container.itemPool)
            locs = self.getLocations(item)
            if not locs:
                self.log.debug(
                    "FillerRandom: constraint collision during step {} for item {}"
                    .format(self.nSteps, item.Type))
                self.resetHelpingContainer()
                date = time.process_time()
                continue
            loc = random.choice(locs)
            itemLoc = ItemLocation(item, loc)
            self.container.collect(itemLoc, pickup=False)
        date = time.process_time()
        if date > self.endDate:
            return False
        # pool is exhausted, use mini solver to see if it is beatable
        if self.isBeatable():
            sys.stdout.write('o')
            sys.stdout.flush()
        else:
            if self.diffSteps > 0 and self.settings.maxDiff < infinity:
                if self.nSteps < self.diffSteps:
                    couldBeBeatable = self.isBeatable(maxDiff=infinity)
                    if couldBeBeatable:
                        difficulty = max([
                            il.Location.difficulty.difficulty
                            for il in self.container.itemLocations
                        ])
                        if self.beatableBackup is None or difficulty < self.beatableBackup[
                                1]:
                            self.beatableBackup = (
                                self.container.itemLocations, difficulty)
                elif self.beatableBackup is not None:
                    self.container.itemLocations = self.beatableBackup[0]
                    difficulty = self.beatableBackup[1]
                    self.errorMsg += "Could not find a solution compatible with max difficulty. Estimated seed difficulty: " + diffValue2txt(
                        difficulty)
                    sys.stdout.write('O')
                    sys.stdout.flush()
                    return True
                else:
                    return False
            # reset container to force a retry
            self.resetHelpingContainer()
            if (self.nSteps + 1) % 100 == 0:
                sys.stdout.write('x')
                sys.stdout.flush()

            # help speedrun filler
            self.getHelp()

        return True
Example #7
0
 def chooseItemLoc(self, itemLocDict, isProg):
     itemList = self.getItemList(itemLocDict)
     item = self.chooseItem(itemList, isProg)
     if item is None:
         return None
     locList = self.getLocList(itemLocDict, item)
     loc = self.chooseLocation(locList, item, isProg)
     if loc is None:
         return None
     return ItemLocation(item, loc)
 def collectAlreadyPlacedItemLocations(self, container):
     if not self.isPlandoRando():
         return
     for locName,itemType in self.plandoSettings["locsItems"].items():
         if not any(loc.Name == locName for loc in container.unusedLocations):
             continue
         item = container.getNextItemInPool(itemType)
         assert item is not None, "Invalid plando item pool"
         location = container.getLocs(lambda loc: loc.Name == locName)[0]
         itemLoc = ItemLocation(item, location)
         container.collect(itemLoc, pickup=False)
 def step(self):
     item = random.choice(self.container.itemPool)
     locs = [
         loc for loc in self.container.unusedLocations
         if self.restrictions.canPlaceAtLocation(item, loc, self.container)
     ]
     loc = random.choice(locs)
     itemLoc = ItemLocation(item, loc)
     self.container.collect(itemLoc, pickup=False)
     sys.stdout.write('.')
     sys.stdout.flush()
     return True
Example #10
0
 def findStartupProgItemPair(self, ap, container):
     self.log.debug("findStartupProgItemPair")
     (itemLocDict, isProg) = self.getPossiblePlacements(ap, container, ComebackCheckType.NoCheck)
     assert not isProg
     items = list(itemLocDict.keys())
     random.shuffle(items)
     for item in items:
         cont = copy.copy(container)
         loc = random.choice(itemLocDict[item])
         itemLoc1 = ItemLocation(item, loc)
         self.log.debug("itemLoc1 attempt: "+getItemLocStr(itemLoc1))
         newAP = self.collect(ap, cont, itemLoc1)
         if self.cache is not None:
             self.cache.reset()
         (ild, isProg) = self.getPossiblePlacements(newAP, cont, ComebackCheckType.NoCheck)
         if isProg:
             item2 = random.choice(list(ild.keys()))
             itemLoc2 = ItemLocation(item2, random.choice(ild[item2]))
             self.log.debug("itemLoc2: "+getItemLocStr(itemLoc2))
             return (itemLoc1, itemLoc2)
     return None
Example #11
0
 def postProcessItemLocs(self, itemLocs, hide):
     # hide some items like in dessy's
     if hide == True:
         for itemLoc in itemLocs:
             item = itemLoc.Item
             loc = itemLoc.Location
             if (item.Category != "Nothing" and loc.CanHidden == True
                     and loc.Visibility == 'Visible'):
                 if bool(random.getrandbits(1)) == True:
                     loc.Visibility = 'Hidden'
     # put nothing in unfilled locations
     filledLocNames = [il.Location.Name for il in itemLocs]
     unfilledLocs = [
         loc for loc in Logic.locations if loc.Name not in filledLocNames
     ]
     nothing = ItemManager.getItem('Nothing')
     for loc in unfilledLocs:
         loc.restricted = True
         itemLocs.append(ItemLocation(nothing, loc, False))
Example #12
0
    def savePlando(self, lock, escapeTimer):
        # store filled locations addresses in the ROM for next creating session
        from rando.Items import ItemManager
        locsItems = {}
        itemLocs = []
        for loc in self.visitedLocations:
            locsItems[loc.Name] = loc.itemName
        for loc in self.locations:
            if loc.Name in locsItems:
                itemLocs.append(
                    ItemLocation(ItemManager.getItem(loc.itemName), loc))
            else:
                # put nothing items in unused locations
                itemLocs.append(
                    ItemLocation(ItemManager.getItem("Nothing"), loc))

        # patch the ROM
        if lock == True:
            import random
            magic = random.randint(1, 0xffff)
        else:
            magic = None
        romPatcher = RomPatcher(magic=magic, plando=True)
        patches = [
            'credits_varia.ips', 'tracking.ips', "Escape_Animals_Disable"
        ]
        if DoorsManager.isRandom():
            patches += RomPatcher.IPSPatches['DoorsColors']
            patches.append("Enable_Backup_Saves")
        if magic != None:
            patches.insert(0, 'race_mode.ips')
            patches.append('race_mode_credits.ips')
        romPatcher.addIPSPatches(patches)

        plms = []
        if self.areaRando == True or self.bossRando == True or self.escapeRando == True:
            doors = GraphUtils.getDoorConnections(
                AccessGraph(Logic.accessPoints, self.fillGraph()),
                self.areaRando, self.bossRando, self.escapeRando, False)
            romPatcher.writeDoorConnections(doors)
            if magic == None:
                doorsPtrs = GraphUtils.getAps2DoorsPtrs()
                romPatcher.writePlandoTransitions(
                    self.curGraphTransitions, doorsPtrs,
                    len(vanillaBossesTransitions) + len(vanillaTransitions))
            if self.escapeRando == True and escapeTimer != None:
                # convert from '03:00' to number of seconds
                escapeTimer = int(escapeTimer[0:2]) * 60 + int(
                    escapeTimer[3:5])
                romPatcher.applyEscapeAttributes(
                    {
                        'Timer': escapeTimer,
                        'Animals': None
                    }, plms)

        # write plm table & random doors
        romPatcher.writePlmTable(plms, self.areaRando, self.bossRando,
                                 self.startAP)

        romPatcher.writeItemsLocs(itemLocs)
        romPatcher.writeItemsNumber()
        romPatcher.writeSpoiler(itemLocs)
        # plando is considered Full
        romPatcher.writeSplitLocs(itemLocs, "Full")
        romPatcher.writeMajorsSplit("Full")

        class FakeRandoSettings:
            def __init__(self):
                self.qty = {'energy': 'plando'}
                self.progSpeed = 'plando'
                self.progDiff = 'plando'
                self.restrictions = {'Suits': False, 'Morph': 'plando'}
                self.superFun = {}

        randoSettings = FakeRandoSettings()
        romPatcher.writeRandoSettings(randoSettings, itemLocs)
        if magic != None:
            romPatcher.writeMagic()
        else:
            romPatcher.writePlandoAddresses(self.visitedLocations)

        romPatcher.commitIPS()
        romPatcher.end()

        data = romPatcher.romFile.data
        preset = os.path.splitext(os.path.basename(self.presetFileName))[0]
        seedCode = 'FX'
        if self.bossRando == True:
            seedCode = 'B' + seedCode
        if DoorsManager.isRandom():
            seedCode = 'D' + seedCode
        if self.areaRando == True:
            seedCode = 'A' + seedCode
        from time import gmtime, strftime
        fileName = 'VARIA_Plandomizer_{}{}_{}.sfc'.format(
            seedCode, strftime("%Y%m%d%H%M%S", gmtime()), preset)
        data["fileName"] = fileName
        # error msg in json to be displayed by the web site
        data["errorMsg"] = ""
        with open(self.outputFileName, 'w') as jsonFile:
            json.dump(data, jsonFile)
Example #13
0
    def getStartupProgItemsPairs(self, ap, container):
        self.log.debug("getStartupProgItemsPairs: kickstart")
        (itemLocDict,
         isProg) = self.getPossiblePlacements(ap, container,
                                              ComebackCheckType.NoCheck)

        # save container
        saveEmptyContainer = ContainerSoftBackup(container)

        # key is (item1, item2)
        pairItemLocDict = {}

        # keep only unique items in itemLocDict
        uniqItemLocDict = {}
        for item, locs in itemLocDict.items():
            if item.Type in ['NoEnergy', 'Nothing']:
                continue
            if item.Type not in [it.Type for it in uniqItemLocDict.keys()]:
                uniqItemLocDict[item] = locs
        if not uniqItemLocDict:
            return None

        if self.cache:
            self.cache.reset()
        curLocsBefore = self.currentLocations(ap, container)
        if not curLocsBefore:
            return None

        self.log.debug("search for progression with a second item")
        for item1, locs1 in uniqItemLocDict.items():
            # collect first item in first available location matching restrictions
            if self.cache:
                self.cache.reset()
            firstItemPlaced = False
            for loc in curLocsBefore:
                if self.restrictions.canPlaceAtLocation(item1, loc, container):
                    self.log.debug("getStartupProgItemsPairs. firstItemPlaced")
                    container.collect(ItemLocation(item1, loc))
                    firstItemPlaced = True
                    break
            if not firstItemPlaced:
                saveEmptyContainer.restore(container)
                continue

            saveAfterFirst = ContainerSoftBackup(container)

            curLocsAfterFirst = self.currentLocations(ap, container)
            if not curLocsAfterFirst:
                saveEmptyContainer.restore(container)
                continue

            for item2, locs2 in uniqItemLocDict.items():
                if item1.Type == item2.Type:
                    continue

                if (item1, item2) in pairItemLocDict.keys() or (
                        item2, item1) in pairItemLocDict.keys():
                    continue

                # collect second item in first available location
                if self.cache:
                    self.cache.reset()
                secondItemPlaced = False
                for loc in curLocsAfterFirst:
                    if self.restrictions.canPlaceAtLocation(
                            item2, loc, container):
                        container.collect(ItemLocation(item2, loc))
                        secondItemPlaced = True
                        break
                if not secondItemPlaced:
                    saveAfterFirst.restore(container)
                    continue

                curLocsAfterSecond = self.currentLocations(ap, container)
                if not curLocsAfterSecond:
                    saveAfterFirst.restore(container)
                    continue

                pairItemLocDict[(item1, item2)] = [
                    curLocsBefore, curLocsAfterFirst, curLocsAfterSecond
                ]
                saveAfterFirst.restore(container)

            saveEmptyContainer.restore(container)

        # check if a pair was found
        if len(pairItemLocDict) == 0:
            self.log.debug("no pair was found")
            return None
        else:
            if self.log.getEffectiveLevel() == logging.DEBUG:
                self.log.debug("pairItemLocDict:")
                for key, locs in pairItemLocDict.items():
                    self.log.debug(
                        "{}->{}: {}".format(key[0].Type, key[1].Type,
                                            [l['Name'] for l in locs[2]]))

            return pairItemLocDict