Posted 24 October 2011 (corrected later that day),
due at 11:59 p.m. EDT on Wednesday
2 November 2011, by placing .java files **and .class files** in your cs187 directory on
your edlab account. Please place files for this assignment in a
subdirectory
of cs187 called "project5".

As we get questions on this assignment we will put answers on the Q&A page.

Some useful code is available in this directory on the course web site. We will make a sample driver available within a few days.

Goals of this project:

- Use a priority queue, implemented with an ordered list, to find the best path in a maze.
- Reuse and adapt code from earlier maze programs to solve a new problem.

We have now implemented two different methods for finding a path from one cell to another in a maze. Project #2 used a stack for depth-first search, which tested whether there was a path and returned the path easily by reading the stack at the end. Project #4 used a queue for breadth-first search, finding the path with the least number of hops, and using parent pointers assigned during the search to return the path at the end. In this project, adapted from Problem J in the 2003 ACM Programming Contest, we are going to use an ordered list to find the best path according to a particular criterion.

Our path is to be traversed by a merchant who has a certain number of silver spoons at the source and needs to get as many of them as possible to the destination. The merchant must pay a toll on entering each (open) cell on the route. Cells are either "villages" that charge one spoon in toll, or "towns" that charge 5% of the spoons brought in, rounded up. (The three-parameter Maze constructor will need to be changed so we can say which open cells are towns and which villages -- we will do that for you.) The best route may thus depend on how many spoons he is transporting.

As in Project #4, we will keep a "queue" of cells that have been
visited by our search, but this time it will be kept as an ordered
list, ordered by the number of spoons we can bring to that cell. When
we choose a new cell to investigate, we choose the one with the
largest number of spoons we can bring. Investigating a cell means
taking all of its open unseen neighbors, seeing how many spoons we can
bring to each, and putting those cells into the ordered list, keeping
the list ordered by number of spoons. We are only interested in paths
that deliver a *positive* number of spoons.

We will want to treat the `seen`

field of our cells
differently in this search. In Project #4, once we found a path from
the source to a cell, we knew that no future path could be shorter,
and we could mark the cell as seen. But now we might discover a
*better* path later, so we should keep cells still in the queue
as "unseen". When an open unseen neighbor of the cell being
investigated turns out to be on the list, we must decide whether the
new path we have discovered is better or worse than the one we found
before, and adjust the queue accordingly.

As in Project #4, we will need parent pointers to be able to
reconstruct the best path when we are done. Note that the best path
may not be the one with the fewest number of hops -- the best path is
the one that brings the most spoons to the cell. We can use the
distance field of our cells to find the length of the *best* path
from the source -- this will save us time in setting up the array to
output as the best path.

We are giving you a class `PQCell`

that extends
`QCell`

and implements
`Comparable<PQCell>`

. It has two additional fields,
the first being
a boolean named `isTown`

that is true for a town and false
for a village. The second is an int named `spoons`

that
you will set during the search, as the number of spoons the merchant
could have there after paying the toll to enter. (A subtlety --
because the `parent`

field is inherited from
`QCell`

, its type is `QCell`

rather than
`PQCell`

. So you will need a cast operation to take a cell
out of a parent field and put it into the output array of the new
`bestPath`

method, which is an array of `PQCell`

objects.)

The Java library does not have a specific interface corresponding
to L&C's `OrderedListADT`

, so we will implement our ordered
list with a `PriorityQueue<PQCell>`

object. The
methods we will primarily need are `add`

, which we can think
of as putting a new `PQCell`

into its proper place in the
ordered list, and `poll`

, which will return and remove the
"smallest" element.

The classes for this project will be `Maze`

and
`PQCell`

. (This means that `Cell`

,
`SCell`

, and `QCell`

must also be present in the
directory for `PQCell`

to work.) The first new method of
`Maze`

should be ```
public int spoons (int startSpoons,
int sx, int sy, int dx, int dy)
```

, which returns the maximum number
of spoons that can be delivered to (dx, dy) if you start
with startSpoons at (sx, sy). The second new method is ```
public
PQCell [ ] bestPath
```

, with the same five `int`

parameters, which returns the path that delivers the maximum (positive)
number of spoons. If there is no way to deliver a positive number,
then `spoons`

should return 0 and `bestPath`

should return a 0-length array.

Note that the merchant does not pay the toll for the source node, but does pay to enter the destination, unless it is equal to the source.

Also note that neither of your two new methods should have any side
effect on the calling `Maze`

object, so you must clean up
any fields of any cells that are altered during the search.

You may borrow code from any of L&C's classes, or from our solutions, with specific attribution in a comment.

Last modified 24 October 2011