diff --git a/README.maxfield.md b/README.maxfield.md
new file mode 100644
index 0000000..a516b12
--- /dev/null
+++ b/README.maxfield.md
@@ -0,0 +1,140 @@
+# Introduction
+
+This code is designed to make a plan for linking a given set of portals in the
+way (and the order) that creates the most fields. This is harder than it sounds.
+If you're working on more than a dozen portals, learning to use this code may
+be faster than planning by hand.
+
+This code follows the procedure in my [YouTube video][0].
+
+# Prerequisites
+
+You'll need [Python][2] (I've got 2.7) as well as networkx, numpy, and matplotlib.
+
+You can get these setup easily with the [Enthought Python Distribution][1].
+
+You can use [pip][3] to install the dependencies via:
+
+ pip install -r requirements.txt
+
+# Example
+
+I'll be distributing this code with a file EXAMPLE.csv. Try running
+
+ python maxfield.py -n 4 EXAMPLE.csv output/ output.pkl
+
+This will put a bunch of files into the "output/" directory (see OUTPUT FILE LIST)
+
+Now try running
+
+ python maxfield.py -n 3 output/output.pkl
+
+This uses the plan stored in output.pkl instead of calculating a new one. It will create files for 3 agents instead of 4.
+
+### OUTPUT FILE LIST
+
+ keyPrep.txt
+ List of portals, their numbers on the map, and how many keys are needed
+
+ keys_for_agent_M_of_N.txt
+ List of keys agent number M will need (if N agents are participating)
+
+ links_for_agent_M_of_N.txt
+ List of ALL the links
+ Total distance traveled and AP earned by agent number M
+ * Except for the links marked with a star (*), the links should be made IN THE ORDER LISTED
+ * Links with a star can be made out of order, but only EARLY i.e. BEFORE their position in the list (this can save you time)
+ * The links that agent number M makes are marked with underscores__
+ * The first portal listed is the origin portal (where the agent must be)
+ * The second portal listed is the destination portal (for which the agent must have a key)
+
+ portalMap.png
+ A map showing the locations of the portals
+ linkMap.png
+ A map showing the locations of portals and links
+ * Up is north
+ * Portal numbers increase from north to south
+ * Portal numbers match "keyPrep.txt" and "linkes_for_agent_M_of_N.txt"
+ * Link numbers match those in the link schedules "links_for_agent_M_of_N.txt"
+
+ ownershipPrep.txt
+ List of portals whose first link is incoming
+ * These portals need to be captured and fully powered before the linking operation
+ List of portals whose first link is outgoing
+ * You may be able to save time by capturing and fully powering these portals DURING the linking operation
+
+ lastPlan.pkl
+ A Python pickle file containing all portal and plan information
+ * The default name is "lastPlan.pkl"
+ * In the examples above, this is called "output.pkl"
+
+# Usage
+
+ python maxfield.py [-b] [-n agent_count] input_file [output_directory] [output_file]
+
+ -b: Include this option if you like your maps blue instead of green for any reason
+
+ agent_count: Number of agents for which to make a plan
+
+ input_file: One of two types of files:
+ .csv
+ a semicolon-delimited file
+ the actual file extension does not matter as long as it is not ".pkl"
+
+ two acceptable formats:
+
+ portal name ; lat ; lng [;keys]
+ OR
+ portal name ; Intel URL [;keys]
+
+ To get the Intel URL:
+ * Click on the portal at ingress.com/intel
+ * Click on "Link" near the top right of the screen
+ * Copy and paste the URL from the box that appears
+ Example of an Intel URL:
+ https://www.ingress.com/intel?ll=29.719016,-95.397893&z=19&pll=29.719011,-95.397881
+
+ portal name should not contain a semicolon
+ lat and lng should be the portal's global coordinates
+ e.g. the Big Ben portal is at 51.500775,-0.124466
+ keys (optional parameter) is the number of keys you have for the portal
+ If you leave this blank, the program assumes you have no keys
+
+ .pkl an output from a previous run of this program
+ this can be used to make the same plan with a different number of agents
+
+ output_directory: directory in which to put all output
+ default is the working directory
+
+ output_file: name for a .pkl file containing information on the plan
+ if you later use this for the input file, the same plan will be
+ produced with the number of agents you specify (default: "lastPlan.pkl")
+
+# Warranty and Copyright
+
+Copyright (C) 2015 by Jonathan Baker: babamots@gmail.com
+
+Maxfield is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+Maxfield is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Maxfield in a file called COPYING.txt. If not, see
+.
+
+# Notes
+
+The space of possible field-maximizing plans is large. Rather than trying every
+possibility, Maxfield randomly tries some plans and presents you with one.
+
+[0]: https://www.youtube.com/watch?v=priezq6Dm4Y
+[1]: https://www.enthought.com/downloads/
+[2]: https://www.python.org/download/releases/2.7
+[3]: https://pypi.python.org/pypi/pip
+
diff --git a/README.md b/README.md
index a516b12..7b33e2c 100644
--- a/README.md
+++ b/README.md
@@ -1,140 +1,56 @@
-# Introduction
+# Maxfield and others
-This code is designed to make a plan for linking a given set of portals in the
-way (and the order) that creates the most fields. This is harder than it sounds.
-If you're working on more than a dozen portals, learning to use this code may
-be faster than planning by hand.
+## Introduction
-This code follows the procedure in my [YouTube video][0].
+**Forks from [maxfield](https://github.com/jpeterbaker/maxfield), Thank you**
-# Prerequisites
+I'm using Ingress Planner + InGraph.
+but it seems that maxfield is better than Ingraph, and the most important is
+that it's built by python.
-You'll need [Python][2] (I've got 2.7) as well as networkx, numpy, and matplotlib.
+Added some feature **(only valid for single agent)** to the original maxfield.
-You can get these setup easily with the [Enthought Python Distribution][1].
+## Prerequisites (from maxfield)
-You can use [pip][3] to install the dependencies via:
+You'll need [Python] (I've got 2.7) as well as networkx, numpy, and matplotlib.
- pip install -r requirements.txt
+You can use [pip] to install the dependencies via:
-# Example
+ `pip install -r requirements.txt`
-I'll be distributing this code with a file EXAMPLE.csv. Try running
+## Features
- python maxfield.py -n 4 EXAMPLE.csv output/ output.pkl
+### Support for '.gph' files
-This will put a bunch of files into the "output/" directory (see OUTPUT FILE LIST)
+You can get '.gph' files from [ingressplanner](www.ingressplanner.net). And use
+it as a common '.csv' file.
-Now try running
+After the plan is generated, in the output dir, you can find a file named
+'result.gph', it can be imported into ingressplanner.
- python maxfield.py -n 3 output/output.pkl
+### Support for [ingress-maxfield](http://www.ingress-maxfield.com/)
-This uses the plan stored in output.pkl instead of calculating a new one. It will create files for 3 agents instead of 4.
+We will also generate a file named 'max.csv' for the site mentioned above.
-### OUTPUT FILE LIST
+## Inplan.py
- keyPrep.txt
- List of portals, their numbers on the map, and how many keys are needed
+Usage: `python inplan.py [input_file] [output_path] [plan_count]`
- keys_for_agent_M_of_N.txt
- List of keys agent number M will need (if N agents are participating)
+Input file and output path is the same as `maxfield.py`.
- links_for_agent_M_of_N.txt
- List of ALL the links
- Total distance traveled and AP earned by agent number M
- * Except for the links marked with a star (*), the links should be made IN THE ORDER LISTED
- * Links with a star can be made out of order, but only EARLY i.e. BEFORE their position in the list (this can save you time)
- * The links that agent number M makes are marked with underscores__
- * The first portal listed is the origin portal (where the agent must be)
- * The second portal listed is the destination portal (for which the agent must have a key)
+`plan_count` here to tell maxfield that how many plans to create.
- portalMap.png
- A map showing the locations of the portals
- linkMap.png
- A map showing the locations of portals and links
- * Up is north
- * Portal numbers increase from north to south
- * Portal numbers match "keyPrep.txt" and "linkes_for_agent_M_of_N.txt"
- * Link numbers match those in the link schedules "links_for_agent_M_of_N.txt"
+After all plans had been created. you can find many plans folder in `output_path`.
- ownershipPrep.txt
- List of portals whose first link is incoming
- * These portals need to be captured and fully powered before the linking operation
- List of portals whose first link is outgoing
- * You may be able to save time by capturing and fully powering these portals DURING the linking operation
+And two files.
- lastPlan.pkl
- A Python pickle file containing all portal and plan information
- * The default name is "lastPlan.pkl"
- * In the examples above, this is called "output.pkl"
+### key.csv
-# Usage
+Every line is a record of a plan.
+Each cell will show you keys needed of a portal in this plan.
+stddev? you know it.
- python maxfield.py [-b] [-n agent_count] input_file [output_directory] [output_file]
- -b: Include this option if you like your maps blue instead of green for any reason
-
- agent_count: Number of agents for which to make a plan
-
- input_file: One of two types of files:
- .csv
- a semicolon-delimited file
- the actual file extension does not matter as long as it is not ".pkl"
-
- two acceptable formats:
-
- portal name ; lat ; lng [;keys]
- OR
- portal name ; Intel URL [;keys]
-
- To get the Intel URL:
- * Click on the portal at ingress.com/intel
- * Click on "Link" near the top right of the screen
- * Copy and paste the URL from the box that appears
- Example of an Intel URL:
- https://www.ingress.com/intel?ll=29.719016,-95.397893&z=19&pll=29.719011,-95.397881
-
- portal name should not contain a semicolon
- lat and lng should be the portal's global coordinates
- e.g. the Big Ben portal is at 51.500775,-0.124466
- keys (optional parameter) is the number of keys you have for the portal
- If you leave this blank, the program assumes you have no keys
-
- .pkl an output from a previous run of this program
- this can be used to make the same plan with a different number of agents
-
- output_directory: directory in which to put all output
- default is the working directory
-
- output_file: name for a .pkl file containing information on the plan
- if you later use this for the input file, the same plan will be
- produced with the number of agents you specify (default: "lastPlan.pkl")
-
-# Warranty and Copyright
-
-Copyright (C) 2015 by Jonathan Baker: babamots@gmail.com
-
-Maxfield is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-Maxfield is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with Maxfield in a file called COPYING.txt. If not, see
-.
-
-# Notes
-
-The space of possible field-maximizing plans is large. Rather than trying every
-possibility, Maxfield randomly tries some plans and presents you with one.
-
-[0]: https://www.youtube.com/watch?v=priezq6Dm4Y
-[1]: https://www.enthought.com/downloads/
-[2]: https://www.python.org/download/releases/2.7
-[3]: https://pypi.python.org/pypi/pip
+### summary.csv
+Here you can find walking distance and move count of each plan.
diff --git a/inplan.py b/inplan.py
new file mode 100755
index 0000000..a98b139
--- /dev/null
+++ b/inplan.py
@@ -0,0 +1,120 @@
+#! /usr/bin/env python
+import subprocess
+import re
+import sys
+import os
+import multiprocessing
+import numpy
+
+
+def worker(plan_number):
+ output_dir = os.path.join(output_path, "plan" + str(plan_number))
+ os.makedirs(output_dir)
+ cmd = ["maxfield", input_file, output_dir]
+ subprocess.check_output(cmd)
+ print "Plan {} finished.".format(plan_number)
+
+def summarize(plan_count):
+ print "Making the summarized table."
+ summarized_content = ["{},{},{},{},{}".format("Plan", "Links",
+ "Fields", "Distance", "Changed")]
+ keys_content = []
+ for i in range(0, plan_count):
+ plan_path = os.path.join(output_path, "plan" + str(i))
+ data_file = open(
+ os.path.join(plan_path,"links_for_agent_1_of_1.txt"),
+ "r")
+ r_distance = re.compile("Total Distance:\s+(\d+)\s+meter")
+ r_links = re.compile("Links made:\s+(\d+)")
+ r_fields = re.compile("Fields completed:\s+(\d+)")
+ r_link_desc = re.compile("^(.*?)\s?->\s?(.*?)$")
+ # 2 | 2 | N1
+ r_key = re.compile("\s+(\d+)\s+\|\s+(\d+)\s+\|\s+(.*?)$")
+ for line in data_file:
+ m_distance = r_distance.match(line)
+ m_links = r_links.match(line)
+ m_fields = r_fields.match(line)
+ if m_distance:
+ distance = m_distance.groups()[0]
+ if m_links:
+ links = m_links.groups()[0]
+ if m_fields:
+ fields = m_fields.groups()[0]
+ data_file.close()
+ # How many times do we change the "Start" Portal?
+ data_file = open(
+ os.path.join(plan_path,"result.gph"),
+ "r")
+ changed_count = 0
+ current_start = ""
+ for line in data_file:
+ if r_link_desc.match(line):
+ g = r_link_desc.match(line).groups()
+ if g[0] != current_start:
+ current_start = g[0]
+ changed_count = changed_count + 1
+ data_file.close()
+
+ # keys
+ data_file = open(
+ os.path.join(plan_path,"keyPrep.txt"),
+ "r")
+ key_total = 0;
+ key_plan = {}
+ for lines in data_file:
+ m_keys = r_key.match(lines)
+ if m_keys == None:
+ continue
+ g_keys = m_keys.groups()
+ key_name = g_keys[2]
+ key_count = g_keys[0]
+ key_plan[key_name] = key_count
+ data_file.close()
+ if (len(keys_content) == 0):
+ first_line = ""
+ for key_name in sorted(key_plan.keys()):
+ first_line = first_line + key_name + ","
+ first_line = first_line + "stddev"
+ keys_content.append("plan," + first_line)
+ key_line = str(i) + ","
+ key_list = []
+ for key_name in sorted(key_plan.keys()):
+ key_line = key_line + str(key_plan[key_name]) + ","
+ key_list.append(int(key_plan[key_name]))
+ stddev = numpy.std(key_list)
+ keys_content.append(key_line + str(stddev))
+
+ summary_line = "{},{},{},{},{}".format(i,
+ links, fields, distance, changed_count)
+ summarized_content.append(summary_line)
+
+ summary_file = open(os.path.join(output_path, "summary.csv"), "w")
+ summary_file.write("\n".join(summarized_content))
+ summary_file.close()
+ key_file = open(os.path.join(output_path, "key.csv"), "w")
+ key_file.write("\n".join(keys_content))
+ key_file.close();
+
+
+
+def main(plan_count):
+ # for i in range(0, int(plan_count)):
+ # output_dir = os.path.join(output_path, "plan" + str(i))
+ # print output_dir
+ # os.makedirs(output_dir)
+ # cmd = ["maxfield", input_file, output_dir]
+ # subprocess.check_output(cmd)
+ # return 0
+ count = multiprocessing.cpu_count()
+ pool = multiprocessing.Pool(processes=count)
+ pool.map(worker, range(0, int(plan_count)))
+ if (input_file[-3:] == "gph"):
+ summarize(int(plan_count))
+
+if __name__ == "__main__":
+ if len(sys.argv) != 4:
+ print "Usage: {} [input_file] [output_path] [plan_count]".format(sys.argv[0])
+ else:
+ input_file = sys.argv[1]
+ output_path = sys.argv[2]
+ main(sys.argv[3])
diff --git a/lib/PlanPrinter.py b/lib/PlanPrinter.py
index 9a1df32..6e4f5e8 100644
--- a/lib/PlanPrinter.py
+++ b/lib/PlanPrinter.py
@@ -31,7 +31,7 @@
import networkx as nx
import electricSpring
import time
-
+import re
# returns the points in a shrunken toward their centroid
def shrink(a):
centroid = a.mean(1).reshape([2,1])
@@ -141,11 +141,11 @@ def agentKeys(self):
fout.write('Map# Keys Name\n')
for portal in self.nameOrder:
-
+
keys = self.agentkeyneeds[agent,portal]
if self.agentkeyneeds[agent,portal] == 0:
keys = ''
-
+
fout.write(rowFormat%(\
self.nslabel[portal],\
keys,\
@@ -249,7 +249,7 @@ def planMap(self):
va = 'bottom'
else:
va = 'top'
-
+
plt.text(self.xy[i,0],self.xy[i,1],str(j),ha=ha,va=va)
@@ -278,7 +278,6 @@ def planMap(self):
# plt.clf()
def agentLinks(self):
-
# Total distance traveled by each agent
agentdists = np.zeros(self.nagents)
# Total number of links, fields for each agent
@@ -309,7 +308,7 @@ def agentLinks(self):
# plainStr = '{0:4d}{1:1s} {2: 5d}{3:5d} {4:s}\n {5:4d} {6:s}\n\n'
plainStr = '{0:4d}{1:1s} {2: 5d}{3:5d} {4:s} -> {5:d} {6:s}\n'
hilitStr = '{0:4d}{1:1s} {2:_>5d}{3:5d} {4:s}\n {5:4d} {6:s}\n\n'
-
+
totalTime = self.a.walktime+self.a.linktime+self.a.commtime
for agent in range(self.nagents):
@@ -319,7 +318,7 @@ def agentLinks(self):
fout.write('Complete link schedule issued to agent %s of %s %s\n\n'\
%(agent+1,self.nagents,time.strftime('%Y-%m-%d %H:%M:%S %Z')))
fout.write('\nLinks marked with * can be made EARLY\n')
-
+
fout.write('----------- PLAN DATA ------------\n')
fout.write('Minutes: %s minutes\n'%int(totalTime/60+.5))
fout.write('Total Distance: %s meter\n'%int(totalDist))
@@ -341,11 +340,11 @@ def agentLinks(self):
fout.write(' Link Destination\n')
fout.write('----------------------------------\n')
# 1234112345612345 name
-
+
last_link_from_other_agent = 0
for i in xrange(self.m):
p,q = self.orderedEdges[i]
-
+
linkagent = self.link2agent[i]
# Put a star by links that can be completed early since they complete no fields
@@ -374,6 +373,7 @@ def agentLinks(self):
if last_link_from_other_agent:
fout.write('\n')
last_link_from_other_agent = 0
+
fout.write(hilitStr.format(\
i,\
star,\
@@ -396,7 +396,7 @@ def animate(self):
INVISIBLE = ( 0.0 , 0.0 , 0.0 , 0.0 )
portals = np.array([self.a.node[i]['xy'] for i in self.a.nodes_iter()]).T
-
+
# Plot all edges lightly
def dashAllEdges():
for p,q in self.a.edges_iter():
@@ -441,7 +441,7 @@ def dashAllEdges():
# newPatches.append(Polygon(shrink(coords.T).T,facecolor=GREEN,\
# edgecolor=INVISIBLE))
# print '%s new patches'%len(newPatches)
-
+
aptotal += 313+1250*len(newPatches)
newEdge = np.array([self.a.node[p]['xy'],self.a.node[q]['xy']]).T
@@ -455,7 +455,7 @@ def dashAllEdges():
# newEdge[0,1]-newEdge[0,0],\
# newEdge[1,1]-newEdge[1,0],\
# fc="k", ec="k")#,head_width=0.0005,head_length=0.001 )
-
+
plt.plot(newEdge[0],newEdge[1],'k-',lw=2)
# plt.plot(newEdge[0],newEdge[1],'g-')
@@ -488,7 +488,7 @@ def dashAllEdges():
def split3instruct(self):
portals = np.array([self.a.node[i]['xy'] for i in self.a.nodes_iter()]).T
-
+
gen1 = self.a.triangulation
oldedges = []
@@ -512,7 +512,7 @@ def split3instruct(self):
if len(newedges) == 0:
break
-
+
plt.plot(portals[0],portals[1],'go')
for edge in oldedges:
@@ -520,7 +520,7 @@ def split3instruct(self):
for edge in newedges:
plt.plot(edge[0],edge[1],'r-')
-
+
oldedges += newedges
plt.axis('off')
@@ -538,3 +538,42 @@ def split3instruct(self):
plt.savefig(self.outputDir+'depth_%s.png'%depth)
plt.clf()
+ def gph(self, gphFile):
+ input_file = open(gphFile, "r")
+ new_content = ["digraph PortalLinks {"]
+ max_input = []
+ for line in input_file:
+ # N1[label="23.1197,113.175007", pos="(16.659203,0.0)"]
+ gphpat = re.compile('^(.*?)\[label="(.*?),(.*?)",\s+pos="\((.*?),(.*?)\)"')
+ m = gphpat.match(line)
+ if m == None:
+ continue
+ g = m.groups()
+ name = g[0]
+ label1 = g[1]
+ label2 = g[2]
+ pos1 = round(float(g[3]), 5)
+ pos2 = round(float(g[4]), 5)
+
+ new_content.append(
+ '{}[label="{},{}", pos="({},{})"]'.format(
+ name, label1, label2, pos1, pos2
+ ))
+ max_input.append(
+ "{};https://ingress.com/intel?ll={},{}&&z=17&&pll={},{};".format(name,
+ label1, label2, label1, label2))
+ input_file.close()
+
+ for i in range(0, self.m):
+ (poFrom, poTo) = self.orderedEdges[i]
+ new_content.append(
+ "{} -> {}".format(self.names[poFrom], self.names[poTo]))
+ new_content.append("}\r\n")
+ result = "\r\n".join(new_content)
+ output_file = open(self.outputDir + "result.gph", "w")
+ output_file.write(result)
+ output_file.close()
+
+ max_file = open(self.outputDir + "max.csv", "w")
+ max_file.write("\n".join(max_input))
+ max_file.close
diff --git a/maxfield.py b/maxfield.py
old mode 100644
new mode 100755
index 065330f..41dafc5
--- a/maxfield.py
+++ b/maxfield.py
@@ -45,7 +45,7 @@
input_file:
One of two types of files:
- .csv formatted as
-
+
portal name ; lat ; lng [; keys]
OR
portal name ; Intel map URL [;keys]
@@ -93,6 +93,9 @@ def main():
output_directory = args['']
if output_directory[-1] != '/':
output_directory += '/'
+ else:
+ output_directory = "output/"
+
output_file = 'lastPlan.pkl'
if not args[''] is None:
@@ -116,6 +119,10 @@ def main():
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+)?')
+ # gph file input: name[label="lat,lng", pos="(0,164.84227554585027)"]
+ gphpat = re.compile('^(.*?)\[label="(.*?),(.*?)",.*?(\d+)?')
+
+
i = 0
# each line should be id,name,lat,long,keys
with open(input_file,'r') as fin:
@@ -123,10 +130,11 @@ def main():
m = urlpat.match(line)
if m is None:
m = cvspat.match(line)
+ if m is None:
+ m = gphpat.match(line)
if m is None:
continue
g = m.groups()
-# print g
a.add_node(i)
a.node[i]['name'] = g[0]
@@ -154,7 +162,7 @@ def main():
a.node[i]['geo'] = locs[i]
a.node[i]['xyz'] = xyz [i]
a.node[i]['xy' ] = xy [i]
-
+
makeFields.maxFields(a)
'''
@@ -185,7 +193,7 @@ def main():
TK += keylack
if keylack > MK:
MK = keylack
-
+
weightedlack = TK+2*MK
if weightedlack < bestlack:
@@ -242,6 +250,9 @@ def main():
PP.agentKeys()
PP.planMap()
PP.agentLinks()
+ print input_file[-3:] == "gph"
+ if (input_file[-3:] == "gph"):
+ PP.gph(input_file)
# These make step-by-step instructional images
#PP.animate()
@@ -249,4 +260,3 @@ def main():
if __name__ == "__main__":
sys.exit(main())
-