Пример #1
0
def queue_job(a, ready_queue):
    # We just crank out plans until we are terminated
    while True:
        b = a.copy()
        success = maxfield.maxFields(b)
        if success:
            for t in b.triangulation:
                t.markEdgesWithFields()

            maxfield.improveEdgeOrder(b)

        ready_queue.put((success, b))
Пример #2
0
def main():
    description = ('Ingress FieldPlan - Maximize the number of links '
                   'and fields, and thus AP, for a collection of '
                   'portals in the game Ingress and create a convenient plan '
                   'in Google Spreadsheets. Spin-off from Maxfield.')

    parser = argparse.ArgumentParser(
        description=description,
        prog='makePlan.py',
        formatter_class=argparse.ArgumentDefaultsHelpFormatter)
    parser.add_argument(
        '-i',
        '--iterations',
        type=int,
        default=10000,
        help='Number of iterations to perform. More iterations may improve '
        'results, but will take longer to process.')
    parser.add_argument('-k',
                        '--maxkeys',
                        type=int,
                        default=None,
                        help='Limit number of keys required per portal '
                        '(may result in less efficient plans)')
    parser.add_argument(
        '-m',
        '--travelmode',
        default='walking',
        help='Travel mode (walking, bicycling, driving, transit).')
    parser.add_argument(
        '-s',
        '--sheetid',
        default=None,
        required=True,
        help='The Google Spreadsheet ID with portal definitions.')
    parser.add_argument(
        '-n',
        '--nosave',
        action='store_true',
        default=False,
        help='Do not attempt to save the spreadsheet, just calculate the plan.'
    )
    parser.add_argument(
        '-p',
        '--plots',
        default=None,
        help='Save step-by-step PNGs of the workplan into this directory.')
    parser.add_argument(
        '--plotdpi',
        default=96,
        type=int,
        help='DPI to use for generating plots (try 144 for high-dpi screens)')
    parser.add_argument('-g',
                        '--gmapskey',
                        default=None,
                        help='Google Maps API key (for better distances)')
    parser.add_argument('-f',
                        '--faction',
                        default='enl',
                        help='Set to "res" to use resistance colours')
    parser.add_argument('-l',
                        '--log',
                        default=None,
                        help='Log file where to log processing info')
    parser.add_argument('-d',
                        '--debug',
                        action='store_true',
                        default=False,
                        help='Add debug information to the logfile')
    parser.add_argument('-q',
                        '--quiet',
                        action='store_true',
                        default=False,
                        help='Only output errors to the stdout')
    args = parser.parse_args()

    if args.iterations < 0:
        parser.error('Number of extra samples should be positive')

    if args.plotdpi < 1:
        parser.error('%s is not a valid screen dpi' % args.plotdpi)

    if args.faction not in ('enl', 'res'):
        parser.error('Sorry, I do not know about faction "%s".' % args.faction)

    logger.setLevel(logging.DEBUG)

    if args.log:
        ch = logging.FileHandler(args.log)
        formatter = logging.Formatter(
            '{%(module)s:%(funcName)s:%(lineno)s} %(message)s')
        ch.setFormatter(formatter)

        if args.debug:
            ch.setLevel(logging.DEBUG)
        else:
            ch.setLevel(logging.INFO)

        logger.addHandler(ch)

    ch = logging.StreamHandler()
    formatter = logging.Formatter('%(message)s')
    ch.setFormatter(formatter)

    if args.quiet:
        ch.setLevel(logging.CRITICAL)
    else:
        ch.setLevel(logging.INFO)

    logger.addHandler(ch)

    gs = gsheets.setup()

    portals, blockers = gsheets.get_portals_from_sheet(gs, args.sheetid)
    logger.info('Considering %d portals', len(portals))

    if len(portals) < 3:
        logger.critical('Must have more than 2 portals!')
        sys.exit(1)

    if len(portals) > _MAX_PORTALS_:
        logger.critical('Portal limit is %d', _MAX_PORTALS_)

    a = maxfield.populateGraph(portals)

    ab = None
    if blockers:
        ab = maxfield.populateGraph(blockers)

    (bestgraph, bestplan, bestdist) = maxfield.loadCache(a, ab)
    if bestgraph is None:
        # Use a copy, because we concat ab to a for blockers distances
        maxfield.genDistanceMatrix(a.copy(), ab, args.gmapskey,
                                   args.travelmode)
        bestkm = None
    else:
        bestkm = bestdist / float(1000)
        logger.info('Best distance of the plan loaded from cache: %0.2f km',
                    bestkm)

    counter = 0

    if args.maxkeys:
        logger.info('Finding an efficient plan with max %s keys', args.maxkeys)
    else:
        logger.info('Finding an efficient plan')

    logger.info('Ctrl-C to exit and use the latest best plan')

    failcount = 0

    try:
        while counter < args.iterations:
            if failcount >= 100:
                logger.info('Too many consecutive failures, exiting early.')
                break

            b = a.copy()
            counter += 1

            if not args.quiet:
                if bestkm is not None:
                    sys.stdout.write('\r(%0.2f km best): %s/%s      ' %
                                     (bestkm, counter, args.iterations))
                    sys.stdout.flush()

            failcount += 1
            if not maxfield.maxFields(b):
                logger.debug('Could not find a triangulation')
                failcount += 1
                continue

            for t in b.triangulation:
                t.markEdgesWithFields()

            maxfield.improveEdgeOrder(b)
            workplan = maxfield.makeWorkPlan(b, ab)

            if args.maxkeys:
                # do any of the portals require more than maxkeys
                sane_key_reqs = True
                for i in range(len(b.node)):
                    if b.in_degree(i) > args.maxkeys:
                        sane_key_reqs = False
                        break

                if not sane_key_reqs:
                    failcount += 1
                    logger.debug('Too many keys required, ignoring plan')
                    continue

            sane_out_links = True
            for i in range(len(b.node)):
                if b.out_degree(i) > 8:
                    sane_out_links = False
                    break

            if not sane_out_links:
                failcount += 1
                logger.debug('Too many outgoing links, ignoring plan')
                continue

            failcount = 0

            totaldist = maxfield.getWorkplanDist(b, workplan)

            if totaldist < bestdist:
                counter = 0
                bestplan = workplan
                bestgraph = b
                bestdist = totaldist
                bestkm = bestdist / float(1000)

    except KeyboardInterrupt:
        if not args.quiet:
            print()
            print('Exiting loop')

    if not args.quiet:
        print()

    if bestplan is None:
        logger.critical('Could not find a solution for this list of portals.')
        sys.exit(1)

    maxfield.saveCache(bestgraph, ab, bestplan, bestdist)

    if args.plots:
        animate.make_png_steps(bestgraph, bestplan, args.plots, args.faction,
                               args.plotdpi)

    gs = gsheets.setup()
    gsheets.write_workplan(gs, args.sheetid, bestgraph, bestplan, args.faction,
                           args.travelmode, args.nosave)
Пример #3
0
def main():
	args = docopt(__doc__)

	# We will take many samples in an attempt to reduce number of keys to farm
	# This is the number of samples to take since the last improvement
	EXTRA_SAMPLES = 20

	np = geometry.np

	#GREEN = 'g'
	#BLUE  = 'b'
	GREEN = '#3BF256' # Actual faction text colors in the app
	BLUE  = '#2ABBFF'
	#GREEN = (0.0 , 1.0 , 0.0 , 0.3)
	#BLUE  = (0.0 , 0.0 , 1.0 , 0.3)
	COLOR = GREEN

	if args['-b']:
		COLOR = BLUE

	output_directory = ''
	if args['<output_directory>'] != None:
		output_directory = args['<output_directory>']
		if output_directory[-1] != '/':
			output_directory += '/'

	output_file = 'lastPlan.pkl'
	if args['<output_file>'] != None:
		output_file = args['<output_file>']
		if not output_file[-3:] == 'pkl':
			print 'WARNING: output file should end in "pkl" or you cannot use it as input later'

	nagents = int(args['-n'])
	if nagents < 0:
		print 'Numer of agents should be positive'
		exit()

	input_file = args['<input_file>']

	if input_file[-3:] != 'pkl':
		a = nx.DiGraph()

		locs = []

		i = 0
		# each line should be id,name,lat,long,keys
		with open(input_file,'r') as fin:
			for line in fin:
				parts = line.split(',')

				if len(parts) < 3:
					break

				a.add_node(i)
				a.node[i]['name'] = parts[0].strip()

				locs.append( np.array(parts[1:3],dtype=int) )

				if len(parts) < 4:
					a.node[i]['keys'] = 0
				else:
					a.node[i]['keys'] = int(parts[3])

				i += 1

		n = a.order() # number of nodes

		locs = np.array(locs,dtype=float)

		# This part assumes we're working with E6 latitude-longitude data
		locs = geometry.e6LLtoRads(locs)
		xyz  = geometry.radstoxyz(locs)
		xy   = geometry.gnomonicProj(locs,xyz)

		for i in xrange(n):
			a.node[i]['geo'] = locs[i]
			a.node[i]['xyz'] = xyz [i]
			a.node[i]['xy' ] = xy  [i]

		# EXTRA_SAMPLES attempts to get graph with few missing keys
		# Try to minimuze TK + 2*MK where
		#   TK is the total number of missing keys
		#   MK is the maximum number of missing keys for any single portal
		bestgraph = None
		bestlack = np.inf
		bestTK = np.inf
		bestMK = np.inf

		sinceImprove = 0

		while sinceImprove<EXTRA_SAMPLES:
			b = a.copy()

			sinceImprove += 1

			if not maxfield.maxFields(b):
				print 'Randomization failure\nThe program may work if you try again. It is more likely to work if you remove some protals.'
				continue

			TK = 0
			MK = 0
			for j in xrange(n):
				keylack = max(b.in_degree(j)-b.node[j]['keys'],0)
				TK += keylack
				if keylack > MK:
					MK = keylack
			
			weightedlack = TK+2*MK

			if weightedlack < bestlack:
				sinceImprove = 0
				print 'IMPROVEMENT:\n\ttotal: %s\n\tmax:   %s\n\tweighted: %s'%\
					   (TK,MK,weightedlack)
				bestgraph = b
				bestlack  = weightedlack
				bestTK  = TK
				bestMK  = MK
			else:
				print 'this time:\n\ttotal: %s\n\tmax:   %s\n\tweighted: %s'%\
					   (TK,MK,weightedlack)

			if weightedlack == 0:
				print 'KEY PERFECTION'
				bestlack  = weightedlack
				bestTK  = TK
				bestMK  = MK
				break

			if all([ b.node[i]['keys'] <= b.out_degree(i) for i in xrange(n) ]):
				print 'All keys used. Improvement impossible'
				break

			print '%s tries since improvement'%sinceImprove

		if bestgraph == None:
			print 'EXITING RANDOMIZATION LOOP WITHOUT SOLUTION!'
			print ''
			exit()

		print 'Choosing plan requiring %s additional keys, max of %s from single portal'%(bestTK,bestMK)

		a = bestgraph

		# Attach to each edge a list of fields that it completes
		for t in a.triangulation:
			t.markEdgesWithFields()

		agentOrder.improveEdgeOrder(a)

		with open(output_directory+output_file,'w') as fout:
			pickle.dump(a,fout)
	else:
		with open(input_file,'r') as fin:
			a = pickle.load(fin)
	#    agentOrder.improveEdgeOrder(a)
	#    with open(output_directory+output_file,'w') as fout:
	#        pickle.dump(a,fout)

	PP = PlanPrinter.PlanPrinter(a,output_directory,nagents,COLOR)
	PP.keyPrep()
	PP.agentKeys()
	PP.planMap()
	PP.agentLinks()
Пример #4
0
def main():
    description = ("Ingress Maxfield - Maximize the number of links "
                   "and fields, and thus AP, for a collection of "
                   "portals in the game Ingress.")
    parser = argparse.ArgumentParser(description=description,
                                     prog="makePlan.py")
    parser.add_argument('-v',
                        '--version',
                        action='version',
                        version="Ingress Maxfield v{0}".format(_V_))
    parser.add_argument('-g',
                        '--google',
                        action='store_true',
                        help='Make maps with google maps API. Default: False')
    parser.add_argument('-a',
                        '--api_key',
                        default=None,
                        help='Google API key for Google maps. Default: None')
    parser.add_argument('-n',
                        '--num_agents',
                        type=int,
                        default='1',
                        help='Number of agents. Default: 1')
    parser.add_argument('-s',
                        '--samples',
                        type=int,
                        default=50,
                        help="Number of iterations to "
                        "perform. More iterations may improve "
                        "results, but will take longer to process. "
                        "Default: 50")
    parser.add_argument('input_file',
                        help="Input semi-colon delimited portal file")
    parser.add_argument('-d',
                        '--output_dir',
                        default='',
                        help="Directory for results. Default: "
                        "this directory")
    parser.add_argument('-f',
                        '--output_file',
                        default='plan.pkl',
                        help="Filename for pickle object. Default: "
                        "plan.pkl")
    args = vars(parser.parse_args())

    # Number of iterations to complete since last improvement
    EXTRA_SAMPLES = args["samples"]

    GREEN = '#3BF256'  # Actual faction text colors in the app
    BLUE = '#2ABBFF'
    # Use google?
    useGoogle = args['google']
    api_key = args['api_key']

    output_directory = args["output_dir"]
    # add ending separator
    if output_directory[-1] != os.sep:
        output_directory += os.sep
    # create directory if doesn't exist
    if not os.path.isdir(output_directory):
        os.mkdir(output_directory)
    output_file = args["output_file"]
    if output_file[-4:] != '.pkl':
        output_file += ".pkl"

    nagents = args["num_agents"]
    if nagents < 0:
        sys.exit("Number of agents should be positive")

    EXTRA_SAMPLES = args["samples"]
    if EXTRA_SAMPLES < 0:
        sys.exit("Number of extra samples should be positive")
    elif EXTRA_SAMPLES > 100:
        sys.exit("Extra samples may not be more than 100")

    input_file = args['input_file']

    if input_file[-3:] != 'pkl':
        # If the input file is a portal list, let's set things up
        a = nx.DiGraph()  # network tool
        locs = []  # portal coordinates
        # each line should be name;intel_link;keys
        portals = pd.read_table(input_file,
                                sep=';',
                                comment='#',
                                index_col=False,
                                names=['name', 'link', 'keys'],
                                dtype=str)
        portals = np.array(portals)
        portals = np.array([
            portal for portal in portals
            if (isinstance(portal[0], basestring)
                and isinstance(portal[1], basestring))
        ])
        print "Found {0} portals in portal list.".format(len(portals))
        if len(portals) < 3:
            sys.exit("Error: Must have more than 2 portals!")
        if len(portals) > _MAX_PORTALS_:
            sys.exit("Error: Portal limit is {0}".\
                     format(_MAX_PORTALS_))
        for num, portal in enumerate(portals):
            if len(portal) < 3:
                print "Error! Portal ", portal[0], " has a formatting problem."
                sys.exit()
            a.add_node(num)
            a.node[num]['name'] = portal[0]
            coords = (portal[1].split('pll='))
            if len(coords) < 2:
                print "Error! Portal ", portal[0], " has a formatting problem."
                sys.exit()
            coord_parts = coords[1].split(',')
            lat = int(float(coord_parts[0]) * 1.e6)
            lon = int(float(coord_parts[1]) * 1.e6)
            locs.append(np.array([lat, lon], dtype=float))
            try:
                keys = int(portal[2])
                a.node[num]['keys'] = keys
            except ValueError:
                a.node[num]['keys'] = 0

        n = a.order()  # number of nodes
        locs = np.array(locs, dtype=float)

        # Convert coords to radians, then to cartesian, then to
        # gnomonic projection
        locs = geometry.e6LLtoRads(locs)
        xyz = geometry.radstoxyz(locs)
        xy = geometry.gnomonicProj(locs, xyz)

        for i in xrange(n):
            a.node[i]['geo'] = locs[i]
            a.node[i]['xyz'] = xyz[i]
            a.node[i]['xy'] = xy[i]

        # EXTRA_SAMPLES attempts to get graph with few missing keys
        # Try to minimuze TK + 2*MK where
        # TK is the total number of missing keys
        # MK is the maximum number of missing keys for any single
        # portal
        bestgraph = None
        bestlack = np.inf
        bestTK = np.inf
        bestMK = np.inf

        allTK = []
        allMK = []
        allWeights = []

        sinceImprove = 0

        while sinceImprove < EXTRA_SAMPLES:
            b = a.copy()

            sinceImprove += 1

            if not maxfield.maxFields(b):
                print 'Randomization failure\nThe program may work if you try again. It is more likely to work if you remove some portals.'
                continue

            TK = 0
            MK = 0
            for j in xrange(n):
                keylack = max(b.in_degree(j) - b.node[j]['keys'], 0)
                TK += keylack
                if keylack > MK:
                    MK = keylack

            weightedlack = TK + 2 * MK

            allTK.append(TK)
            allMK.append(MK)
            allWeights.append(weightedlack)

            if weightedlack < bestlack:
                sinceImprove = 0
                print 'IMPROVEMENT:\n\ttotal: %s\n\tmax:   %s\n\tweighted: %s'%\
                       (TK,MK,weightedlack)
                bestgraph = b
                bestlack = weightedlack
                bestTK = TK
                bestMK = MK
            else:
                print 'this time:\n\ttotal: %s\n\tmax:   %s\n\tweighted: %s'%\
                       (TK,MK,weightedlack)

            if weightedlack <= 0:
                print 'KEY PERFECTION'
                bestlack = weightedlack
                bestTK = TK
                bestMK = MK
                break
            # if num agent keys is zero, this code isn't true...
            # if all([ b.node[i]['keys'] <= b.out_degree(i) for i in xrange(n) ]):
            #     print 'All keys used. Improvement impossible'
            #     break

            print '%s tries since improvement' % sinceImprove

        if bestgraph == None:
            print 'EXITING RANDOMIZATION LOOP WITHOUT SOLUTION!'
            print ''
            exit()

        print 'Choosing plan requiring %s additional keys, max of %s from single portal' % (
            bestTK, bestMK)

        plt.clf()
        plt.scatter(allTK, allMK, c=allWeights, marker='o')
        plt.xlim(min(allTK) - 1, max(allTK) + 1)
        plt.ylim(min(allMK) - 1, max(allMK) + 1)
        plt.xlabel('Total keys required')
        plt.ylabel('Max keys required for a single portal')
        cbar = plt.colorbar()
        cbar.set_label('Optimization Weighting (lower=better)')
        plt.savefig(output_directory + 'optimization.png')

        a = bestgraph

        # Attach to each edge a list of fields that it completes
        # catch no triangulation (bad portal file?)
        try:
            for t in a.triangulation:
                t.markEdgesWithFields()
        except AttributeError:
            print "Error: problem with bestgraph... no triangulation...?"

        agentOrder.improveEdgeOrder(a)

        with open(output_directory + output_file, 'w') as fout:
            pickle.dump(a, fout)
    else:
        with open(input_file, 'r') as fin:
            a = pickle.load(fin)
    #    agentOrder.improveEdgeOrder(a)
    #    with open(output_directory+output_file,'w') as fout:
    #        pickle.dump(a,fout)

    PP = PlanPrinterMap.PlanPrinter(a,
                                    output_directory,
                                    nagents,
                                    useGoogle=useGoogle,
                                    api_key=api_key)
    PP.keyPrep()
    PP.agentKeys()
    PP.planMap(useGoogle=useGoogle)
    PP.agentLinks()

    # These make step-by-step instructional images
    PP.animate(useGoogle=useGoogle)
    PP.split3instruct(useGoogle=useGoogle)

    print "Number of portals: {0}".format(PP.num_portals)
    print "Number of links: {0}".format(PP.num_links)
    print "Number of fields: {0}".format(PP.num_fields)
    portal_ap = (125 * 8 + 500 + 250) * PP.num_portals
    link_ap = 313 * PP.num_links
    field_ap = 1250 * PP.num_fields
    print "AP from portals capture: {0}".format(portal_ap)
    print "AP from link creation: {0}".format(link_ap)
    print "AP from field creation: {0}".format(field_ap)
    print "Total AP: {0}".format(portal_ap + link_ap + field_ap)
Пример #5
0
def main():
    description=("Ingress Maxfield - Maximize the number of links "
                 "and fields, and thus AP, for a collection of "
                 "portals in the game Ingress.")
    parser = argparse.ArgumentParser(description=description,
                                     prog="makePlan.py")
    parser.add_argument('-v','--version',action='version',
                        version="Ingress Maxfield v{0}".format(_V_))
    parser.add_argument('-g','--google',action='store_true',
                        help='Make maps with google maps API. Default: False')
    parser.add_argument('-a','--api_key',default=None,
                        help='Google API key for Google maps. Default: None')
    parser.add_argument('-n','--num_agents',type=int,default='1',
                        help='Number of agents. Default: 1')
    parser.add_argument('-s','--samples',type=int,default=50,
                        help="Number of iterations to "
                        "perform. More iterations may improve "
                        "results, but will take longer to process. "
                        "Default: 50")
    parser.add_argument('input_file',
                        help="Input semi-colon delimited portal file")
    args = vars(parser.parse_args())

    # Number of iterations to complete since last improvement
    EXTRA_SAMPLES = args["samples"]

    GREEN = '#3BF256' # Actual faction text colors in the app
    BLUE  = '#2ABBFF'
    # Use google?
    useGoogle = True
    api_key = args['api_key']

    input_file = args['input_file']

    output_directory = os.path.expanduser('~') + "/Ingress/Fielding/{}".format(os.path.split(args['input_file'])[1][:-4])
    print(output_directory)
    # add ending separator
    if output_directory[-1] != os.sep:
        output_directory += os.sep
    # create directory if doesn't exist
    if not os.path.exists(output_directory):
        os.makedirs(output_directory)
    output_file = (os.path.split(args['input_file'])[1][:-4])
    print(output_file)
    if output_file[-4:] != '.pkl':
        output_file += ".pkl"

    nagents = args["num_agents"]
    if nagents < 0:
        sys.exit("Number of agents should be positive")

    EXTRA_SAMPLES = args["samples"]
    if EXTRA_SAMPLES < 0:
        sys.exit("Number of extra samples should be positive")
    elif EXTRA_SAMPLES > 100:
        sys.exit("Extra samples may not be more than 100")

    if input_file[-3:] != 'pkl':
        # If the input file is a portal list, let's set things up
        a = nx.DiGraph() # network tool
        locs = [] # portal coordinates
        # each line should be name;intel_link;keys
        portals = pd.read_table(input_file,sep=';',
                                comment='#',index_col=False,
                                names=['name','link','keys'],dtype=str)
        portals = np.array(portals)
        portals = np.array([portal for portal in portals if (isinstance(portal[0], basestring) and isinstance(portal[1], basestring))])
        print ("Found {0} portals in portal list.".format(len(portals)))
        if len(portals) < 3:
            sys.exit("Error: Must have more than 2 portals!")
        if len(portals) > _MAX_PORTALS_:
            sys.exit("Error: Portal limit is {0}".\
                     format(_MAX_PORTALS_))
        for num,portal in enumerate(portals):
            if len(portal) < 3:
                print ("Error! Portal ",portal[0]," has a formatting problem.")
                sys.exit()
            a.add_node(num)
            a.node[num]['name'] = portal[0]
            coords = (portal[1].split('pll='))
            if len(coords) < 2:
                print ("Error! Portal ",portal[0]," has a formatting problem.")
                sys.exit()
            coord_parts = coords[1].split(',')
            lat = int(float(coord_parts[0]) * 1.e6)
            lon = int(float(coord_parts[1]) * 1.e6)
            locs.append(np.array([lat,lon],dtype=float))
            try:
                keys = int(portal[2])
                a.node[num]['keys'] = keys
            except ValueError:
                a.node[num]['keys'] = 0

        n = a.order() # number of nodes
        locs = np.array(locs,dtype=float)

        # Convert coords to radians, then to cartesian, then to
        # gnomonic projection
        locs = geometry.e6LLtoRads(locs)
        xyz  = geometry.radstoxyz(locs)
        xy   = geometry.gnomonicProj(locs,xyz)

        for i in range(n):
            a.node[i]['geo'] = locs[i]
            a.node[i]['xyz'] = xyz[i]
            a.node[i]['xy' ] = xy[i]

        # EXTRA_SAMPLES attempts to get graph with few missing keys
        # Try to minimuze TK + 2*MK where
        # TK is the total number of missing keys
        # MK is the maximum number of missing keys for any single
        # portal
        bestgraph = None
        bestlack = np.inf
        bestTK = np.inf
        bestMK = np.inf

        allTK = []
        allMK = []
        allWeights = []

        sinceImprove = 0

        while sinceImprove<EXTRA_SAMPLES:
            b = a.copy()

            sinceImprove += 1

            if not maxfield.maxFields(b):
                print ('Randomization failure\nThe program may work if you try again. It is more likely to work if you remove some portals.')
                continue

            TK = 0
            MK = 0
            for j in range(n):
                keylack = max(b.in_degree(j)-b.node[j]['keys'],0)
                TK += keylack
                if keylack > MK:
                    MK = keylack
            
            weightedlack = TK+2*MK

            allTK.append(TK)
            allMK.append(MK)
            allWeights.append(weightedlack)

            if weightedlack < bestlack:
                sinceImprove = 0
                print ('IMPROVEMENT:\n\ttotal: %s\n\tmax:   %s\n\tweighted: %s'%\
                       (TK,MK,weightedlack))
                bestgraph = b
                bestlack  = weightedlack
                bestTK  = TK
                bestMK  = MK
            else:
                print ('this time:\n\ttotal: %s\n\tmax:   %s\n\tweighted: %s'%\
                       (TK,MK,weightedlack))

            if weightedlack <= 0:
                print ('KEY PERFECTION')
                bestlack  = weightedlack
                bestTK  = TK
                bestMK  = MK
                break
            # if num agent keys is zero, this code isn't true...
            # if all([ b.node[i]['keys'] <= b.out_degree(i) for i in xrange(n) ]):
            #     print 'All keys used. Improvement impossible'
            #     break

            print ('%s tries since improvement'%sinceImprove)

        if bestgraph == None:
            print ('EXITING RANDOMIZATION LOOP WITHOUT SOLUTION!')
            print ('')
            exit()

        print ('Choosing plan requiring %s additional keys, max of %s from single portal'%(bestTK,bestMK))

        plt.clf()
        plt.scatter(allTK,allMK,c=allWeights,marker='o')
        plt.xlim(min(allTK)-1,max(allTK)+1)
        plt.ylim(min(allMK)-1,max(allMK)+1)
        plt.xlabel('Total keys required')
        plt.ylabel('Max keys required for a single portal')
        cbar = plt.colorbar()
        cbar.set_label('Optimization Weighting (lower=better)')
        plt.savefig(output_directory+'optimization.png')

        a = bestgraph

        # Attach to each edge a list of fields that it completes
        # catch no triangulation (bad portal file?)
        try:
            for t in a.triangulation:
                t.markEdgesWithFields()
        except AttributeError:
            print ("Error: problem with bestgraph... no triangulation...?")

        agentOrder.improveEdgeOrder(a)

        with open(output_directory+output_file,'wb') as fout:
            pickle.dump(a,fout)
    else:
        with open(input_file,'r') as fin:
            a = pickle.load(fin)
    #    agentOrder.improveEdgeOrder(a)
    #    with open(output_directory+output_file,'w') as fout:
    #        pickle.dump(a,fout)

    PP = PlanPrinterMap.PlanPrinter(a,output_directory,nagents,color=BLUE,useGoogle=useGoogle,
                                    api_key=api_key)
    PP.keyPrep()
    PP.agentKeys()
    PP.planMap(useGoogle=useGoogle)
    PP.agentLinks()

    # These make step-by-step instructional images
    PP.animate(useGoogle=useGoogle)
    PP.split3instruct(useGoogle=useGoogle)

    print ("Number of portals: {0}".format(PP.num_portals))
    print ("Number of links: {0}".format(PP.num_links))
    print ("Number of fields: {0}".format(PP.num_fields))
    portal_ap = (125*8 + 500 + 250)*PP.num_portals
    link_ap = 313 * PP.num_links
    field_ap = 1250 * PP.num_fields
    print ("AP from portals capture: {0}".format(portal_ap))
    print ("AP from link creation: {0}".format(link_ap))
    print ("AP from field creation: {0}".format(field_ap))
    print ("Total AP: {0}".format(portal_ap+link_ap+field_ap))
Пример #6
0
def main():
    args = docopt(__doc__)

    # We will take many samples in an attempt to reduce number of keys to farm
    # This is the number of samples to take since the last improvement
    EXTRA_SAMPLES = 20

    np = geometry.np

    #GREEN = 'g'
    #BLUE  = 'b'
    GREEN = '#3BF256' # Actual faction text colors in the app
    BLUE  = '#2ABBFF'
    #GREEN = (0.0 , 1.0 , 0.0 , 0.3)
    #BLUE  = (0.0 , 0.0 , 1.0 , 0.3)
    COLOR = BLUE

    if args['-b']:
        COLOR = GREEN

    output_directory = ''
    if args['<output_directory>'] != None:
        output_directory = args['<output_directory>']
        if output_directory[-1] != '/':
            output_directory += '/'
        if( not os.path.isdir('./'+output_directory) ):
            print 'Output directory (%s) does not exist. Creating it.' % output_directory
            os.makedirs('./'+output_directory)

    output_file = 'lastPlan.pkl'
    if args['<output_file>'] != None:
        output_file = args['<output_file>']
        if not output_file[-3:] == 'pkl':
            print 'WARNING: output file should end in "pkl" or you cannot use it as input later'

    nagents = int(args['-n'])
    if nagents < 0:
        print 'Numer of agents should be positive'
        exit()

    input_file = args['<input_file>']

    if input_file[-3:] != 'pkl':
        a = nx.DiGraph()

        locs = []

        i = 0
        # each line should be id,name,lat,long,keys
        with open(input_file,'r') as fin:
            for line in fin:
                parts = line.split(',')

                if len(parts) < 3:
                    break

                # allow masking of input csv file
                # note, if no 4th column, back to default behavior
                # unless you put "false" as the number of keys ;)
                use = parts[-1].strip().lower()
                if(use == "false"): continue

                a.add_node(i)
                a.node[i]['name'] = parts[0].strip()

                locs.append( np.array(parts[1:3],dtype=int) )

                if len(parts) < 4:
                    a.node[i]['keys'] = 0
                else:
                    a.node[i]['keys'] = int(parts[3])

                i += 1

        n = a.order() # number of nodes

        locs = np.array(locs,dtype=float)

        # This part assumes we're working with E6 latitude-longitude data
        locs = geometry.e6LLtoRads(locs)
        xyz  = geometry.radstoxyz(locs)
        xy   = geometry.gnomonicProj(locs,xyz)

        for i in xrange(n):
            a.node[i]['geo'] = locs[i]
            a.node[i]['xyz'] = xyz [i]
            a.node[i]['xy' ] = xy  [i]

        # EXTRA_SAMPLES attempts to get graph with few missing keys
        # Try to minimuze TK + 2*MK where
        #   TK is the total number of missing keys
        #   MK is the maximum number of missing keys for any single portal
        bestgraph = None
        bestlack = np.inf
        bestTK = np.inf
        bestMK = np.inf

        sinceImprove = 0

        while sinceImprove<EXTRA_SAMPLES:
            b = a.copy()

            sinceImprove += 1

            if not maxfield.maxFields(b):
                print 'Randomization failure\nThe program may work if you try again. It is more likely to work if you remove some protals.'
                continue

            TK = 0
            MK = 0
            for j in xrange(n):
                keylack = max(b.in_degree(j)-b.node[j]['keys'],0)
                TK += keylack
                if keylack > MK:
                    MK = keylack

            weightedlack = TK+2*MK

            if weightedlack < bestlack:
                sinceImprove = 0
                print 'IMPROVEMENT:\n\ttotal: %s\n\tmax:   %s\n\tweighted: %s'%\
                        (TK,MK,weightedlack)
                bestgraph = b
                bestlack  = weightedlack
                bestTK  = TK
                bestMK  = MK
            else:
                print 'this time:\n\ttotal: %s\n\tmax:   %s\n\tweighted: %s'%\
                        (TK,MK,weightedlack)

            if weightedlack == 0:
                print 'KEY PERFECTION'
                bestlack  = weightedlack
                bestTK  = TK
                bestMK  = MK
                break

            if all([ b.node[i]['keys'] <= b.out_degree(i) for i in xrange(n) ]):
                print 'All keys used. Improvement impossible'
                break

            print '%s tries since improvement'%sinceImprove

        if bestgraph == None:
            print 'EXITING RANDOMIZATION LOOP WITHOUT SOLUTION!'
            print ''
            exit()

        print 'Choosing plan requiring %s additional keys, max of %s from single portal'%(bestTK,bestMK)

        a = bestgraph

        # Attach to each edge a list of fields that it completes
        for t in a.triangulation:
            t.markEdgesWithFields()

        agentOrder.improveEdgeOrder(a)

        with open(output_directory+output_file,'w') as fout:
            pickle.dump(a,fout)
    else:
        with open(input_file,'r') as fin:
            a = pickle.load(fin)
    #    agentOrder.improveEdgeOrder(a)
    #    with open(output_directory+output_file,'w') as fout:
    #        pickle.dump(a,fout)

    PP = PlanPrinter.PlanPrinter(a,output_directory,nagents,COLOR)
    PP.keyPrep()
    PP.agentKeys()
    PP.planMap()
    PP.agentLinks()
Пример #7
0
def main(args):
    start_time = time.time()
    if args.log is not None:
        sys.stdout = open(args.log,'w',0)
    GREEN = '#3BF256' # Actual faction text colors in the app
    BLUE  = '#2ABBFF'
    if args.res:
        color=BLUE
    else:
        color=GREEN
    # Use google?
    useGoogle = args.google
    api_key = args.api_key

    output_directory = args.output_dir
    # add ending separator
    if output_directory[-1] != os.sep:
        output_directory += os.sep
    # create directory if doesn't exist
    if not os.path.isdir(output_directory):
        os.mkdir(output_directory)
    output_file = args.output_file
    if output_file[-4:] != '.pkl':
        output_file += ".pkl"

    nagents = args.num_agents
    if nagents <= 0:
        print "Number of agents should be greater than zero"
        raise ValueError("Number of agents should be greater than zero")

    input_file = args.input_file

    if input_file[-3:] != 'pkl':
        # If the input file is a portal list, let's set things up
        a = nx.DiGraph() # network tool
        locs = [] # portal coordinates
        # each line should be name;intel_link;keys
        portals = pd.read_table(input_file,sep=';',
                                comment='#',index_col=False,
                                names=['name','link','keys','sbla'],
                                dtype=str)
        portals = np.array(portals)
        portals = np.array([portal for portal in portals if (isinstance(portal[0], basestring) and isinstance(portal[1], basestring))])
        print "Found {0} portals in portal list.".format(len(portals))
        if len(portals) < 3:
            print "Error: Must have more than 2 portals!"
            raise ValueError("Error: Must have more than 2 portals!")
        if len(portals) > _MAX_PORTALS_:
            print "Error: Portal limit is {0}".format(_MAX_PORTALS_)
            raise ValueError("Error: Portal limit is {0}".format(_MAX_PORTALS_))
        for num,portal in enumerate(portals):
            if len(portal) < 3:
                print "Error! Portal ",portal[0]," has a formatting problem."
                raise ValueError("Error! Portal ",portal[0]," has a formatting problem.")
            # loop over columns. Four possibilities:
            # 0. First entry is always portal name
            # 1. contains "pll=" it is the Intel URL
            # 2. contains an intenger, it is the number of keys
            # 3. contains "sbla", it is an SBLA portal
            loc = None
            keys = 0
            sbla = False
            for pind,pfoobar in enumerate(portal):
                if str(pfoobar) == 'nan':
                    continue
                if pind == 0: # This is the name
                    a.add_node(num)
                    a.node[num]['name'] = pfoobar.strip()
                    continue
                if 'pll=' in pfoobar: # this is the URL
                    if loc is not None:
                        print "Error! Already found URL for this portal: {0}".format(portal[0])
                        raise ValueError("Error! Already found URL for this portal: {0}".format(portal[0]))
                    coords = (pfoobar.strip().split('pll='))
                    if len(coords) < 2:
                        print "Error! Portal ",portal[0]," has a formatting problem."
                        raise ValueError("Error! Portal ",portal[0]," has a formatting problem.")
                    coord_parts = coords[1].split(',')
                    lat = int(float(coord_parts[0]) * 1.e6)
                    lon = int(float(coord_parts[1]) * 1.e6)
                    loc = np.array([lat,lon],dtype=float)
                    continue
                try: # this is the number of keys
                    keys = int(pfoobar.strip())
                    continue
                except ValueError:
                    pass
                try: # this is SBLA
                    sbla = pfoobar.strip()
                    sbla = (sbla.lower() == 'sbla')
                    continue
                except ValueError:
                    pass
                # we should never get here unless there was a bad column
                print "Error: bad data value here:"
                print portal
                print pfoobar
                raise ValueError()
            if loc is None:
                print "Formatting problem: {0}".format(portal[0])
                raise ValueError("Formatting problem: {0}".format(portal[0]))
            locs.append(loc)
            a.node[num]['keys'] = keys
            a.node[num]['sbla'] = sbla
            if sbla:
                print "{0} has SBLA".format(portal[0])

        n = a.order() # number of nodes
        locs = np.array(locs,dtype=float)

        # Convert coords to radians, then to cartesian, then to
        # gnomonic projection
        locs = geometry.LLtoRads(locs)
        xyz  = geometry.radstoxyz(locs)
        xy   = geometry.gnomonicProj(locs,xyz)

        for i in xrange(n):
            a.node[i]['geo'] = locs[i]
            a.node[i]['xyz'] = xyz[i]
            a.node[i]['xy' ] = xy[i]

        # Below is remnants from "random optimization" technique
        """
        # EXTRA_SAMPLES attempts to get graph with few missing keys
        # Try to minimuze TK + 2*MK where
        # TK is the total number of missing keys
        # MK is the maximum number of missing keys for any single
        # portal
        bestgraph = None
        bestlack = np.inf
        bestTK = np.inf
        bestMK = np.inf

        allTK = []
        allMK = []
        allWeights = []

        sinceImprove = 0

        while sinceImprove<EXTRA_SAMPLES:
            b = a.copy()

            sinceImprove += 1

            if not maxfield.maxFields(b):
                print 'Randomization failure\nThe program may work if you try again. It is more likely to work if you remove some portals.'
                continue

            TK = 0
            MK = 0
            for j in xrange(n):
                keylack = max(b.in_degree(j)-b.node[j]['keys'],0)
                TK += keylack
                if keylack > MK:
                    MK = keylack
            
            weightedlack = TK+2*MK

            allTK.append(TK)
            allMK.append(MK)
            allWeights.append(weightedlack)

            if weightedlack < bestlack:
                sinceImprove = 0
                print 'IMPROVEMENT:\n\ttotal: %s\n\tmax:   %s\n\tweighted: %s'%\
                       (TK,MK,weightedlack)
                bestgraph = b
                bestlack  = weightedlack
                bestTK  = TK
                bestMK  = MK
            else:
                print 'this time:\n\ttotal: %s\n\tmax:   %s\n\tweighted: %s'%\
                       (TK,MK,weightedlack)

            if weightedlack <= 0:
                print 'KEY PERFECTION'
                bestlack  = weightedlack
                bestTK  = TK
                bestMK  = MK
                break
            # if num agent keys is zero, this code isn't true...
            # if all([ b.node[i]['keys'] <= b.out_degree(i) for i in xrange(n) ]):
            #     print 'All keys used. Improvement impossible'
            #     break

            print '%s tries since improvement'%sinceImprove

        if bestgraph == None:
            print 'EXITING RANDOMIZATION LOOP WITHOUT SOLUTION!'
            print ''
            exit()

        print 'Choosing plan requiring %s additional keys, max of %s from single portal'%(bestTK,bestMK)

        plt.clf()
        plt.scatter(allTK,allMK,c=allWeights,marker='o')
        plt.xlim(min(allTK)-1,max(allTK)+1)
        plt.ylim(min(allMK)-1,max(allMK)+1)
        plt.xlabel('Total keys required')
        plt.ylabel('Max keys required for a single portal')
        cbar = plt.colorbar()
        cbar.set_label('Optimization Weighting (lower=better)')
        plt.savefig(output_directory+'optimization.png')

        a = bestgraph
        """
        with open(output_directory+output_file,'w') as fout:
            pickle.dump(a,fout)
    else:
        with open(input_file,'r') as fin:
            a = pickle.load(fin)

    # Optimize the plan to get shortest walking distance
    best_plan = None
    best_PP = None
    best_time = 1.e9
    for foobar in xrange(args.attempts):
        if not args.quiet:
            tdiff = time.time() - start_time
            hrs = int(tdiff/3600.)
            mins = int((tdiff-3600.*hrs)/60.)
            secs = tdiff-3600.*hrs-60.*mins
            sys.stdout.write("\r[{0:20s}] {1}% ({2}/{3} iterations) : {4:02}h {5:02}m {6:05.2f}s".\
                         format('#'*(20*foobar/args.attempts),
                                100*foobar/args.attempts,
                                foobar,args.attempts,
                                hrs,mins,secs))
        b = copy.deepcopy(a)
        maxfield.maxFields(b,allow_suboptimal=(not args.optimal))
        # Attach to each edge a list of fields that it completes
        # catch no triangulation (bad portal file?)
        try:
            for t in b.triangulation:
                t.markEdgesWithFields()
        except AttributeError:
            print "Error: problem with bestgraph... no triangulation...?"
        agentOrder.improveEdgeOrder(b)
        PP = PlanPrinterMap.PlanPrinter(b,output_directory,nagents,useGoogle=useGoogle,
                                        api_key=api_key,color=color)
        totalTime = b.walktime+b.linktime+b.commtime
        if totalTime < best_time:
            best_plan = b
            best_PP = copy.deepcopy(PP)
            best_time = totalTime
    if not args.quiet:
        tdiff = time.time() - start_time
        hrs = int(tdiff/3600.)
        mins = int((tdiff-3600.*hrs)/60.)
        secs = tdiff-3600.*hrs-60.*mins
        sys.stdout.write("\r[{0:20s}] {1}% ({2}/{3} iterations) : {4:02}h {5:02}m {6:05.2f}s".\
                         format('#'*(20),
                                100,args.attempts,args.attempts,
                                hrs,mins,secs))
        print ""

    # generate plan details and map
    best_PP.keyPrep()
    best_PP.agentKeys()
    best_PP.planMap(useGoogle=useGoogle)
    best_PP.agentLinks()

    # These make step-by-step instructional images
    if not args.skipplot:
        best_PP.animate(useGoogle=useGoogle)
        best_PP.split3instruct(useGoogle=useGoogle)

    print ""
    print ""
    print ""
    print "Found best plan after {0} iterations.".format(args.attempts)
    totalTime = best_plan.walktime+best_plan.linktime+best_plan.commtime
    print "Total time: {0} minutes".format(int(totalTime/60. + 0.5))
    print "Number of portals: {0}".format(best_PP.num_portals)
    print "Number of links: {0}".format(best_PP.num_links)
    print "Number of fields: {0}".format(best_PP.num_fields)
    portal_ap = (125*8 + 500 + 250)*best_PP.num_portals
    link_ap = 313 * best_PP.num_links
    field_ap = 1250 * best_PP.num_fields
    print "AP from portals capture: {0}".format(portal_ap)
    print "AP from link creation: {0}".format(link_ap)
    print "AP from field creation: {0}".format(field_ap)
    print "Total AP: {0}".format(portal_ap+link_ap+field_ap)

    tdiff = time.time() - start_time
    hrs = int(tdiff/3600.)
    mins = int((tdiff-3600.*hrs)/60.)
    secs = tdiff-3600.*hrs-60.*mins
    print "Runtime: {0:02}h {1:02}m {2:05.2f}s".format(hrs,mins,secs)

    plt.close('all')
Пример #8
0
def main(args):
    start_time = time.time()
    if args.log is not None:
        sys.stdout = open(args.log, 'w', 0)
    GREEN = '#3BF256'  # Actual faction text colors in the app
    BLUE = '#2ABBFF'
    if args.res:
        color = BLUE
    else:
        color = GREEN
    # Use google?
    useGoogle = args.google
    api_key = args.api_key

    output_directory = args.output_dir
    # add ending separator
    if output_directory[-1] != os.sep:
        output_directory += os.sep
    # create directory if doesn't exist
    if not os.path.isdir(output_directory):
        os.mkdir(output_directory)
    output_file = args.output_file
    if output_file[-4:] != '.pkl':
        output_file += ".pkl"

    nagents = args.num_agents
    if nagents <= 0:
        print "Number of agents should be greater than zero"
        raise ValueError("Number of agents should be greater than zero")

    input_file = args.input_file

    if input_file[-3:] != 'pkl':
        # If the input file is a portal list, let's set things up
        a = nx.DiGraph()  # network tool
        locs = []  # portal coordinates
        # each line should be name;intel_link;keys
        portals = pd.read_table(input_file,
                                sep=';',
                                comment='#',
                                index_col=False,
                                names=['name', 'link', 'keys', 'sbla'],
                                dtype=str)
        portals = np.array(portals)
        portals = np.array([
            portal for portal in portals
            if (isinstance(portal[0], basestring)
                and isinstance(portal[1], basestring))
        ])
        print "Found {0} portals in portal list.".format(len(portals))

        intel_url = "https://www.ingress.com/intel?z=17&"  # setup url for intel map
        ll_set = False
        pls = []

        if len(portals) < 3:
            print "Error: Must have more than 2 portals!"
            raise ValueError("Error: Must have more than 2 portals!")
        if len(portals) > _MAX_PORTALS_:
            print "Error: Portal limit is {0}".format(_MAX_PORTALS_)
            raise ValueError(
                "Error: Portal limit is {0}".format(_MAX_PORTALS_))
        for num, portal in enumerate(portals):
            if len(portal) < 3:
                print "Error! Portal ", portal[0], " has a formatting problem."
                raise ValueError("Error! Portal ", portal[0],
                                 " has a formatting problem.")
            # loop over columns. Four possibilities:
            # 0. First entry is always portal name
            # 1. contains "pll=" it is the Intel URL
            # 2. contains an intenger, it is the number of keys
            # 3. contains "sbla", it is an SBLA portal
            loc = None
            keys = 0
            sbla = False
            for pind, pfoobar in enumerate(portal):
                if str(pfoobar) == 'nan':
                    continue
                if pind == 0:  # This is the name
                    a.add_node(num)
                    a.node[num]['name'] = pfoobar.strip()
                    continue
                if 'pll=' in pfoobar:  # this is the URL
                    if loc is not None:
                        print "Error! Already found URL for this portal: {0}".format(
                            portal[0])
                        raise ValueError(
                            "Error! Already found URL for this portal: {0}".
                            format(portal[0]))
                    coords = (pfoobar.strip().split('pll='))
                    if len(coords) < 2:
                        print "Error! Portal ", portal[
                            0], " has a formatting problem."
                        raise ValueError("Error! Portal ", portal[0],
                                         " has a formatting problem.")
                    coord_parts = coords[1].split(',')
                    lat = int(float(coord_parts[0]) * 1.e6)
                    lon = int(float(coord_parts[1]) * 1.e6)
                    pls.append(coord_parts[0] + "," + coord_parts[1])
                    loc = np.array([lat, lon], dtype=float)
                    if not ll_set:
                        # use coordinates from first portal to center the map
                        intel_url += "ll=" + coord_parts[
                            0] + "," + coord_parts[1] + "&"
                        ll_set = True
                    continue
                try:  # this is the number of keys
                    keys = int(pfoobar.strip())
                    continue
                except ValueError:
                    pass
                try:  # this is SBLA
                    sbla = pfoobar.strip()
                    sbla = (sbla.lower() == 'sbla')
                    continue
                except ValueError:
                    pass
                # we should never get here unless there was a bad column
                print "Error: bad data value here:"
                print portal
                print pfoobar
                raise ValueError()
            if loc is None:
                print "Formatting problem: {0}".format(portal[0])
                raise ValueError("Formatting problem: {0}".format(portal[0]))
            locs.append(loc)
            a.node[num]['keys'] = keys
            a.node[num]['sbla'] = sbla
            if sbla:
                print "{0} has SBLA".format(portal[0])

        n = a.order()  # number of nodes
        locs = np.array(locs, dtype=float)

        # Convert coords to radians, then to cartesian, then to
        # gnomonic projection
        locs = geometry.LLtoRads(locs)
        xyz = geometry.radstoxyz(locs)
        xy = geometry.gnomonicProj(locs, xyz)

        for i in xrange(n):
            a.node[i]['geo'] = locs[i]
            a.node[i]['xyz'] = xyz[i]
            a.node[i]['xy'] = xy[i]

        # build portal list for intel_url
        intel_url += "pls="
        json_output = []
        for p in xrange(len(pls)):
            if p < len(pls) - 1:
                intel_url += pls[p] + "," + pls[p + 1]
                intel_url += "_"
                json_output.append({
                    "type":
                    "polyline",
                    "latLngs": [{
                        "lat": pls[p].split(',')[0],
                        "lng": pls[p].split(',')[1]
                    }, {
                        "lat": pls[p + 1].split(',')[0],
                        "lng": pls[p + 1].split(',')[1]
                    }],
                    "color":
                    "#a24ac3"
                })
            elif p == len(pls) - 1:
                intel_url += pls[p] + "," + pls[0]
                json_output.append({
                    "type":
                    "polyline",
                    "latLngs": [{
                        "lat": pls[p].split(',')[0],
                        "lng": pls[p].split(',')[1]
                    }, {
                        "lat": pls[0].split(',')[0],
                        "lng": pls[0].split(',')[1]
                    }],
                    "color":
                    "#a24ac3"
                })
        print intel_url
        print json.dumps(json_output, indent=4)

        # Below is remnants from "random optimization" technique
        """
        # EXTRA_SAMPLES attempts to get graph with few missing keys
        # Try to minimuze TK + 2*MK where
        # TK is the total number of missing keys
        # MK is the maximum number of missing keys for any single
        # portal
        bestgraph = None
        bestlack = np.inf
        bestTK = np.inf
        bestMK = np.inf

        allTK = []
        allMK = []
        allWeights = []

        sinceImprove = 0

        while sinceImprove<EXTRA_SAMPLES:
            b = a.copy()

            sinceImprove += 1

            if not maxfield.maxFields(b):
                print 'Randomization failure\nThe program may work if you try again. It is more likely to work if you remove some portals.'
                continue

            TK = 0
            MK = 0
            for j in xrange(n):
                keylack = max(b.in_degree(j)-b.node[j]['keys'],0)
                TK += keylack
                if keylack > MK:
                    MK = keylack
            
            weightedlack = TK+2*MK

            allTK.append(TK)
            allMK.append(MK)
            allWeights.append(weightedlack)

            if weightedlack < bestlack:
                sinceImprove = 0
                print 'IMPROVEMENT:\n\ttotal: %s\n\tmax:   %s\n\tweighted: %s'%\
                       (TK,MK,weightedlack)
                bestgraph = b
                bestlack  = weightedlack
                bestTK  = TK
                bestMK  = MK
            else:
                print 'this time:\n\ttotal: %s\n\tmax:   %s\n\tweighted: %s'%\
                       (TK,MK,weightedlack)

            if weightedlack <= 0:
                print 'KEY PERFECTION'
                bestlack  = weightedlack
                bestTK  = TK
                bestMK  = MK
                break
            # if num agent keys is zero, this code isn't true...
            # if all([ b.node[i]['keys'] <= b.out_degree(i) for i in xrange(n) ]):
            #     print 'All keys used. Improvement impossible'
            #     break

            print '%s tries since improvement'%sinceImprove

        if bestgraph == None:
            print 'EXITING RANDOMIZATION LOOP WITHOUT SOLUTION!'
            print ''
            exit()

        print 'Choosing plan requiring %s additional keys, max of %s from single portal'%(bestTK,bestMK)

        plt.clf()
        plt.scatter(allTK,allMK,c=allWeights,marker='o')
        plt.xlim(min(allTK)-1,max(allTK)+1)
        plt.ylim(min(allMK)-1,max(allMK)+1)
        plt.xlabel('Total keys required')
        plt.ylabel('Max keys required for a single portal')
        cbar = plt.colorbar()
        cbar.set_label('Optimization Weighting (lower=better)')
        plt.savefig(output_directory+'optimization.png')

        a = bestgraph
        """
        with open(output_directory + output_file, 'w') as fout:
            pickle.dump(a, fout)
    else:
        with open(input_file, 'r') as fin:
            a = pickle.load(fin)

    # Optimize the plan to get shortest walking distance
    best_plan = None
    best_PP = None
    best_time = 1.e9
    for foobar in xrange(args.attempts):
        if not args.quiet:
            tdiff = time.time() - start_time
            hrs = int(tdiff / 3600.)
            mins = int((tdiff - 3600. * hrs) / 60.)
            secs = tdiff - 3600. * hrs - 60. * mins
            sys.stdout.write("\r[{0:20s}] {1}% ({2}/{3} iterations) : {4:02}h {5:02}m {6:05.2f}s".\
                         format('#'*(20*foobar/args.attempts),
                                100*foobar/args.attempts,
                                foobar,args.attempts,
                                hrs,mins,secs))
        b = copy.deepcopy(a)
        maxfield.maxFields(b, allow_suboptimal=(not args.optimal))
        # Attach to each edge a list of fields that it completes
        # catch no triangulation (bad portal file?)
        try:
            for t in b.triangulation:
                t.markEdgesWithFields()
        except AttributeError:
            print "Error: problem with bestgraph... no triangulation...?"
        agentOrder.improveEdgeOrder(b)
        PP = PlanPrinterMap.PlanPrinter(b,
                                        output_directory,
                                        nagents,
                                        useGoogle=useGoogle,
                                        api_key=api_key,
                                        color=color)
        totalTime = b.walktime + b.linktime + b.commtime
        if totalTime < best_time:
            best_plan = b
            best_PP = copy.deepcopy(PP)
            best_time = totalTime

    b = best_plan
    agentOrder.improveEdgeOrderMore(b)

    # Re-run to fix the animations and stars of edges that can be done early
    # (improveEdgeOrderMore may have modified the completion order)
    try:
        first = True
        for t in b.triangulation:
            t.markEdgesWithFields(clean=first)
            first = False
    except AttributeError:
        print "Error: problem with bestgraph... no triangulation...?"

    best_PP = PlanPrinterMap.PlanPrinter(b,
                                         output_directory,
                                         nagents,
                                         useGoogle=useGoogle,
                                         api_key=api_key,
                                         color=color)
    best_time = b.walktime + b.linktime + b.commtime

    if not args.quiet:
        tdiff = time.time() - start_time
        hrs = int(tdiff / 3600.)
        mins = int((tdiff - 3600. * hrs) / 60.)
        secs = tdiff - 3600. * hrs - 60. * mins
        sys.stdout.write("\r[{0:20s}] {1}% ({2}/{3} iterations) : {4:02}h {5:02}m {6:05.2f}s".\
                         format('#'*(20),
                                100,args.attempts,args.attempts,
                                hrs,mins,secs))
        print ""

    # generate plan details and map
    best_PP.keyPrep()
    best_PP.agentKeys()
    best_PP.planMap(useGoogle=useGoogle)
    best_PP.agentLinks()

    # These make step-by-step instructional images
    if not args.skipplot:
        best_PP.animate(useGoogle=useGoogle)
        best_PP.split3instruct(useGoogle=useGoogle)

    print ""
    print ""
    print ""
    print "Found best plan after {0} iterations.".format(args.attempts)
    totalTime = best_plan.walktime + best_plan.linktime + best_plan.commtime
    print "Total time: {0} minutes".format(int(totalTime / 60. + 0.5))
    print "Number of portals: {0}".format(best_PP.num_portals)
    print "Number of links: {0}".format(best_PP.num_links)
    print "Number of fields: {0}".format(best_PP.num_fields)
    portal_ap = (125 * 8 + 500 + 250) * best_PP.num_portals
    link_ap = 313 * best_PP.num_links
    field_ap = 1250 * best_PP.num_fields
    print "AP from portals capture: {0}".format(portal_ap)
    print "AP from link creation: {0}".format(link_ap)
    print "AP from field creation: {0}".format(field_ap)
    print "Total AP: {0}".format(portal_ap + link_ap + field_ap)

    tdiff = time.time() - start_time
    hrs = int(tdiff / 3600.)
    mins = int((tdiff - 3600. * hrs) / 60.)
    secs = tdiff - 3600. * hrs - 60. * mins
    print "Runtime: {0:02}h {1:02}m {2:05.2f}s".format(hrs, mins, secs)

    plt.close('all')
Пример #9
0
def main():
    args = docopt.docopt(__doc__)
    timestamp = datetime.datetime.now().strftime("%Y%m%d%H%M%S")

    COLOR = GREEN if args['-g'] else BLUE


    nagents = int(args['-n'])
    if nagents <= 0:
        print 'Number of agents should be positive'
        exit()


    # We will take many samples in an attempt to reduce number of keys to farm
    # This is the number of samples to take since the last improvement
    EXTRA_SAMPLES = int(args['-s'])
    if EXTRA_SAMPLES not in range(1, 101):
        print 'Number of extra samples must be between 1 and 100'
        exit()


    input_file = args['<input_file>']
    name, ext = os.path.splitext(os.path.basename(input_file))

    try:
        os.makedirs(name)
    except OSError as exception:
        if exception.errno != errno.EEXIST:
            raise

    output_directory = name + os.sep
    output_file = name + '_' + timestamp + '.pkl'

    if ext != '.pkl':
        a = nx.DiGraph()
        np = geometry.np

        locs = []

        # each line should be name,intel_link,keys
        with open(input_file) as fin:
            text, encoding = guess_bytes(fin.read())
            rows = unicodecsv.reader(text.encode('utf-8').strip().split('\n'), encoding='utf-8')
            for i, row in enumerate(rows):
                a.add_node(i)
                a.node[i]['name'] = row[0]

                url = ','.join(row[1:4]).strip()
                if not url.startswith('http'):
                    print 'Unable to parse input file. Did you forget to put quotes around a name containing a comma?'
                    exit()

                coords = urlparse.parse_qs(urlparse.urlparse(url).query)['pll'][0] # this could have been done the quick and dirty way, but I chose this way. It just felt right
                coord_parts = coords.split(',')
                lat = int(float(coord_parts[0]) * 1.e6)
                lon = int(float(coord_parts[1]) * 1.e6)
                locs.append(np.array([lat, lon], dtype=int)) # why does this have to be a numpy array?
                
                if '.' in row[-1]:
                    a.node[i]['keys'] = 0
                else:
                    a.node[i]['keys'] = int(row[-1])

        n = a.order() # number of nodes
        if n > 65:
            print 'Limit of 65 portals may be optimized at once'
            exit()

        locs = np.array(locs, dtype=float)

        # This part assumes we're working with E6 latitude-longitude data
        locs = geometry.e6LLtoRads(locs)
        xyz  = geometry.radstoxyz(locs)
        xy   = geometry.gnomonicProj(locs,xyz)

        for i in xrange(n):
            a.node[i]['geo'] = locs[i]
            a.node[i]['xyz'] = xyz [i]
            a.node[i]['xy' ] = xy  [i]

        # EXTRA_SAMPLES attempts to get graph with few missing keys
        # Try to minimuze TK + 2*MK where
        #   TK is the total number of missing keys
        #   MK is the maximum number of missing keys for any single portal
        bestgraph = None
        bestlack = np.inf
        bestTK = np.inf
        bestMK = np.inf

        allTK = []
        allMK = []
        allWeights = []

        sinceImprove = 0

        while sinceImprove < EXTRA_SAMPLES:
            b = a.copy()

            sinceImprove += 1

            if not maxfield.maxFields(b):
                print 'Randomization failure\n\tThe program may work if you try again. It is more likely to work if you remove some portals.'
                continue

            TK = 0
            MK = 0
            for j in xrange(n):
                keylack = max(b.in_degree(j)-b.node[j]['keys'],0)
                TK += keylack
                if keylack > MK:
                    MK = keylack

            weightedlack = TK+2*MK

            allTK.append(TK)
            allMK.append(MK)
            allWeights.append(weightedlack)

            if weightedlack < bestlack:
                sinceImprove = 0
                print 'IMPROVEMENT:\ttotal: {}\tmax: {}\tweighted: {}\t{} tries since improvement'.format(TK, MK, weightedlack, sinceImprove)
                bestgraph = b
                bestlack = weightedlack
                bestTK  = TK
                bestMK  = MK
            else:
                print 'this time:\ttotal: {}\tmax: {}\tweighted: {}\t{} tries since improvement'.format(TK, MK, weightedlack, sinceImprove)

            if weightedlack <= 0:
                print 'KEY PERFECTION'
                bestlack = weightedlack
                bestTK  = TK
                bestMK  = MK
                break
            # if num agent keys is zero, this code isn't true...
            # if all([ b.node[i]['keys'] <= b.out_degree(i) for i in xrange(n) ]):
            #     print 'All keys used. Improvement impossible'
            #     break

        if bestgraph == None:
            print 'EXITING RANDOMIZATION LOOP WITHOUT SOLUTION!'
            print ''
            exit()

        print 'Choosing plan requiring {} additional keys, max of {} from single portal'.format(bestTK, bestMK)

        plt.clf()
        plt.scatter(allTK,allMK,c=allWeights,marker='o')
        plt.xlim(min(allTK)-1,max(allTK)+1)
        plt.ylim(min(allMK)-1,max(allMK)+1)
        plt.xlabel('Total keys required')
        plt.ylabel('Max keys required for a single portal')
        cbar = plt.colorbar()
        cbar.set_label('Optimization Weighting (lower=better)')
        plt.savefig(output_directory+'optimization.png')

        a = bestgraph # remember: a = nx.DiGraph()

        # Attach to each edge a list of fields that it completes
        for t in a.triangulation:
            t.markEdgesWithFields()

        agentOrder.improveEdgeOrder(a)

        with open(output_directory+output_file,'w') as fout:
            pickle.dump(a, fout)
    else:
        with open(input_file,'r') as fin:
            a = pickle.load(fin)

    #    agentOrder.improveEdgeOrder(a)
    #    with open(output_directory+output_file,'w') as fout:
    #        pickle.dump(a,fout)

    PP = PlanPrinterMap.PlanPrinter(a, output_directory, nagents, COLOR)
    PP.keyPrep()
    PP.agentKeys()
    PP.planMap()
    PP.agentLinks()

    # These make step-by-step instructional images
    PP.animate()
    PP.split3instruct()

    print "Number of portals: {0}".format(PP.num_portals)
    print "Number of links: {0}".format(PP.num_links)
    print "Number of fields: {0}".format(PP.num_fields)
    portal_ap = (125*8 + 500 + 250)*PP.num_portals
    link_ap = 313 * PP.num_links
    field_ap = 1250 * PP.num_fields
    print "AP from portals capture: {0}".format(portal_ap)
    print "AP from link creation: {0}".format(link_ap)
    print "AP from field creation: {0}".format(field_ap)
    print "Total AP: {0}".format(portal_ap+link_ap+field_ap)
Пример #10
0
def main():
    args = docopt(__doc__)

    np = geometry.np

    #GREEN = 'g'
    #BLUE  = 'b'
    GREEN = '#3BF256' # Actual faction text colors in the app
    BLUE  = '#2ABBFF'
    #GREEN = (0.0 , 1.0 , 0.0 , 0.3)
    #BLUE  = (0.0 , 0.0 , 1.0 , 0.3)
    COLOR = GREEN

    if args['-b']:
        COLOR = BLUE

    output_directory = ''
    if args['<output_directory>'] != None:
        output_directory = args['<output_directory>']
        if output_directory[-1] != '/':
            output_directory += '/'

    output_file = 'lastPlan.pkl'
    if args['<output_file>'] != None:
        output_file = args['<output_file>']
        if not output_file[-3:] == 'pkl':
            print 'WARNING: output file should end in "pkl" or you cannot use it as input later'

    nagents = int(args['-n'])
    if nagents <= 0:
        print 'Numer of agents should be positive'
        exit()

    input_file = args['<input_file>']

    if input_file[-3:] != 'pkl':
        a = nx.DiGraph()

        locs = []
        #                             ------------- URL -------------
        #                      name  ;       lat      ,  lng         ;     keys
        urlpat = re.compile('^([^;]*);.*ll=([-0-9\.]+),([-0-9\.]+)\s*;?\s*(\d+)?')
        #                      name  ;     lat         ;     lng         ;     keys
        cvspat = re.compile('^([^;]*);\s*([-0-9\.]+)\s*;\s*([-0-9\.]+)\s*;?\s*(\d+)?')
        i = 0
        # each line should be id,name,lat,long,keys
        with open(input_file,'r') as fin:
            for line in fin:
                m = urlpat.match(line)
                if m == None:
                    m = cvspat.match(line)
                if m == None:
                    continue
                g = m.groups()
#                print g

                a.add_node(i)
                a.node[i]['name'] = g[0]

                locs.append( np.array([float(g[1]),float(g[2])] ))

                if g[3] == None:
                    a.node[i]['keys'] = 0
                else:
                    a.node[i]['keys'] = int(g[3])

                i += 1

        n = a.order() # number of nodes

        locs = np.array(locs,dtype=float)
#        print locs

        # This part assumes we're working with decimal latitude-longitude data
        locs = geometry.LLtoRads(locs)
        xyz  = geometry.radstoxyz(locs)
        xy   = geometry.gnomonicProj(locs,xyz)

        for i in xrange(n):
            a.node[i]['geo'] = locs[i]
            a.node[i]['xyz'] = xyz [i]
            a.node[i]['xy' ] = xy  [i]
            
        maxfield.maxFields(a)

        '''
        # EXTRA_SAMPLES attempts to get graph with few missing keys
        # Try to minimuze TK + 2*MK where
        #  TK is the total number of missing keys
        #   MK is the maximum number of missing keys for any single portal
        bestgraph = None
        bestlack = np.inf
        bestTK = np.inf
        bestMK = np.inf

        sinceImprove = 0

        while sinceImprove<EXTRA_SAMPLES:
            b = a.copy()

            sinceImprove += 1

            if not maxfield.maxFields(b):
                print 'Randomization failure\nThe program may work if you try again. It is more likely to work if you remove some protals.'
                continue

            TK = 0
            MK = 0
            for j in xrange(n):
                keylack = max(b.in_degree(j)-b.node[j]['keys'],0)
                TK += keylack
                if keylack > MK:
                    MK = keylack
            
            weightedlack = TK+2*MK

            if weightedlack < bestlack:
                sinceImprove = 0
                print 'IMPROVEMENT:\n\ttotal: %s\n\tmax:   %s\n\tweighted: %s'%\
                       (TK,MK,weightedlack)
                bestgraph = b
                bestlack  = weightedlack
                bestTK  = TK
                bestMK  = MK
            else:
                print 'this time:\n\ttotal: %s\n\tmax:   %s\n\tweighted: %s'%\
                       (TK,MK,weightedlack)

            if weightedlack == 0:
                print 'KEY PERFECTION'
                bestlack  = weightedlack
                bestTK  = TK
                bestMK  = MK
                break

#            if all([ b.node[i]['keys'] <= b.out_degree(i) for i in xrange(n) ]):
#                print 'All keys used. Improvement impossible'
#                break
#            print '%s tries since improvement'%sinceImprove

        if bestgraph == None:
            print 'EXITING RANDOMIZATION LOOP WITHOUT SOLUTION!'
            print ''
            exit()

        print 'Choosing plan requiring %s additional keys, max of %s from single portal'%(bestTK,bestMK)

        a = bestgraph
        '''

        # Attach to each edge a list of fields that it completes
        for t in a.triangulation:
            t.markEdgesWithFields()

        agentOrder.improveEdgeOrder(a)

        with open(output_directory+output_file,'w') as fout:
            pickle.dump(a,fout)
    else:
        with open(input_file,'r') as fin:
            a = pickle.load(fin)
    #    agentOrder.improveEdgeOrder(a)
    #    with open(output_directory+output_file,'w') as fout:
    #        pickle.dump(a,fout)

    PP = PlanPrinter.PlanPrinter(a,output_directory,nagents,COLOR)
    PP.keyPrep()
    PP.agentKeys()
    PP.planMap()
    PP.agentLinks()
Пример #11
0
    # EXTRA_SAMPLES attempts to get graph with few missing keys
    # Try to minimuze TK + 2*MK where
    #   TK is the total number of missing keys
    #   MK is the maximum number of missing keys for any single portal
    bestgraph = None
    bestlack = np.inf
    bestTK = np.inf
    bestMK = np.inf

    sinceImprove = 0
    
    while sinceImprove<EXTRA_SAMPLES:
        b = a.copy()

        if not maxfield.maxFields(b):
            print 'Failed maxfield (if this happens many times, this loop could be infinite. I''ll fix this sometime)'
            continue

        TK = 0
        MK = 0
        for j in xrange(n):
            keylack = max(b.in_degree(j)-b.node[j]['keys'],0)
            TK += keylack
            if keylack > MK:
                MK = keylack
        
        weightedlack = TK+2*MK

        if weightedlack < bestlack:
            sinceImprove = 0
Пример #12
0
def main():
    args = docopt(__doc__)

    # We will take many samples in an attempt to reduce number of keys to farm
    # This is the number of samples to take since the last improvement
    EXTRA_SAMPLES = 50

    np = geometry.np

    #GREEN = 'g'
    #BLUE  = 'b'
    GREEN = '#3BF256' # Actual faction text colors in the app
    BLUE  = '#2ABBFF'
    #GREEN = (0.0 , 1.0 , 0.0 , 0.3)
    #BLUE  = (0.0 , 0.0 , 1.0 , 0.3)
    COLOR = GREEN

    if args['-b']:
        COLOR = BLUE

    output_directory = ''
    if args['<output_directory>'] != None:
        output_directory = args['<output_directory>']
        if output_directory[-1] != '/':
            output_directory += '/'

    output_file = 'lastPlan.pkl'
    if args['<output_file>'] != None:
        output_file = args['<output_file>']
        if not output_file[-3:] == 'pkl':
            print 'WARNING: output file should end in "pkl" or you cannot use it as input later'

    nagents = int(args['-n'])
    if nagents < 0:
        print 'Number of agents should be positive'
        exit()

    EXTRA_SAMPLES = int(args['-s'])
    if EXTRA_SAMPLES < 0:
        print 'Number of extra samples should be positive'
        exit()
    elif EXTRA_SAMPLES > 100:
        print 'Extra samples may not be more than 100'
        exit()

    input_file = args['<input_file>']

    if input_file[-3:] != 'pkl':
        a = nx.DiGraph()

        locs = []

        i = 0
        # each line should be name,intel_link,keys
        with open(input_file,'r') as fin:
            for line in fin:
                parts = line.split(';')

                if len(parts) < 2:
                    break

                a.add_node(i)
                a.node[i]['name'] = parts[0].strip()

                coords = (parts[1].split('pll='))[1]
                coord_parts = coords.split(',')
                lat = int(float(coord_parts[0]) * 1.e6)
                lon = int(float(coord_parts[1]) * 1.e6)
                locs.append( np.array([lat,lon],dtype=int) )

                if len(parts) < 3:
                    a.node[i]['keys'] = 0
                else:
                    a.node[i]['keys'] = int(parts[3])

                i += 1

        if i > 65:
            print 'Limit of 65 portals may be optimized at once'
            exit()
        
        n = a.order() # number of nodes

        locs = np.array(locs,dtype=float)

        # This part assumes we're working with E6 latitude-longitude data
        locs = geometry.e6LLtoRads(locs)
        xyz  = geometry.radstoxyz(locs)
        xy   = geometry.gnomonicProj(locs,xyz)

        for i in xrange(n):
            a.node[i]['geo'] = locs[i]
            a.node[i]['xyz'] = xyz [i]
            a.node[i]['xy' ] = xy  [i]

        # EXTRA_SAMPLES attempts to get graph with few missing keys
        # Try to minimuze TK + 2*MK where
        #   TK is the total number of missing keys
        #   MK is the maximum number of missing keys for any single portal
        bestgraph = None
        bestlack = np.inf
        bestTK = np.inf
        bestMK = np.inf

        allTK = []
        allMK = []
        allWeights = []

        sinceImprove = 0

        while sinceImprove<EXTRA_SAMPLES:
            b = a.copy()

            sinceImprove += 1

            if not maxfield.maxFields(b):
                print 'Randomization failure\nThe program may work if you try again. It is more likely to work if you remove some protals.'
                continue

            TK = 0
            MK = 0
            for j in xrange(n):
                keylack = max(b.in_degree(j)-b.node[j]['keys'],0)
                TK += keylack
                if keylack > MK:
                    MK = keylack
            
            weightedlack = TK+2*MK

            allTK.append(TK)
            allMK.append(MK)
            allWeights.append(weightedlack)

            if weightedlack < bestlack:
                sinceImprove = 0
                print 'IMPROVEMENT:\n\ttotal: %s\n\tmax:   %s\n\tweighted: %s'%\
                       (TK,MK,weightedlack)
                bestgraph = b
                bestlack  = weightedlack
                bestTK  = TK
                bestMK  = MK
            else:
                print 'this time:\n\ttotal: %s\n\tmax:   %s\n\tweighted: %s'%\
                       (TK,MK,weightedlack)

            if weightedlack <= 0:
                print 'KEY PERFECTION'
                bestlack  = weightedlack
                bestTK  = TK
                bestMK  = MK
                break
            # if num agent keys is zero, this code isn't true...
            # if all([ b.node[i]['keys'] <= b.out_degree(i) for i in xrange(n) ]):
            #     print 'All keys used. Improvement impossible'
            #     break

            print '%s tries since improvement'%sinceImprove

        if bestgraph == None:
            print 'EXITING RANDOMIZATION LOOP WITHOUT SOLUTION!'
            print ''
            exit()

        print 'Choosing plan requiring %s additional keys, max of %s from single portal'%(bestTK,bestMK)

        plt.clf()
        plt.scatter(allTK,allMK,c=allWeights,marker='o')
        plt.xlim(min(allTK)-1,max(allTK)+1)
        plt.ylim(min(allMK)-1,max(allMK)+1)
        plt.xlabel('Total keys required')
        plt.ylabel('Max keys required for a single portal')
        cbar = plt.colorbar()
        cbar.set_label('Optimization Weighting (lower=better)')
        plt.savefig(output_directory+'optimization.png')

        a = bestgraph

        # Attach to each edge a list of fields that it completes
        for t in a.triangulation:
            t.markEdgesWithFields()

        agentOrder.improveEdgeOrder(a)

        with open(output_directory+output_file,'w') as fout:
            pickle.dump(a,fout)
    else:
        with open(input_file,'r') as fin:
            a = pickle.load(fin)
    #    agentOrder.improveEdgeOrder(a)
    #    with open(output_directory+output_file,'w') as fout:
    #        pickle.dump(a,fout)

    PP = PlanPrinterMap.PlanPrinter(a,output_directory,nagents,COLOR)
    PP.keyPrep()
    PP.agentKeys()
    PP.planMap()
    PP.agentLinks()

    # These make step-by-step instructional images
    PP.animate()
    PP.split3instruct()

    print "Number of portals: {0}".format(PP.num_portals)
    print "Number of links: {0}".format(PP.num_links)
    print "Number of fields: {0}".format(PP.num_fields)
    portal_ap = (125*8 + 500 + 250)*PP.num_portals
    link_ap = 313 * PP.num_links
    field_ap = 1250 * PP.num_fields
    print "AP from portals capture: {0}".format(portal_ap)
    print "AP from link creation: {0}".format(link_ap)
    print "AP from field creation: {0}".format(field_ap)
    print "Total AP: {0}".format(portal_ap+link_ap+field_ap)