示例#1
0
class TestGraphUtils(TestCase):
  def setUp(self):
    controller = Controller()
    files = ['assets/data/map_data.json', 'assets/data/cmi_hub.json']
    self.g = Graph()
    controller.build_graph_from_files(self.g, files)
    self.utils = GraphUtils()

  def testMerge(self):
    print(self.utils.smallest_city(self.g))
    assert self.utils.smallest_city(self.g)[0] == u'CMI'
 def escapeGraph(self, emptyContainer, graph, maxDiff):
     if not self.escapeRando:
         return
     possibleTargets, dst, path = self.getPossibleEscapeTargets(emptyContainer, graph, maxDiff)
     # update graph with escape transition
     graph.addTransition(escapeSource, dst)
     # get timer value
     self.escapeTimer(graph, path)
     self.log.debug("escapeGraph: ({}, {}) timer: {}".format(escapeSource, dst, graph.EscapeAttributes['Timer']))
     # animals
     GraphUtils.escapeAnimalsTransitions(graph, possibleTargets, dst)
示例#3
0
 def updateLocationsClass(self, split):
     if split != 'Full' and split != 'Scavenger':
         startAP = getAccessPoint(self.graphSettings.startAP)
         possibleMajLocs, preserveMajLocs, nMaj, nChozo = Logic.LocationsHelper.getStartMajors(
             startAP.Name)
         if split == 'Major':
             n = nMaj
         elif split == 'Chozo':
             n = nChozo
         GraphUtils.updateLocClassesStart(startAP.GraphArea, split,
                                          possibleMajLocs, preserveMajLocs,
                                          n)
示例#4
0
    def setUp(self):
        f = open('assets/data/map_data.json', 'r')
        decoded = json.loads(f.read())
        self.g = graph.Graph()
        self.g.build_nodes(decoded['metros'])
        self.g.build_edges(decoded['routes'])
        self.utils = GraphUtils()

        f = open('assets/data/test1_map_data.json', 'r')
        decoded = json.loads(f.read())
        self.gSmall = graph.Graph()
        self.gSmall.build_nodes(decoded['metros'])
        self.gSmall.build_edges(decoded['routes'])
示例#5
0
 def testSave(self):
     self.utils.save_to_disk(self.g)
     f2 = open('assets/data/map_data_written.json', 'r')
     decoded = json.loads(f2.read())
     self.g2 = graph.Graph()
     self.g2.build_nodes(decoded['metros'])
     self.g2.build_edges(decoded['routes'])
     self.utils = GraphUtils()
     assert (self.utils.longest_flight(self.g2) == ('SYD', 'LAX', 12051))
     assert (self.utils.shortest_flight(self.g2) == ('NYC', 'WAS', 334))
     assert (self.utils.average_distance(self.g2) == 2300)
     assert self.utils.biggest_city(self.g2) == ('TYO', 34000000)
     assert self.utils.smallest_city(self.g2) == ('ESS', 589900)
示例#6
0
    def loadTransitions(self, tourian):
        # return the transitions
        rooms = GraphUtils.getRooms()
        bossTransitions = {}
        areaTransitions = {}
        for accessPoint in Logic.accessPoints:
            if accessPoint.isInternal() == True:
                continue
            key = self.getTransition(accessPoint.ExitInfo['DoorPtr'])
            if key not in rooms:
                # can happen with race mode seeds
                continue
            destAP = rooms[key]
            if accessPoint.Boss == True or destAP.Boss == True:
                bossTransitions[accessPoint.Name] = destAP.Name
            else:
                areaTransitions[accessPoint.Name] = destAP.Name

        def removeBiTrans(transitions):
            # remove bidirectionnal transitions
            # can't del keys in a dict while iterating it
            transitionsCopy = copy.copy(transitions)
            for src in transitionsCopy:
                if src in transitions:
                    dest = transitions[src]
                    if dest in transitions:
                        if transitions[dest] == src:
                            del transitions[dest]

            return [(t, transitions[t]) for t in transitions]

        # get escape transition
        if tourian == 'Disabled':
            escapeSrcAP = getAccessPoint('Climb Bottom Left')
        else:
            escapeSrcAP = getAccessPoint('Tourian Escape Room 4 Top Right')
        key = self.getTransition(escapeSrcAP.ExitInfo['DoorPtr'])
        # may not be set in plandomizer
        if key in rooms:
            escapeDstAP = rooms[key]
            escapeTransition = [(escapeSrcAP.Name, escapeDstAP.Name)]
        else:
            escapeTransition = []

        areaTransitions = removeBiTrans(areaTransitions)
        bossTransitions = removeBiTrans(bossTransitions)

        return (areaTransitions, bossTransitions, escapeTransition, GraphUtils.hasMixedTransitions(areaTransitions, bossTransitions))
 def createGraph(self):
     transitions = self.graphSettings.plandoRandoTransitions
     if transitions is None:
         transitions = []
         if self.minimizerN is not None:
             transitions = GraphUtils.createMinimizerTransitions(self.graphSettings.startAP, self.minimizerN)
         else:
             if not self.bossRando:
                 transitions += vanillaBossesTransitions
             else:
                 transitions += GraphUtils.createBossesTransitions()
             if not self.areaRando:
                 transitions += vanillaTransitions
             else:
                 transitions += GraphUtils.createAreaTransitions(self.graphSettings.lightAreaRando)
     return AccessGraph(Logic.accessPoints, transitions, self.graphSettings.dotFile)
示例#8
0
 def setDefaultPatches(startLocation):
     # called by the isolver in seedless mode.
     # activate only layout patch (the most common one), red tower blue doors and the startLocation's patches.
     from graph.graph_utils import GraphUtils
     RomPatches.ActivePatches[0] = [
         RomPatches.RedTowerBlueDoors
     ] + RomPatches.TotalLayout + GraphUtils.getGraphPatches(startLocation)
示例#9
0
 def createItemLocContainer(self):
     self.getForbidden()
     self.log.debug("LAST CHECKPOOL")
     if not self.checkPool():
         self.log.debug("createItemLocContainer: checkPool fail")
         return None
     self.checkDoorBeams()
     self.container = ItemLocContainer(self.sm, self.getItemPool(),
                                       self.locations)
     if self.restrictions.isLateMorph():
         self.restrictions.lateMorphInit(self.startAP, self.container,
                                         self.services)
         isStdStart = GraphUtils.isStandardStart(self.startAP)
         # ensure we have an area layout that can put morph outside start area
         # TODO::allow for custom start which doesn't require morph early
         if self.graphSettings.areaRando and isStdStart and not self.restrictions.suitsRestrictions and self.restrictions.lateMorphForbiddenArea is None:
             self.container = None
             self.log.debug("createItemLocContainer: checkLateMorph fail")
             return None
     # checkStart needs the container
     if not self.checkStart():
         self.container = None
         self.log.debug("createItemLocContainer: checkStart fail")
         return None
     # add placement restriction helpers for random fill
     if self.settings.progSpeed == 'speedrun':
         restrictionDict = self.getSpeedrunRestrictionsDict()
         self.restrictions.addPlacementRestrictions(restrictionDict)
     self.settings.collectAlreadyPlacedItemLocations(self.container)
     self.fillRestrictedLocations()
     self.settings.updateSuperFun(self.superFun)
     return self.container
示例#10
0
 def getSpeedrunRestrictionsDict(self):
     itemTypes = {
         item.Type
         for item in self.container.itemPool
         if item.Category not in Restrictions.NoCheckCat
     }
     allAreas = {loc.GraphArea for loc in self.locations}
     items = [
         self.container.getNextItemInPool(itemType)
         for itemType in itemTypes
     ]
     restrictionDict = {}
     for area in allAreas:
         restrictionDict[area] = {}
         for itemType in itemTypes:
             restrictionDict[area][itemType] = set()
     for item in items:
         itemType = item.Type
         poss = self.services.possibleLocations(item, self.startAP,
                                                self.container)
         for loc in poss:
             restrictionDict[loc.GraphArea][itemType].add(loc.Name)
     if self.restrictions.isEarlyMorph() and GraphUtils.isStandardStart(
             self.startAP):
         morphLocs = ['Morphing Ball']
         if self.restrictions.split in ['Full', 'Major']:
             dboost = self.sm.knowsCeilingDBoost()
             if dboost.bool == True and dboost.difficulty <= self.settings.maxDiff:
                 morphLocs.append('Energy Tank, Brinstar Ceiling')
         for area, locDict in restrictionDict.items():
             if area == 'Crateria':
                 locDict['Morph'] = set(morphLocs)
             else:
                 locDict['Morph'] = set()
     return restrictionDict
示例#11
0
 def applyStartAP(self, apName, plms, doors):
     ap = getAccessPoint(apName)
     if not GraphUtils.isStandardStart(apName):
         # not Ceres or Landing Site, so Zebes will be awake
         plms.append('Morph_Zebes_Awake')
     (w0, w1) = getWord(ap.Start['spawn'])
     if 'doors' in ap.Start:
         doors += ap.Start['doors']
     doors.append(0x0)
     addr = 0x10F200
     patch = [w0, w1] + doors
     assert (addr + len(patch)) < 0x10F210, "Stopped before new_game overwrite"
     patchDict = {
         'StartAP': {
             addr: patch
         },
     }
     self.applyIPSPatch('StartAP', patchDict)
     # handle custom saves
     if 'save' in ap.Start:
         self.applyIPSPatch(ap.Start['save'])
         plms.append(ap.Start['save'])
     # handle optional rom patches
     if 'rom_patches' in ap.Start:
         for patch in ap.Start['rom_patches']:
             self.applyIPSPatch(patch)
示例#12
0
 def __init__(self,
              startAP,
              graph,
              restrictions,
              emptyContainer,
              endDate=infinity):
     super(FrontFiller, self).__init__(startAP, graph, restrictions,
                                       emptyContainer, endDate)
     self.choice = ItemThenLocChoice(restrictions)
     self.stdStart = GraphUtils.isStandardStart(self.startAP)
示例#13
0
    def run(self):
        # init session
        if self.session.plando is None:
            self.session.plando = {
                "state": {},
                "preset": "regular",
                "seed": None,
                "startLocation": "Landing Site",

                # rando params
                "rando": {},

                # set to False in plando.html
                "firstTime": True
            }

        # load presets list
        (stdPresets, tourPresets, comPresets) = loadPresetsList(self.cache)

        # access points
        vanillaAPs = []
        for (src, dest) in vanillaTransitions:
            vanillaAPs += [transition2isolver(src), transition2isolver(dest)]

        vanillaBossesAPs = []
        for (src, dest) in vanillaBossesTransitions:
            vanillaBossesAPs += [
                transition2isolver(src),
                transition2isolver(dest)
            ]

        escapeAPs = []
        for (src, dest) in vanillaEscapeTransitions:
            escapeAPs += [transition2isolver(src), transition2isolver(dest)]

        # generate list of addresses to read in the ROM
        addresses = getAddressesToRead(plando=True)

        startAPs = GraphUtils.getStartAccessPointNamesCategory()
        startAPs = [
            OPTGROUP(_label="Standard", *startAPs["regular"]),
            OPTGROUP(_label="Custom", *startAPs["custom"]),
            OPTGROUP(_label="Custom (Area rando only)", *startAPs["area"])
        ]

        return dict(stdPresets=stdPresets,
                    tourPresets=tourPresets,
                    comPresets=comPresets,
                    vanillaAPs=vanillaAPs,
                    vanillaBossesAPs=vanillaBossesAPs,
                    escapeAPs=escapeAPs,
                    curSession=self.session.plando,
                    addresses=addresses,
                    startAPs=startAPs,
                    version=displayedVersion)
示例#14
0
    def loadTransitions(self):
        # return the transitions
        rooms = GraphUtils.getRooms()
        bossTransitions = {}
        areaTransitions = {}
        for accessPoint in Logic.accessPoints:
            if accessPoint.isInternal() == True:
                continue
            key = self.getTransition(accessPoint.ExitInfo['DoorPtr'])

            destAP = rooms[key]
            if accessPoint.Boss == True or destAP.Boss == True:
                bossTransitions[accessPoint.Name] = destAP.Name
            else:
                areaTransitions[accessPoint.Name] = destAP.Name

        def removeBiTrans(transitions):
            # remove bidirectionnal transitions
            # can't del keys in a dict while iterating it
            transitionsCopy = copy.copy(transitions)
            for src in transitionsCopy:
                if src in transitions:
                    dest = transitions[src]
                    if dest in transitions:
                        if transitions[dest] == src:
                            del transitions[dest]

            return [(t, transitions[t]) for t in transitions]

        # get escape transition
        escapeSrcAP = getAccessPoint('Tourian Escape Room 4 Top Right')
        key = self.getTransition(escapeSrcAP.ExitInfo['DoorPtr'])
        escapeDstAP = rooms[key]
        escapeTransition = [(escapeSrcAP.Name, escapeDstAP.Name)]

        areaTransitions = removeBiTrans(areaTransitions)
        bossTransitions = removeBiTrans(bossTransitions)

        return (areaTransitions, bossTransitions, escapeTransition,
                GraphUtils.hasMixedTransitions(areaTransitions,
                                               bossTransitions))
示例#15
0
 def escapeGraph(self, container, graph, maxDiff, escapeTrigger):
     if not self.escapeRando:
         return True
     emptyContainer = copy.copy(container)
     emptyContainer.resetCollected(reassignItemLocs=True)
     dst = None
     if escapeTrigger is None:
         possibleTargets, dst, path = self.getPossibleEscapeTargets(emptyContainer, graph, maxDiff)
         # update graph with escape transition
         graph.addTransition(escapeSource, dst)
         paths = [path]
     else:
         possibleTargets, paths = self.escapeTrigger(emptyContainer, graph, maxDiff, escapeTrigger)
         if paths is None:
             return False
     # get timer value
     self.escapeTimer(graph, paths, self.areaRando or escapeTrigger is not None)
     self.log.debug("escapeGraph: ({}, {}) timer: {}".format(escapeSource, dst, graph.EscapeAttributes['Timer']))
     # animals
     GraphUtils.escapeAnimalsTransitions(graph, possibleTargets, dst)
     return True
示例#16
0
  def setUp(self):
    f = open('assets/data/map_data.json', 'r')
    decoded = json.loads(f.read())
    self.g = graph.Graph()
    self.g.build_nodes(decoded['metros'])
    self.g.build_edges(decoded['routes'])
    self.utils = GraphUtils()

    f = open('assets/data/test1_map_data.json', 'r')
    decoded = json.loads(f.read())
    self.gSmall = graph.Graph()
    self.gSmall.build_nodes(decoded['metros'])
    self.gSmall.build_edges(decoded['routes'])
示例#17
0
 def testSave(self):
   self.utils.save_to_disk(self.g)
   f2 = open('assets/data/map_data_written.json', 'r')
   decoded = json.loads(f2.read())
   self.g2 = graph.Graph()
   self.g2.build_nodes(decoded['metros'])
   self.g2.build_edges(decoded['routes'])
   self.utils = GraphUtils()
   assert (self.utils.longest_flight(self.g2) == ('SYD', 'LAX', 12051))
   assert (self.utils.shortest_flight(self.g2) == ('NYC', 'WAS', 334))
   assert (self.utils.average_distance(self.g2) == 2300)
   assert self.utils.biggest_city(self.g2) == ('TYO', 34000000)
   assert self.utils.smallest_city(self.g2) == ( 'ESS', 589900)
示例#18
0
def getDefaultMultiValues():
    from graph.graph_utils import GraphUtils
    defaultMultiValues = {
        'startLocation':
        GraphUtils.getStartAccessPointNames(),
        'majorsSplit': ['Full', 'FullWithHUD', 'Major', 'Chozo', 'Scavenger'],
        'progressionSpeed': [
            'slowest', 'slow', 'medium', 'fast', 'fastest', 'basic',
            'VARIAble', 'speedrun'
        ],
        'progressionDifficulty': ['easier', 'normal', 'harder'],
        'morphPlacement': ['early', 'late', 'normal'],
        'energyQty': ['ultra sparse', 'sparse', 'medium', 'vanilla'],
        'gravityBehaviour': ['Vanilla', 'Balanced', 'Progressive']
    }
    return defaultMultiValues
示例#19
0
 def createItemLocContainer(self, endDate, vcr=None):
     self.getForbidden()
     self.log.debug("LAST CHECKPOOL")
     if not self.checkPool():
         self.log.debug("createItemLocContainer: last checkPool fail")
         return None
     # reset restricted in locs from previous attempt
     for loc in self.locations:
         loc.restricted = False
     for loc in self.restrictedLocs:
         self.log.debug(
             "createItemLocContainer: loc is restricted: {}".format(
                 loc.Name))
         loc.restricted = True
     self.checkDoorBeams()
     self.container = ItemLocContainer(self.sm, self.getItemPool(),
                                       self.locations)
     if self.restrictions.isLateMorph():
         self.restrictions.lateMorphInit(self.startAP, self.container,
                                         self.services)
         isStdStart = GraphUtils.isStandardStart(self.startAP)
         # ensure we have an area layout that can put morph outside start area
         # TODO::allow for custom start which doesn't require morph early
         if self.graphSettings.areaRando and isStdStart and not self.restrictions.suitsRestrictions and self.restrictions.lateMorphForbiddenArea is None:
             self.container = None
             self.log.debug("createItemLocContainer: checkLateMorph fail")
             return None
     # checkStart needs the container
     if not self.checkStart():
         self.container = None
         self.log.debug("createItemLocContainer: checkStart fail")
         return None
     self.settings.collectAlreadyPlacedItemLocations(self.container)
     self.fillRestrictedLocations()
     if self.restrictions.split == 'Scavenger':
         # initScavenger will actually fill up the container using random fill,
         # the scavenger "filler" will focus on determining mandatory route
         self.container = self.initScavenger(endDate, vcr)
         if self.container is None:
             self.log.debug("createItemLocContainer: initScavenger fail")
             return None
     elif self.settings.progSpeed == 'speedrun':
         # add placement restriction helpers for random fill
         self.restrictions.setPlacementRestrictions(
             self.getRestrictionsDict())
     self.settings.updateSuperFun(self.superFun)
     return self.container
示例#20
0
 def setUp(self):
   controller = Controller()
   files = ['assets/data/map_data.json', 'assets/data/cmi_hub.json']
   self.g = Graph()
   controller.build_graph_from_files(self.g, files)
   self.utils = GraphUtils()
示例#21
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)
示例#22
0
 def loadPlandoTransitions(self):
     # add escape transition
     transitionsAddr = self.romLoader.getPlandoTransitions(
         len(vanillaBossesTransitions) + len(vanillaTransitions) + 1)
     return GraphUtils.getTransitions(transitionsAddr)
 def __init__(self, graphSettings, areaGraph, restrictions, container, endDate):
     super(FillerProgSpeed, self).__init__(graphSettings.startAP, areaGraph, restrictions, container, endDate)
     distanceProp = 'GraphArea' if graphSettings.areaRando else 'Area'
     self.stdStart = GraphUtils.isStandardStart(self.startAP)
     self.progSpeedParams = ProgSpeedParameters(self.restrictions, len(container.unusedLocations))
     self.choice = ItemThenLocChoiceProgSpeed(restrictions, self.progSpeedParams, distanceProp, self.services)
示例#24
0
    def run(self):
        # init session
        if self.session.tracker is None:
            self.session.tracker = {
                "state": {},
                "preset": "regular",
                "seed": None,
                "startLocation": "Landing Site",
                # set to False in tracker.html
                "firstTime": True
            }

        # load presets list
        (stdPresets, tourPresets, comPresets) = loadPresetsList(self.cache)

        # access points
        vanillaAPs = []
        for (src, dest) in vanillaTransitions:
            vanillaAPs += [transition2isolver(src), transition2isolver(dest)]

        vanillaBossesAPs = []
        for (src, dest) in vanillaBossesTransitions:
            vanillaBossesAPs += [
                transition2isolver(src),
                transition2isolver(dest)
            ]

        escapeAPs = []
        for (src, dest) in vanillaEscapeTransitions:
            escapeAPs += [transition2isolver(src), transition2isolver(dest)]

        # generate list of addresses to read in the ROM
        addresses = getAddressesToRead()

        startAPs = GraphUtils.getStartAccessPointNamesCategory()
        startAPs = [
            OPTGROUP(_label="Standard", *startAPs["regular"]),
            OPTGROUP(_label="Custom", *startAPs["custom"]),
            OPTGROUP(_label="Custom (Area rando only)", *startAPs["area"])
        ]

        # get ap -> grapharea for auto tracker
        apsGraphArea = {
            locName4isolver(ap.Name): ap.GraphArea
            for ap in accessPoints
        }

        return dict(stdPresets=stdPresets,
                    tourPresets=tourPresets,
                    comPresets=comPresets,
                    vanillaAPs=vanillaAPs,
                    vanillaBossesAPs=vanillaBossesAPs,
                    escapeAPs=escapeAPs,
                    curSession=self.session.tracker,
                    addresses=addresses,
                    startAPs=startAPs,
                    areaAccessPoints=InteractiveSolver.areaAccessPoints,
                    bossAccessPoints=InteractiveSolver.bossAccessPoints,
                    escapeAccessPoints=InteractiveSolver.escapeAccessPoints,
                    nothingScreens=InteractiveSolver.nothingScreens,
                    doorsScreen=InteractiveSolver.doorsScreen,
                    bossBitMasks=InteractiveSolver.bossBitMasks,
                    apsGraphArea=apsGraphArea)
示例#25
0
class TestGraphUtils(TestCase):
    def setUp(self):
        f = open('assets/data/map_data.json', 'r')
        decoded = json.loads(f.read())
        self.g = graph.Graph()
        self.g.build_nodes(decoded['metros'])
        self.g.build_edges(decoded['routes'])
        self.utils = GraphUtils()

        f = open('assets/data/test1_map_data.json', 'r')
        decoded = json.loads(f.read())
        self.gSmall = graph.Graph()
        self.gSmall.build_nodes(decoded['metros'])
        self.gSmall.build_edges(decoded['routes'])

    def testSave(self):
        self.utils.save_to_disk(self.g)
        f2 = open('assets/data/map_data_written.json', 'r')
        decoded = json.loads(f2.read())
        self.g2 = graph.Graph()
        self.g2.build_nodes(decoded['metros'])
        self.g2.build_edges(decoded['routes'])
        self.utils = GraphUtils()
        assert (self.utils.longest_flight(self.g2) == ('SYD', 'LAX', 12051))
        assert (self.utils.shortest_flight(self.g2) == ('NYC', 'WAS', 334))
        assert (self.utils.average_distance(self.g2) == 2300)
        assert self.utils.biggest_city(self.g2) == ('TYO', 34000000)
        assert self.utils.smallest_city(self.g2) == ('ESS', 589900)

    def testLongestFlight(self):
        assert (self.utils.longest_flight(self.g) == ('SYD', 'LAX', 12051))
        assert (self.utils.longest_flight(self.gSmall) == ('MEX', 'LIM',
                                                           24530))

    def testShortestFlight(self):
        assert (self.utils.shortest_flight(self.g) == ('NYC', 'WAS', 334))
        assert (self.utils.shortest_flight(self.gSmall) == ('SCL', 'LIM',
                                                            2453))

    def testMapUrl(self):
        assert (
            self.utils.get_map_string(self.g) ==
            'PAR-ALG,+PAR-MAD,+PAR-LON,+PAR-ESS,+PAR-MIL,+MIL-PAR,+MIL-ESS,+MIL-IST,+MIA-MEX,+MIA-BOG,+MIA-ATL,+MIA-WAS,+LIM-SCL,+LIM-MEX,+LIM-BOG,+ATL-CHI,+ATL-WAS,+ATL-MIA,+PEK-SHA,+PEK-ICN,+LON-MAD,+LON-NYC,+LON-ESS,+LON-PAR,+IST-CAI,+IST-ALG,+IST-MIL,+IST-LED,+IST-MOW,+IST-BGW,+LOS-SAO,+LOS-KRT,+LOS-FIH,+CAI-KRT,+CAI-ALG,+CAI-IST,+CAI-BGW,+CAI-RUH,+DEL-THR,+DEL-KHI,+DEL-CCU,+DEL-MAA,+DEL-BOM,+BOM-KHI,+BOM-DEL,+BOM-MAA,+BGW-CAI,+BGW-IST,+BGW-THR,+BGW-KHI,+BGW-RUH,+NYC-MAD,+NYC-LON,+NYC-WAS,+NYC-YYZ,+BOG-LIM,+BOG-MEX,+BOG-MIA,+BOG-SAO,+BOG-BUE,+SCL-LIM,+SAO-BOG,+SAO-BUE,+SAO-MAD,+SAO-LOS,+KHI-BGW,+KHI-THR,+KHI-RUH,+KHI-DEL,+KHI-BOM,+JKT-MAA,+JKT-BKK,+JKT-SGN,+JKT-SYD,+BKK-MAA,+BKK-CCU,+BKK-HKG,+BKK-SGN,+BKK-JKT,+CCU-DEL,+CCU-MAA,+CCU-HKG,+CCU-BKK,+MNL-HKG,+MNL-TPE,+MNL-SFO,+MNL-SYD,+MNL-SGN,+SGN-BKK,+SGN-HKG,+SGN-MNL,+SGN-JKT,+OSA-TYO,+OSA-TPE,+HKG-CCU,+HKG-BKK,+HKG-SHA,+HKG-TPE,+HKG-MNL,+HKG-SGN,+BUE-BOG,+BUE-SAO,+TPE-HKG,+TPE-SHA,+TPE-OSA,+TPE-MNL,+ESS-LON,+ESS-PAR,+ESS-MIL,+ESS-LED,+ICN-SHA,+ICN-PEK,+ICN-TYO,+JNB-FIH,+JNB-KRT,+CHI-MEX,+CHI-LAX,+CHI-SFO,+CHI-YYZ,+CHI-ATL,+THR-MOW,+THR-BGW,+THR-DEL,+THR-KHI,+THR-RUH,+KRT-LOS,+KRT-FIH,+KRT-JNB,+KRT-CAI,+SHA-HKG,+SHA-PEK,+SHA-ICN,+SHA-TYO,+SHA-TPE,+FIH-LOS,+FIH-KRT,+FIH-JNB,+WAS-ATL,+WAS-MIA,+WAS-YYZ,+WAS-NYC,+RUH-CAI,+RUH-BGW,+RUH-THR,+RUH-KHI,+TYO-SHA,+TYO-ICN,+TYO-SFO,+TYO-OSA,+LED-ESS,+LED-MOW,+LED-IST,+SYD-MNL,+SYD-JKT,+SYD-LAX,+ALG-CAI,+ALG-MAD,+ALG-PAR,+ALG-IST,+MOW-LED,+MOW-THR,+MOW-IST,+YYZ-CHI,+YYZ-WAS,+YYZ-NYC,+MAA-DEL,+MAA-BOM,+MAA-CCU,+MAA-BKK,+MAA-JKT,+SFO-TYO,+SFO-MNL,+SFO-LAX,+SFO-CHI,+LAX-MEX,+LAX-SYD,+LAX-SFO,+LAX-CHI,+MAD-SAO,+MAD-ALG,+MAD-NYC,+MAD-LON,+MAD-PAR,+MEX-LIM,+MEX-LAX,+MEX-CHI,+MEX-MIA,+MEX-BOG'
        )

    def testAverageDist(self):
        assert (self.utils.average_distance(self.g) == 2300)
        assert (self.utils.average_distance(self.gSmall) == (2453 +
                                                             (24530 * 2)) / 3)

    def testBiggestPop(self):
        assert self.utils.biggest_city(self.g) == ('TYO', 34000000)
        assert self.utils.biggest_city(self.gSmall) == ('MEX', 23400000)

    def testSmallestPop(self):
        assert self.utils.smallest_city(self.g) == ('ESS', 589900)
        assert self.utils.smallest_city(self.gSmall) == ('SCL', 6000000)

    def testAveragePop(self):
        assert self.utils.average_city(self.g) == 11796143
        assert self.utils.average_city(
            self.gSmall) == (6000000 + 23400000 + 9050000) / 3

    def testContinents(self):
        assert self.utils.get_continents_and_cities(self.g) == {
            u'Europe': [
                u'Paris', u'Milan', u'London', u'Istanbul', u'Essen',
                u'St. Petersburg', u'Moscow', u'Madrid'
            ],
            u'Australia': [u'Sydney'],
            u'Africa': [
                u'Lagos', u'Cairo', u'Johannesburg', u'Khartoum', u'Kinshasa',
                u'Algiers'
            ],
            u'Asia': [
                u'Beijing', u'Delhi', u'Mumbai', u'Bagdad', u'Karachi',
                u'Jakarta', u'Bangkok', u'Calcutta', u'Manila',
                u'Ho Chi Minh City', u'Osaka', u'Hong Kong', u'Taipei',
                u'Seoul', u'Tehrah', u'Shanghai', u'Riyadh', u'Tokyo',
                u'Chennai'
            ],
            u'North America': [
                u'Miami', u'Atlanta', u'New York', u'Chicago', u'Washington',
                u'Toronto', u'San Francisco', u'Los Angeles', u'Mexico City'
            ],
            u'South America':
            [u'Lima', u'Bogota', u'Santiago', u'Sao Paulo', u'Buenos Aires']
        }

    def testHubs(self):
        assert self.utils.get_hub_cities(self.g) == ['IST', 'HKG']

    def testShortestPath(self):
        print(self.utils.shortestPath(self.g, 'CHI', 'TYO'))
        assert self.utils.shortestPath(self.g, 'CHI',
                                       'TYO') == ['CHI', 'SFO', 'TYO']

    def testRouteDistance(self):
        assert sum(self.utils.route_distance(
            self.g, ['CHI', 'SFO', 'TYO'])) == (8296 + 2994)

    def testShortestPath(self):
        assert (self.utils.shortestPath(self.g, 'CHI',
                                        'TYO') == ['CHI', 'SFO', 'TYO'])
        assert (self.utils.shortestPath(self.gSmall, 'SCL',
                                        'MEX') == ['SCL', 'LIM', 'MEX'])
示例#26
0
    def run(self):
        self.initRandomizerSession()

        (stdPresets, tourPresets, comPresets) = loadPresetsList(self.cache)

        randoPresetsDesc = {
            "all_random": "all the parameters set to random",
            "Chozo_Speedrun": "speedrun progression speed with Chozo split",
            "default": "VARIA randomizer default settings",
            "doors_long": "be prepared to hunt for beams and ammo to open doors",
            "doors_short": "uses Chozo/speedrun settings for a quicker door color rando",
            "free": "easiest possible settings",
            "hardway2hell": "harder highway2hell",
            "haste": "inspired by DASH randomizer with Nerfed Charge / Progressive Suits",
            "highway2hell": "favors suitless seeds",
            "hud": "Full rando with remaining major upgrades in the area shown in the HUD",
            "hud_hard": "Low resources and VARIA HUD enabled to help you track of actual items count",
            "hud_start": "Non-vanilla start with Major or Chozo split",
            "minimizer":"Typical 'boss rush' settings with random start and nerfed charge",
            "minimizer_hardcore":"Have fun 'rushing' bosses with no equipment on a tiny map",
            "minimizer_maximizer":"No longer a boss rush",
            "quite_random": "randomizes a few significant settings to have various seeds",
            "scavenger_hard":"Pretty hostile Scavenger mode",
            "scavenger_random":"Randomize everything within Scavenger mode",
            "scavenger_speedrun":"Quickest Scavenger settings",
            "scavenger_vanilla_but_not":"Items are vanilla, but area and bosses are not",
            "stupid_hard": "hardest possible settings",
            "surprise": "quite_random with Area/Boss/Doors/Start settings randomized",
            "vanilla": "closest possible to vanilla Super Metroid",
            "way_of_chozo": "chozo split with boss randomization",
            "where_am_i": "Area mode with random start location and early morph",
            "where_is_morph": "Area mode with late Morph",
            "Multi_Category_Randomizer_Week_1": "Multi-Category Randomizer Tournament week 1",
            "Multi_Category_Randomizer_Week_2": "Multi-Category Randomizer Tournament week 2",
            "Multi_Category_Randomizer_Week_3": "Multi-Category Randomizer Tournament week 3",
            "Multi_Category_Randomizer_Week_4": "Multi-Category Randomizer Tournament week 4",
            "Multi_Category_Randomizer_Week_5": "Multi-Category Randomizer Tournament week 5",
            "Multi_Category_Randomizer_Week_6": "Multi-Category Randomizer Tournament week 6",
            "Multi_Category_Randomizer_Week_7": "Multi-Category Randomizer Tournament week 7",
            "Season_Races": "rando league races (Majors/Minors split)",
            "SGLive2022_Race_1": "SGLive 2022 Super Metroid randomizer tournament race 1",
            "SGLive2022_Race_2": "SGLive 2022 Super Metroid randomizer tournament race 2",
            "SGLive2022_Race_3": "SGLive 2022 Super Metroid randomizer tournament race 3",
            "SMRAT2021": "Super Metroid Randomizer Accessible Tournament 2021",
            "VARIA_Weekly": "Casual logic community races"
        }

        randoPresetsCategories = {
            "Standard": ["", "default", "Chozo_Speedrun", "free", "haste", "vanilla"],
            "Hud": ["hud", "hud_hard", "hud_start"],
            "Scavenger": ["scavenger_hard", "scavenger_random", "scavenger_speedrun", "scavenger_vanilla_but_not"],
            "Area": ["way_of_chozo", "where_am_i", "where_is_morph"],
            "Doors": ["doors_long", "doors_short"],
            "Minimizer": ["minimizer", "minimizer_hardcore", "minimizer_maximizer"],
            "Hard": ["hardway2hell", "highway2hell", "stupid_hard"],
            "Random": ["all_random", "quite_random", "surprise"],
            "Tournament": ["Season_Races", "SMRAT2021", "VARIA_Weekly", "SGLive2022_Race_1", "SGLive2022_Race_2", "SGLive2022_Race_3", "Multi_Category_Randomizer_Week_1", "Multi_Category_Randomizer_Week_2", "Multi_Category_Randomizer_Week_3", "Multi_Category_Randomizer_Week_4", "Multi_Category_Randomizer_Week_5", "Multi_Category_Randomizer_Week_6", "Multi_Category_Randomizer_Week_7"]
        }

        startAPs = GraphUtils.getStartAccessPointNamesCategory()
        startAPs = [OPTGROUP(_label="Standard", *startAPs["regular"]),
                    OPTGROUP(_label="Custom", *startAPs["custom"]),
                    OPTGROUP(_label="Custom (Area rando only)", *startAPs["area"])]

        # get multi
        currentMultiValues = self.getCurrentMultiValues()
        defaultMultiValues = getDefaultMultiValues()

        # objectives self exclusions
        objectivesExclusions = Objectives.getExclusions()
        objectivesTypes = Objectives.getObjectivesTypes()
        objectivesSort = Objectives.getObjectivesSort()
        objectivesCategories = Objectives.getObjectivesCategories()

        # check if we have a guid in the url
        url = self.request.env.request_uri.split('/')
        if len(url) > 0 and url[-1] != 'randomizer':
            # a seed unique key was passed as parameter
            key = url[-1]

            # decode url
            key = urllib.parse.unquote(key)

            # sanity check
            if IS_MATCH('^[0-9a-z-]*$')(key)[1] is None and IS_LENGTH(maxsize=36, minsize=36)(key)[1] is None:
                with DB() as db:
                    seedInfo = db.getSeedInfo(key)
                if seedInfo is not None and len(seedInfo) > 0:
                    defaultParams = getRandomizerDefaultParameters()
                    defaultParams.update(seedInfo)
                    seedInfo = defaultParams

                    # check that the seed ips is available
                    if seedInfo["upload_status"] in ['pending', 'uploaded', 'local']:
                        # load parameters in session
                        for key, value in seedInfo.items():
                            if key in ["complexity", "randoPreset", "raceMode"]:
                                continue
                            elif key in defaultMultiValues:
                                keyMulti = key + 'MultiSelect'
                                if keyMulti in seedInfo:
                                    if key == 'objective' and value == 'nothing':
                                        self.session.randomizer[key] = ""
                                    else:
                                        self.session.randomizer[key] = seedInfo[key]
                                    valueMulti = seedInfo[keyMulti]
                                    if type(valueMulti) == str:
                                        valueMulti = valueMulti.split(',')
                                    self.session.randomizer[keyMulti] = valueMulti
                                    currentMultiValues[key] = valueMulti
                            elif key in self.session.randomizer and 'MultiSelect' not in key:
                                self.session.randomizer[key] = value

        return dict(stdPresets=stdPresets, tourPresets=tourPresets, comPresets=comPresets,
                    randoPresetsDesc=randoPresetsDesc, randoPresetsCategories=randoPresetsCategories,
                    startAPs=startAPs, currentMultiValues=currentMultiValues, defaultMultiValues=defaultMultiValues,
                    maxsize=sys.maxsize, displayNames=displayNames, objectivesExclusions=objectivesExclusions,
                    objectivesTypes=objectivesTypes, objectivesSort=objectivesSort,
                    objectivesCategories=objectivesCategories)
示例#27
0
    def loadRom(self, rom, interactive=False, magic=None, startAP=None):
        # startAP param is only use for seedless
        if rom == None:
            # TODO::add a --logic parameter for seedless
            Logic.factory('vanilla')
            self.romFileName = 'seedless'
            self.majorsSplit = 'Full'
            self.masterMajorsSplit = 'Full'
            self.areaRando = True
            self.bossRando = True
            self.escapeRando = False
            self.escapeTimer = "03:00"
            self.startAP = startAP
            RomPatches.setDefaultPatches(startAP)
            self.startArea = getAccessPoint(startAP).Start['solveArea']
            # in seedless load all the vanilla transitions
            self.areaTransitions = vanillaTransitions[:]
            self.bossTransitions = vanillaBossesTransitions[:]
            self.escapeTransition = [vanillaEscapeTransitions[0]]
            # in seedless we allow mixing of area and boss transitions
            self.hasMixedTransitions = True
            self.curGraphTransitions = self.bossTransitions + self.areaTransitions + self.escapeTransition
            self.locations = Logic.locations
            for loc in self.locations:
                loc.itemName = 'Nothing'
            # set doors related to default patches
            DoorsManager.setDoorsColor()
            self.doorsRando = False
            self.hasNothing = False
        else:
            self.romFileName = rom
            self.romLoader = RomLoader.factory(rom, magic)
            Logic.factory(self.romLoader.readLogic())
            self.romLoader.readNothingId()
            self.locations = Logic.locations
            (self.majorsSplit, self.masterMajorsSplit) = self.romLoader.assignItems(self.locations)
            (self.startAP, self.startArea, startPatches) = self.romLoader.getStartAP()
            if not GraphUtils.isStandardStart(self.startAP) and self.majorsSplit != 'Full':
                # update major/chozo locs in non standard start
                self.romLoader.updateSplitLocs(self.majorsSplit, self.locations)
            (self.areaRando, self.bossRando, self.escapeRando) = self.romLoader.loadPatches()
            RomPatches.ActivePatches += startPatches
            self.escapeTimer = self.romLoader.getEscapeTimer()
            self.doorsRando = self.romLoader.loadDoorsColor()
            self.hasNothing = self.checkLocsForNothing()

            if interactive == False:
                print("ROM {} majors: {} area: {} boss: {} escape: {} patches: {} activePatches: {}".format(rom, self.majorsSplit, self.areaRando, self.bossRando, self.escapeRando, sorted(self.romLoader.getPatches()), sorted(RomPatches.ActivePatches)))
            else:
                print("majors: {} area: {} boss: {} escape: {} activepatches: {}".format(self.majorsSplit, self.areaRando, self.bossRando, self.escapeRando, sorted(RomPatches.ActivePatches)))

            (self.areaTransitions, self.bossTransitions, self.escapeTransition, self.hasMixedTransitions) = self.romLoader.getTransitions()
            if interactive == True and self.debug == False:
                # in interactive area mode we build the graph as we play along
                if self.areaRando == True and self.bossRando == True:
                    self.curGraphTransitions = []
                elif self.areaRando == True:
                    self.curGraphTransitions = self.bossTransitions[:]
                elif self.bossRando == True:
                    self.curGraphTransitions = self.areaTransitions[:]
                else:
                    self.curGraphTransitions = self.bossTransitions + self.areaTransitions
                if self.escapeRando == False:
                    self.curGraphTransitions += self.escapeTransition
            else:
                self.curGraphTransitions = self.bossTransitions + self.areaTransitions + self.escapeTransition

        self.smbm = SMBoolManager()
        self.areaGraph = AccessGraph(Logic.accessPoints, self.curGraphTransitions)

        # store at each step how many locations are available
        self.nbAvailLocs = []

        if self.log.getEffectiveLevel() == logging.DEBUG:
            self.log.debug("Display items at locations:")
            for loc in self.locations:
                self.log.debug('{:>50}: {:>16}'.format(loc.Name, loc.itemName))
示例#28
0
class TestGraphUtils(TestCase):
  def setUp(self):
    f = open('assets/data/map_data.json', 'r')
    decoded = json.loads(f.read())
    self.g = graph.Graph()
    self.g.build_nodes(decoded['metros'])
    self.g.build_edges(decoded['routes'])
    self.utils = GraphUtils()

    f = open('assets/data/test1_map_data.json', 'r')
    decoded = json.loads(f.read())
    self.gSmall = graph.Graph()
    self.gSmall.build_nodes(decoded['metros'])
    self.gSmall.build_edges(decoded['routes'])

  def testSave(self):
    self.utils.save_to_disk(self.g)
    f2 = open('assets/data/map_data_written.json', 'r')
    decoded = json.loads(f2.read())
    self.g2 = graph.Graph()
    self.g2.build_nodes(decoded['metros'])
    self.g2.build_edges(decoded['routes'])
    self.utils = GraphUtils()
    assert (self.utils.longest_flight(self.g2) == ('SYD', 'LAX', 12051))
    assert (self.utils.shortest_flight(self.g2) == ('NYC', 'WAS', 334))
    assert (self.utils.average_distance(self.g2) == 2300)
    assert self.utils.biggest_city(self.g2) == ('TYO', 34000000)
    assert self.utils.smallest_city(self.g2) == ( 'ESS', 589900)


  def testLongestFlight(self):
    assert (self.utils.longest_flight(self.g) == ('SYD', 'LAX', 12051))
    assert (self.utils.longest_flight(self.gSmall) == ('MEX', 'LIM', 24530))

  def testShortestFlight(self):
    assert (self.utils.shortest_flight(self.g) == ('NYC', 'WAS', 334))
    assert (self.utils.shortest_flight(self.gSmall) == ('SCL', 'LIM', 2453))

  def testMapUrl(self):
    assert (self.utils.get_map_string(
      self.g) == 'PAR-ALG,+PAR-MAD,+PAR-LON,+PAR-ESS,+PAR-MIL,+MIL-PAR,+MIL-ESS,+MIL-IST,+MIA-MEX,+MIA-BOG,+MIA-ATL,+MIA-WAS,+LIM-SCL,+LIM-MEX,+LIM-BOG,+ATL-CHI,+ATL-WAS,+ATL-MIA,+PEK-SHA,+PEK-ICN,+LON-MAD,+LON-NYC,+LON-ESS,+LON-PAR,+IST-CAI,+IST-ALG,+IST-MIL,+IST-LED,+IST-MOW,+IST-BGW,+LOS-SAO,+LOS-KRT,+LOS-FIH,+CAI-KRT,+CAI-ALG,+CAI-IST,+CAI-BGW,+CAI-RUH,+DEL-THR,+DEL-KHI,+DEL-CCU,+DEL-MAA,+DEL-BOM,+BOM-KHI,+BOM-DEL,+BOM-MAA,+BGW-CAI,+BGW-IST,+BGW-THR,+BGW-KHI,+BGW-RUH,+NYC-MAD,+NYC-LON,+NYC-WAS,+NYC-YYZ,+BOG-LIM,+BOG-MEX,+BOG-MIA,+BOG-SAO,+BOG-BUE,+SCL-LIM,+SAO-BOG,+SAO-BUE,+SAO-MAD,+SAO-LOS,+KHI-BGW,+KHI-THR,+KHI-RUH,+KHI-DEL,+KHI-BOM,+JKT-MAA,+JKT-BKK,+JKT-SGN,+JKT-SYD,+BKK-MAA,+BKK-CCU,+BKK-HKG,+BKK-SGN,+BKK-JKT,+CCU-DEL,+CCU-MAA,+CCU-HKG,+CCU-BKK,+MNL-HKG,+MNL-TPE,+MNL-SFO,+MNL-SYD,+MNL-SGN,+SGN-BKK,+SGN-HKG,+SGN-MNL,+SGN-JKT,+OSA-TYO,+OSA-TPE,+HKG-CCU,+HKG-BKK,+HKG-SHA,+HKG-TPE,+HKG-MNL,+HKG-SGN,+BUE-BOG,+BUE-SAO,+TPE-HKG,+TPE-SHA,+TPE-OSA,+TPE-MNL,+ESS-LON,+ESS-PAR,+ESS-MIL,+ESS-LED,+ICN-SHA,+ICN-PEK,+ICN-TYO,+JNB-FIH,+JNB-KRT,+CHI-MEX,+CHI-LAX,+CHI-SFO,+CHI-YYZ,+CHI-ATL,+THR-MOW,+THR-BGW,+THR-DEL,+THR-KHI,+THR-RUH,+KRT-LOS,+KRT-FIH,+KRT-JNB,+KRT-CAI,+SHA-HKG,+SHA-PEK,+SHA-ICN,+SHA-TYO,+SHA-TPE,+FIH-LOS,+FIH-KRT,+FIH-JNB,+WAS-ATL,+WAS-MIA,+WAS-YYZ,+WAS-NYC,+RUH-CAI,+RUH-BGW,+RUH-THR,+RUH-KHI,+TYO-SHA,+TYO-ICN,+TYO-SFO,+TYO-OSA,+LED-ESS,+LED-MOW,+LED-IST,+SYD-MNL,+SYD-JKT,+SYD-LAX,+ALG-CAI,+ALG-MAD,+ALG-PAR,+ALG-IST,+MOW-LED,+MOW-THR,+MOW-IST,+YYZ-CHI,+YYZ-WAS,+YYZ-NYC,+MAA-DEL,+MAA-BOM,+MAA-CCU,+MAA-BKK,+MAA-JKT,+SFO-TYO,+SFO-MNL,+SFO-LAX,+SFO-CHI,+LAX-MEX,+LAX-SYD,+LAX-SFO,+LAX-CHI,+MAD-SAO,+MAD-ALG,+MAD-NYC,+MAD-LON,+MAD-PAR,+MEX-LIM,+MEX-LAX,+MEX-CHI,+MEX-MIA,+MEX-BOG')

  def testAverageDist(self):
    assert (self.utils.average_distance(self.g) == 2300)
    assert (self.utils.average_distance(self.gSmall) == (2453 + (24530 * 2)) / 3)

  def testBiggestPop(self):
    assert self.utils.biggest_city(self.g) == ('TYO', 34000000)
    assert self.utils.biggest_city(self.gSmall) == ('MEX', 23400000)

  def testSmallestPop(self):
    assert self.utils.smallest_city(self.g) == ( 'ESS', 589900)
    assert self.utils.smallest_city(self.gSmall) == ( 'SCL', 6000000)

  def testAveragePop(self):
    assert self.utils.average_city(self.g) == 11796143
    assert self.utils.average_city(self.gSmall) == (6000000+23400000+9050000)/3

  def testContinents(self):
    assert self.utils.get_continents_and_cities(self.g) == {
      u'Europe': [u'Paris', u'Milan', u'London', u'Istanbul', u'Essen', u'St. Petersburg', u'Moscow', u'Madrid'],
      u'Australia': [u'Sydney'], u'Africa': [u'Lagos', u'Cairo', u'Johannesburg', u'Khartoum', u'Kinshasa', u'Algiers'],
      u'Asia': [u'Beijing', u'Delhi', u'Mumbai', u'Bagdad', u'Karachi', u'Jakarta', u'Bangkok', u'Calcutta', u'Manila',
                u'Ho Chi Minh City', u'Osaka', u'Hong Kong', u'Taipei', u'Seoul', u'Tehrah', u'Shanghai', u'Riyadh',
                u'Tokyo', u'Chennai'],
      u'North America': [u'Miami', u'Atlanta', u'New York', u'Chicago', u'Washington', u'Toronto', u'San Francisco',
                         u'Los Angeles', u'Mexico City'],
      u'South America': [u'Lima', u'Bogota', u'Santiago', u'Sao Paulo', u'Buenos Aires']}

  def testHubs(self):
    assert self.utils.get_hub_cities(self.g) == ['IST', 'HKG']

  def testShortestPath(self):
    print(self.utils.shortestPath(self.g, 'CHI', 'TYO'))
    assert self.utils.shortestPath(self.g, 'CHI', 'TYO') == ['CHI', 'SFO', 'TYO']

  def testRouteDistance(self):
    assert sum(self.utils.route_distance(self.g, ['CHI', 'SFO', 'TYO'])) == (8296 + 2994)

  def testShortestPath(self):
    assert (self.utils.shortestPath(self.g, 'CHI', 'TYO') == ['CHI', 'SFO', 'TYO'])
    assert (self.utils.shortestPath(self.gSmall, 'SCL', 'MEX') == ['SCL', 'LIM', 'MEX'])
 parser.add_argument('--lightArea', help="keep number of transitions between vanilla areas", action='store_true',
                     dest='lightArea', default=False)
 parser.add_argument('--escapeRando',
                     help="Randomize the escape sequence",
                     dest='escapeRando', nargs='?', const=True, default=False)
 parser.add_argument('--noRemoveEscapeEnemies',
                     help="Do not remove enemies during escape sequence", action='store_true',
                     dest='noRemoveEscapeEnemies', default=False)
 parser.add_argument('--bosses', help="randomize bosses",
                     dest='bosses', nargs='?', const=True, default=False)
 parser.add_argument('--minimizer', help="minimizer mode: area and boss mixed together. arg is number of non boss locations",
                     dest='minimizerN', nargs='?', const=35, default=None,
                     choices=[str(i) for i in range(30,101)]+["random"])
 parser.add_argument('--startLocation', help="Name of the Access Point to start from",
                     dest='startLocation', nargs='?', default="Landing Site",
                     choices=['random'] + GraphUtils.getStartAccessPointNames())
 parser.add_argument('--startLocationList', help="list to choose from when random",
                     dest='startLocationList', nargs='?', default=None)
 parser.add_argument('--debug', '-d', help="activate debug logging", dest='debug',
                     action='store_true')
 parser.add_argument('--maxDifficulty', '-t',
                     help="the maximum difficulty generated seed will be for given parameters",
                     dest='maxDifficulty', nargs='?', default=None,
                     choices=['easy', 'medium', 'hard', 'harder', 'hardcore', 'mania', 'random'])
 parser.add_argument('--minDifficulty',
                     help="the minimum difficulty generated seed will be for given parameters (speedrun prog speed required)",
                     dest='minDifficulty', nargs='?', default=None,
                     choices=['easy', 'medium', 'hard', 'harder', 'hardcore', 'mania'])
 parser.add_argument('--seed', '-s', help="randomization seed to use", dest='seed',
                     nargs='?', default=0, type=int)
 parser.add_argument('--rom', '-r',