271 lines
		
	
	
		
			8.8 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			271 lines
		
	
	
		
			8.8 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| 
 | |
| import sys, random
 | |
| from collections import defaultdict
 | |
| from rando.Items import ItemManager
 | |
| from utils.utils import getRangeDict, chooseFromRange
 | |
| from rando.ItemLocContainer import ItemLocation
 | |
| 
 | |
| # Holder for settings and a few utility functions related to them
 | |
| # (especially for plando/rando).
 | |
| # Holds settings not related to graph layout.
 | |
| class RandoSettings(object):
 | |
|     def __init__(self, maxDiff, progSpeed, progDiff, qty, restrictions,
 | |
|                  superFun, runtimeLimit_s, plandoSettings, minDiff):
 | |
|         self.progSpeed = progSpeed.lower()
 | |
|         self.progDiff = progDiff.lower()
 | |
|         self.maxDiff = maxDiff
 | |
|         self.qty = qty
 | |
|         self.restrictions = restrictions
 | |
|         self.superFun = superFun
 | |
|         self.runtimeLimit_s = runtimeLimit_s
 | |
|         if self.runtimeLimit_s <= 0:
 | |
|             self.runtimeLimit_s = sys.maxsize
 | |
|         self.plandoSettings = plandoSettings
 | |
|         self.minDiff = minDiff
 | |
| 
 | |
|     def getSuperFun(self):
 | |
|         return self.superFun[:]
 | |
| 
 | |
|     def updateSuperFun(self, superFun):
 | |
|         self.superFun = superFun[:]
 | |
| 
 | |
|     def isPlandoRando(self):
 | |
|         return self.plandoSettings is not None
 | |
| 
 | |
|     def getItemManager(self, smbm, nLocs):
 | |
|         if not self.isPlandoRando():
 | |
|             return ItemManager(self.restrictions['MajorMinor'], self.qty, smbm, nLocs, self.maxDiff)
 | |
|         else:
 | |
|             return ItemManager('Plando', self.qty, smbm, nLocs, self.maxDiff)
 | |
| 
 | |
|     def getExcludeItems(self, locations):
 | |
|         if not self.isPlandoRando():
 | |
|             return None
 | |
|         exclude = {'alreadyPlacedItems': defaultdict(int), 'forbiddenItems': []}
 | |
|         # locsItems is a dict {'loc name': 'item type'}
 | |
|         for locName,itemType in self.plandoSettings["locsItems"].items():
 | |
|             if not any(loc.Name == locName for loc in locations):
 | |
|                 continue
 | |
|             exclude['alreadyPlacedItems'][itemType] += 1
 | |
|             exclude['alreadyPlacedItems']['total'] += 1
 | |
| 
 | |
|         exclude['forbiddenItems'] = self.plandoSettings['forbiddenItems']
 | |
| 
 | |
|         return exclude
 | |
| 
 | |
|     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)
 | |
| 
 | |
| # Holds settings and utiliy functions related to graph layout
 | |
| class GraphSettings(object):
 | |
|     def __init__(self, startAP, areaRando, lightAreaRando, bossRando, escapeRando, minimizerN, dotFile, doorsColorsRando, allowGreyDoors, plandoRandoTransitions):
 | |
|         self.startAP = startAP
 | |
|         self.areaRando = areaRando
 | |
|         self.lightAreaRando = lightAreaRando
 | |
|         self.bossRando = bossRando
 | |
|         self.escapeRando = escapeRando
 | |
|         self.minimizerN = minimizerN
 | |
|         self.dotFile = dotFile
 | |
|         self.doorsColorsRando = doorsColorsRando
 | |
|         self.allowGreyDoors = allowGreyDoors
 | |
|         self.plandoRandoTransitions = plandoRandoTransitions
 | |
| 
 | |
|     def isMinimizer(self):
 | |
|         return self.minimizerN is not None
 | |
| 
 | |
| # algo settings depending on prog speed (slowest to fastest+variable,
 | |
| # other "speeds" are actually different algorithms)
 | |
| class ProgSpeedParameters(object):
 | |
|     def __init__(self, restrictions, nLocs):
 | |
|         self.restrictions = restrictions
 | |
|         self.nLocs = nLocs
 | |
| 
 | |
|     def getVariableSpeed(self):
 | |
|         ranges = getRangeDict({
 | |
|             'slowest':7,
 | |
|             'slow':20,
 | |
|             'medium':35,
 | |
|             'fast':27,
 | |
|             'fastest':11
 | |
|         })
 | |
|         return chooseFromRange(ranges)
 | |
| 
 | |
|     def getMinorHelpProb(self, progSpeed):
 | |
|         if self.restrictions.split != 'Major':
 | |
|             return 0
 | |
|         if progSpeed == 'slowest':
 | |
|             return 0.16
 | |
|         elif progSpeed == 'slow':
 | |
|             return 0.33
 | |
|         elif progSpeed == 'medium':
 | |
|             return 0.5
 | |
|         return 1
 | |
| 
 | |
|     def getLateDoorsProb(self, progSpeed):
 | |
|         if progSpeed == 'slowest':
 | |
|             return 1
 | |
|         elif progSpeed == 'slow':
 | |
|             return 0.8
 | |
|         elif progSpeed == 'medium':
 | |
|             return 0.66
 | |
|         elif progSpeed == 'fast':
 | |
|             return 0.5
 | |
|         elif progSpeed == 'fastest':
 | |
|             return 0.33
 | |
|         return 0
 | |
| 
 | |
|     def getItemLimit(self, progSpeed):
 | |
|         itemLimit = self.nLocs
 | |
|         if progSpeed == 'slow':
 | |
|             itemLimit = int(self.nLocs*0.209) # 21 for 105
 | |
|         elif progSpeed == 'medium':
 | |
|             itemLimit = int(self.nLocs*0.095) # 9 for 105
 | |
|         elif progSpeed == 'fast':
 | |
|             itemLimit = int(self.nLocs*0.057) # 5 for 105
 | |
|         elif progSpeed == 'fastest':
 | |
|             itemLimit = int(self.nLocs*0.019) # 1 for 105
 | |
|         minLimit = itemLimit - int(itemLimit/5)
 | |
|         maxLimit = itemLimit + int(itemLimit/5)
 | |
|         if minLimit == maxLimit:
 | |
|             itemLimit = minLimit
 | |
|         else:
 | |
|             itemLimit = random.randint(minLimit, maxLimit)
 | |
|         return itemLimit
 | |
| 
 | |
|     def getLocLimit(self, progSpeed):
 | |
|         locLimit = -1
 | |
|         if progSpeed == 'slow':
 | |
|             locLimit = 1
 | |
|         elif progSpeed == 'medium':
 | |
|             locLimit = 2
 | |
|         elif progSpeed == 'fast':
 | |
|             locLimit = 3
 | |
|         elif progSpeed == 'fastest':
 | |
|             locLimit = 4
 | |
|         return locLimit
 | |
| 
 | |
|     def getProgressionItemTypes(self, progSpeed):
 | |
|         progTypes = ItemManager.getProgTypes()
 | |
|         if self.restrictions.isLateDoors():
 | |
|             progTypes += ['Wave','Spazer','Plasma']
 | |
|         progTypes.append('Charge')
 | |
|         if progSpeed == 'slowest':
 | |
|             return progTypes
 | |
|         else:
 | |
|             progTypes.remove('HiJump')
 | |
|             progTypes.remove('Charge')
 | |
|         if progSpeed == 'slow':
 | |
|             return progTypes
 | |
|         else:
 | |
|             progTypes.remove('Bomb')
 | |
|             progTypes.remove('Grapple')
 | |
|         if progSpeed == 'medium':
 | |
|             return progTypes
 | |
|         else:
 | |
|             if not self.restrictions.isLateDoors():
 | |
|                 progTypes.remove('Ice')
 | |
|             progTypes.remove('SpaceJump')
 | |
|         if progSpeed == 'fast':
 | |
|             return progTypes
 | |
|         else:
 | |
|             progTypes.remove('SpeedBooster')
 | |
|         if progSpeed == 'fastest':
 | |
|             return progTypes # only morph, varia, gravity
 | |
|         raise RuntimeError("Unknown prog speed " + progSpeed)
 | |
| 
 | |
|     def getPossibleSoftlockProb(self, progSpeed):
 | |
|         if progSpeed == 'slowest':
 | |
|             return 1
 | |
|         if progSpeed == 'slow':
 | |
|             return 0.66
 | |
|         if progSpeed == 'medium':
 | |
|             return 0.33
 | |
|         if progSpeed == 'fast':
 | |
|             return 0.1
 | |
|         if progSpeed == 'fastest':
 | |
|             return 0
 | |
|         raise RuntimeError("Unknown prog speed " + progSpeed)
 | |
| 
 | |
|     def getChooseLocDict(self, progDiff):
 | |
|         if progDiff == 'normal':
 | |
|             return {
 | |
|                 'Random' : 1,
 | |
|                 'MinDiff' : 0,
 | |
|                 'MaxDiff' : 0
 | |
|             }
 | |
|         elif progDiff == 'easier':
 | |
|             return {
 | |
|                 'Random' : 2,
 | |
|                 'MinDiff' : 1,
 | |
|                 'MaxDiff' : 0
 | |
|             }
 | |
|         elif progDiff == 'harder':
 | |
|             return {
 | |
|                 'Random' : 2,
 | |
|                 'MinDiff' : 0,
 | |
|                 'MaxDiff' : 1
 | |
|             }
 | |
| 
 | |
|     def getChooseItemDict(self, progSpeed):
 | |
|         if progSpeed == 'slowest':
 | |
|             return {
 | |
|                 'MinProgression' : 1,
 | |
|                 'Random' : 2,
 | |
|                 'MaxProgression' : 0
 | |
|             }
 | |
|         elif progSpeed == 'slow':
 | |
|             return {
 | |
|                 'MinProgression' : 25,
 | |
|                 'Random' : 75,
 | |
|                 'MaxProgression' : 0
 | |
|             }
 | |
|         elif progSpeed == 'medium':
 | |
|             return {
 | |
|                 'MinProgression' : 0,
 | |
|                 'Random' : 1,
 | |
|                 'MaxProgression' : 0
 | |
|             }
 | |
|         elif progSpeed == 'fast':
 | |
|             return {
 | |
|                 'MinProgression' : 0,
 | |
|                 'Random' : 85,
 | |
|                 'MaxProgression' : 15
 | |
|             }
 | |
|         elif progSpeed == 'fastest':
 | |
|             return {
 | |
|                 'MinProgression' : 0,
 | |
|                 'Random' : 2,
 | |
|                 'MaxProgression' : 1
 | |
|             }
 | |
| 
 | |
|     def getSpreadFactor(self, progSpeed):
 | |
|         if progSpeed == 'slowest':
 | |
|             return 0.9
 | |
|         elif progSpeed == 'slow':
 | |
|             return 0.7
 | |
|         elif progSpeed == 'medium':
 | |
|             return 0.4
 | |
|         elif progSpeed == 'fast':
 | |
|             return 0.1
 | |
|         return 0
 | |
| 
 | |
|     def getChozoSecondPhaseRestrictionProb(self, progSpeed):
 | |
|         if progSpeed == 'slowest':
 | |
|             return 0
 | |
|         if progSpeed == 'slow':
 | |
|             return 0.16
 | |
|         if progSpeed == 'medium':
 | |
|             return 0.5
 | |
|         if progSpeed == 'fast':
 | |
|             return 0.9
 | |
|         return 1
 | 
