In this lab, we will implement a generic version of the Queue data type within the context of searching a maze.
In Lab 4, we explored searching a maze for a goal using a stack to organize our potential Trails. The stack allowed us to search in a depth-first search manner. In other words, we would explore down a trail as far as possible, and backtracked if we reached a dead end in our journey, because we were search the youngest potential trail next.
But there are other ways to search. We now want to investigate a breadth-first search approach, where the oldest potential trail is expanded next.
In this lab, you will create the necessary data structures to search a maze with breadth-first search.
To implement the generic version of a Queue with nodes, you should use the generic ListNode<E> class we implemented last lab.
ListNode<E>
maze.searchers
Write a class called ListQueue<E>. This will need to implement the Queue<E> interface, and have at least a ListNode<E> called front and another called back as fields.
ListQueue<E>
Queue<E>
front
back
public void add(E item)
Create a new ListNode<E> that stores the item.
item
If the queue isEmpty, then set front to this new ListNode<E>.
isEmpty
Otherwise, the current back should refer to this new ListNode<E> as its next.
next
Finally, redirect back to reference this new ListNode<E>.
public E remove()
Call the emptyCheck method. This will throw an IllegalStateException if the queue is empty.
emptyCheck
IllegalStateException
Save the value stored in front, and redirect front to point to the next ListNode<E>.
Return the value you stored.
public E element()
Return the value stored in the front ListNode<E>.
public int size()
If front is null, return 0.
null
Otherwise, return the number of ListNode<E> that are chained from the front node.
Run the ListQueueTest suite, and ensure your above methods are passing these tests.
ListQueueTest
Run the GUI to interact with your code.
Write a class called ArrayQueue<E>. This will need to implement the Queue<E> interface. The E[] stuff field is provided for you, you will need to add the necessary ints to track the data. I recommend starting with front and size both equal to 0.
ArrayQueue<E>
E[] stuff
int
size
If there is no more room in the stuff array, you will need to resize.
stuff
Now, you can always add the new item to the back spot in the stuff array, and increment the size.
Save the value in the front index of the array.
Increment the value of front.
Decrement the value of size.
Return the item you stored.
Return the item in the front spot of the stuff array.
Return the size field.
Run the ArrayQueueTest suite, and ensure your above methods are passing these tests.
ArrayQueueTest
A Trail is another recursive data structure, similar to a ListNode. The two fields of a Trail are a Position, denoting the end of the trail, and a link to another Trail called prev, which is a record of how you arrived at the current Trail. For the first step of a Trail, the prev is left as null.
Trail
ListNode
Position
end
prev
In this step, you will use Trails to write an algorithm in the Puzzle class that solves a maze using either a Stack or a Queue. This is because the behavior of both is abstracted into a Searcher class. The Searcher class has method names like the Queue.
Trails
Puzzle
Searcher
Queue
public Trail solve(Searcher<Trail> solver)
If there is no Explorer in the maze or no goal in the maze, then return null.
Explorer
Otherwise, add a new Trail starting at the Explorer’s position onto the solver.
solver
While the solver still has potential Trails:
Cell
Maze
OPEN
VISITED
If you empty the solver and have still not found the goal, then return null.
Run the PuzzleTest suite, and ensure your above methods are passing these tests.
PuzzleTest
Create 10 mazes of size 30x30 and for each maze, record the number of visited nodes as a percentage of the total number of open spaces in the initial maze.
Use this data to compare the Stack (from your previous lab) versus Queue search strategies. Does either strategy have any clear strengths or weaknesses?