COMP 372: Project 1 --- Navigating Memphis
In this project, you will use the A* algorithm to find the fastest route between two locations
in Memphis.
Your program should ask the user for three inputs: the name of a map file (in
the same format as used in Project 0), then the IDs for two different locations
on that map. Your program should use the A* algorithm to find the quickest driving route
in terms of time between the two locations. Your program should print the following
pieces of information in the format specified in the examples below.
- The total number of A* nodes expanded (the size of the final explored list).
- The total time the route takes to drive, in minutes.
- The route itself, consisting of location IDs and the road segment names.
Your algorithm should use the speed limit for each road to determine the time it takes
to travel that particular road segment. You may assume speed changes are instantaneous,
and you don't have to take traffic or stop lights (or other things which one would slow
down for) into account.
You will notice that in order to calculate the travel time for a road segment, you will
need the length of the road in miles as well as the speed limit. To do this from
latitude and longitude coordinates, you should use this
code that calculates great-circle
distances on a sphere. (No, the earth is not perfectly spherical, but it's an OK
approximation.) Remember to multiply the return value by 3960 to get
the distance in miles! You can then use the distance in miles combined with the
speed limit of the road in miles per hour, to compute the travel time in minutes.
For g(n), use the travel time in minutes from the start state to the node n. For the
heuristic value h(n), use the straight-line travel time from n to the goal state, assuming
you could drive from node n to the goal at 65 miles per hour. We can use 65mph because
that's the maximum speed limit of any Memphis road, so this h(n) will never overestimate
the true travel time.
Implementing A*
Use the A* pseudocode in the book or from the handouts in class. While you may find online
sources helpful in understanding the algorithm, you may encounter slight variations
in different people's versions
of the algorithm that will make it difficult for me to test your code and help you debug
it if necessary.
Testing
For testing purposes (both for you and me), you must put a global constant
at the top of your main program called DEBUG. If this set to true, then your program
should, during the main A* loop, print three kinds of information as necessary:
- For each iteration of the main A* loop, print the current node location ID when you pop it off the frontier along with its f/g/h costs.
- Every time a new node is added to the frontier (this happens when the current node is being expanded), print
the new node's location ID, along with its f/g/h costs.
- Every time a node is updated on the frontier (also happens during the node expansion phase),
print the updated node's location ID, along with the old and new f/g/h costs.
You should use this debugging output to make sure you are examining nodes
in the same order that my solution is. You can set this to false when you get your
program working so it doesn't clutter up your output, and I will use it when I check your
output against mine when grading your solution. (It is possible there may be slight variations
here due to Python/C++ implementations of floating-point numbers. Use doubles in C++.)
Location IDs
To test your program, I have collected the IDs for some Memphis landmarks, commonly-visited places,
and some intersections near Rhodes.
Example runs
These examples use the all-memphis.txt map. Assuming the debugging flag is turned off,
the first three all run in less than one second on my computer, and the last one takes less than five seconds.
What to turn in
Through Moodle, turn in your code. Make sure there is a DEBUG global constant that I can easily find.
Grading
You will be graded on correctness of your program (whether it gives the best path or tour),
and whether the sequence of nodes expanded matches mine --- this guarantees you implemented A*
correctly.
Fun ideas
- Compare some of the routes your program finds against Google Maps or another mapping
service. Why are they different sometimes?