def getVariableSpeed(self): ranges = getRangeDict({ 'slowest':7, 'slow':20, 'medium':35, 'fast':27, 'fastest':11 }) return chooseFromRange(ranges)
def getItemPool(self): exceptionMessage = "Too many items already placed by the plando or not enough available locations:" self.itemManager.newItemPool(addBosses=False) # add the already placed items by the plando for item in self.exclude: if item == 'total': continue itemClass = 'Major' if item in [ 'Missile', 'Super', 'PowerBomb', 'Kraid', 'Phantoon', 'Draygon', 'Ridley', 'MotherBrain' ]: itemClass = 'Minor' for i in range(self.exclude[item]): self.itemManager.addItem(item, itemClass) remain = self.maxItems - self.exclude['total'] self.log.debug("Plando: remain start: {}".format(remain)) if remain > 0: # add missing bosses for boss in [ 'Kraid', 'Phantoon', 'Draygon', 'Ridley', 'MotherBrain' ]: if boss not in self.exclude or self.exclude[boss] == 0: self.itemManager.addItem(boss, 'Minor') self.exclude[boss] = 1 remain -= 1 self.log.debug("Plando: remain after bosses: {}".format(remain)) if remain < 0: raise Exception("{} can't add the remaining bosses".format( exceptionMessage)) # add missing majors majors = [] for itemType in [ 'Bomb', 'Charge', 'Ice', 'HiJump', 'SpeedBooster', 'Wave', 'Spazer', 'SpringBall', 'Varia', 'Plasma', 'Grapple', 'Morph', 'Gravity', 'XRayScope', 'SpaceJump', 'ScrewAttack' ]: if itemType not in self.exclude or self.exclude[itemType] == 0: self.itemManager.addItem(itemType, 'Major') self.exclude[itemType] = 1 majors.append(itemType) remain -= 1 self.log.debug("Plando: remain after majors: {}".format(remain)) if remain < 0: raise Exception("{} can't add the remaining majors: {}".format( exceptionMessage, ', '.join(majors))) # add minimum minors to finish the game for (itemType, minimum) in [('Missile', 3), ('Super', 2), ('PowerBomb', 1)]: if itemType not in self.exclude: self.exclude[itemType] = 0 while self.exclude[itemType] < minimum: self.itemManager.addItem(itemType, 'Minor') self.exclude[itemType] += 1 remain -= 1 self.log.debug( "Plando: remain after minimum minors: {}".format(remain)) if remain < 0: raise Exception( "{} can't add the minimum minors to finish the game". format(exceptionMessage)) # add energy energyQty = self.qty['energy'] limits = { "sparse": [('ETank', 4), ('Reserve', 1)], "medium": [('ETank', 8), ('Reserve', 2)], "vanilla": [('ETank', 14), ('Reserve', 4)] } for (itemType, minimum) in limits[energyQty]: if itemType not in self.exclude: self.exclude[itemType] = 0 while self.exclude[itemType] < minimum: self.itemManager.addItem(itemType, 'Major') self.exclude[itemType] += 1 remain -= 1 self.log.debug("Plando: remain after energy: {}".format(remain)) if remain < 0: raise Exception("{} can't add energy".format(exceptionMessage)) # add ammo nbMinorsAlready = self.exclude['Missile'] + self.exclude[ 'Super'] + self.exclude['PowerBomb'] minorLocations = max(0, 0.66 * self.qty['minors'] - nbMinorsAlready) maxItems = len( self.itemManager.getItemPool()) + int(minorLocations) rangeDict = getRangeDict(self.qty['ammo']) while len( self.itemManager.getItemPool()) < maxItems and remain > 0: item = chooseFromRange(rangeDict) self.itemManager.addMinor(item) remain -= 1 self.log.debug("Plando: remain after ammo: {}".format(remain)) # add nothing while remain > 0: self.itemManager.addMinor('Nothing') remain -= 1 self.log.debug("Plando: remain after nothing: {}".format(remain)) return self.itemManager.getItemPool()
def addAmmo(self): self.calcMaxAmmo() # we have to remove the minors already added maxItems = min( len(self.itemManager.getItemPool()) + int(self.minorLocations), self.maxItems) self.log.debug("maxItems: {}".format(maxItems)) ammoQty = self.qty['ammo'] if not self.qty['strictMinors']: rangeDict = getRangeDict(ammoQty) self.log.debug("rangeDict: {}".format(rangeDict)) while len(self.itemManager.getItemPool()) < maxItems: item = chooseFromRange(rangeDict) self.itemManager.addMinor(item) else: minorsTypes = ['Missile', 'Super', 'PowerBomb'] totalProps = sum(ammoQty[m] for m in minorsTypes) minorsByProp = sorted(minorsTypes, key=lambda m: ammoQty[m]) maxMinors = 0.66 * (maxItems - 5) totalMinorLocations = int(maxMinors * self.qty['minors'] / 100) self.log.debug("totalProps: {}".format(totalProps)) self.log.debug( "totalMinorLocations: {}".format(totalMinorLocations)) def ammoCount(ammo): return float( len([ item for item in self.itemManager.getItemPool() if item.Type == ammo ])) def targetRatio(ammo): return round(float(ammoQty[ammo]) / totalProps, 3) def cmpRatio(ammo, ratio): thisAmmo = ammoCount(ammo) thisRatio = round(thisAmmo / totalMinorLocations, 3) nextRatio = round((thisAmmo + 1) / totalMinorLocations, 3) self.log.debug( "{} current, next/target ratio: {}, {}/{}".format( ammo, thisRatio, nextRatio, ratio)) return abs(nextRatio - ratio) < abs(thisRatio - ratio) def fillAmmoType(ammo, checkRatio=True): ratio = targetRatio(ammo) self.log.debug("{}: target ratio: {}".format(ammo, ratio)) while len(self.itemManager.getItemPool()) < maxItems and ( not checkRatio or cmpRatio(ammo, ratio)): self.log.debug("Add {}".format(ammo)) self.itemManager.addMinor(ammo) for m in minorsByProp: fillAmmoType(m) # now that the ratios have been matched as exactly as possible, we distribute the error def getError(m, countOffset=0): return abs((ammoCount(m) + countOffset) / totalMinorLocations - targetRatio(m)) while len(self.itemManager.getItemPool()) < maxItems: minNextError = 1000 chosenAmmo = None for m in minorsByProp: nextError = getError(m, 1) if nextError < minNextError: minNextError = nextError chosenAmmo = m self.itemManager.addMinor(chosenAmmo) # fill up the rest with blank items for i in range(self.maxItems - maxItems): self.itemManager.addMinor('Nothing')
def determineParameters(self, progSpeed=None, progDiff=None): self.chooseLocRanges = getRangeDict(self.getChooseLocs(progDiff)) self.chooseItemRanges = getRangeDict(self.getChooseItems(progSpeed)) self.spreadProb = self.progSpeedParams.getSpreadFactor(progSpeed) self.lateDoorsProb = self.progSpeedParams.getLateDoorsProb(progSpeed)