Note that the 9pm deadline is subject to the same late penalty as on the written assignments: divide the number of minutes late (past 9pm) your assignment is by 5, take the floor function, and then raise 2 to the resulting power. That number out of 64 is the fraction of points you'll lose. E.g. if you're 10 minutes late, you lose 6.25%, but if you're 25 minutes late, you lose 50%.
For this project, we revisit the Amazing Maze Solver that you worked on in Project 1. In particular, now that you've learned some new, more powerful data structures, we can go back and solve problems we couldn't solve before!
In Project 1, we focused on different implementations for the data structure that holds the "active states", i.e., the states from which we intend to continue searching for a solution. As you discovered, if you use a stack, you get depth-first search; if you use a queue, you get breadth-first search; and if you use a priority queue, you get best-first search.
The puzzle solver also needed a dictionary (the
seenStates
dictionary) to keep track
of whether the solver had seen a state already. If so, the solver
skips putting that state into the activeStates; this prevents the solver
from getting stuck in an infinite loop, because we'll never try to
explore the same state more than once. In addition, the seenStates
dictionary is used to keep track of how we got to each state: each
state keeps track of its predecessor, so that when the solver eventually
finds a solution, it can follow the trail of predecessors back to
the start state, thereby spelling out a step-by-step solution to the
puzzle. However, back when we did Project 1, we hadn't learned anything
about the Dictionary ADT yet, so we implemented this with just a simple,
unordered linked list.
Now that you've learned more, we can now make the maze solver better! In particular, you have learned about AVL trees and hash tables as efficient data structure for the Dictionary ADT. Therefore, for this project, your job will be to write 3 new dictionary implementations (AVL Tree, Hash Table with Linear Probing, Hash Table with Double Hashing), and compare their performance to the LinkedListDict.
By the way, be sure to use the code provided with this project, not Project 1! If you don't do this, your code might be much slower than necessary.
You should also notice that find() should keep track of how deep it goes
each time it is called, and record that number by calling record_stats
.
You will also need to add code to find() to count how many probes
are needed, and to track the statistics by calling record_stats
.
At the beginning of your add() function, note the check if the add will push the load factor over 3/4; if so, add() will call rehash() to rehash into the next bigger sized hash table before performing the insertion. Do not modify this code.
You also must answer some questions in the HANDIN.txt file.
Important marking constraints: We will mark your code
semi-automatically. Therefore, you must ensure that your code will
compile and link correctly by simply running make
on the
ugrad Linux servers, with our supplied Makefile.
Also, your code must respect the supplied interface types,
with no modifications. And do not modify the tracing code
marked with "DO NOT CHANGE".
You are responsible for deallocating any memory that you
allocate. (The rule of thumb is: if you create something
with new
, you should destroy it with delete
when you've finished with it. If you used new
with
brackets to make an array, use delete []
rather than
just delete
.)
You may want to use the program valgrind
to help
check for memory leaks, but valgrind is no substitute for understanding
what you're doing.
Important Programming Advice: Test your code!!!!!!!! This means writing tests, just like on Project 1. Do not just rely on the solver to test your code. Your code must implement the Dictionary find and add functions of the Dictionary ADT properly. Do your best to make sure your code really works correctly, even for corner cases!
Teams
You may work on a team of at most two on this assignment, subject to
the course's Academic Conduct
policy, and we strongly encourage that you do so. We recommend that you work (literally) together as much as
possible, but you may choose how to divide the work under three
conditions: (1) document each team member's effort in
the HANDIN.txt
file; (2) work together on
and both understand your HANDIN.txt
; (3)
understand how your team member's code is structured and why it
works. Remember to test your team's code as an integrated whole!
Except in extreme cases, all team members will receive the same grade
for the project. Check
out All
I Need to Know about Pair Programming I Learned in Kindergarten
for advice on working in a pair.
What we've provided
As before, we've provided a whole bunch of files::
make
will use this to build your
program. You should not need to modify the
makefile, even if you add new .cpp
and .hpp
files. DO NOT MISS the
following commands:
make
handin-proj2
hands in your final project 2 submission (run
early and often). These commands must be executed on our
undergrad linux servers, in a directory that contains the
relevant HANDIN.txt, and various .cpp and .hpp
files you wish to hand in.All provided files are included in this zip archive: project2-files.zip
As before, use make
to compile the code.
Note that you might have to put in some placeholder code in the
classes that you haven't written yet, in order to allow the compilation
to complete. Also, you may ignore any type conversion warnings in the
code that we've supplied.
Final Submission
You are required to hand in your project2 directory with your implementations of the Dictionary ADT. Included in this directory should be at least these files:
You should not need to hand in changes to any other files in the project.
Turn your files in
electronically using handin
,
by running make handin-proj2
.
Checking Your Stats:
If you want to check whether your statistics collection code is working correctly, here are the search cost stats (number of nodes in the AVL tree traversed, or number of hash buckets checked -- see the individual .cpp files for more details) you should see when running on the Maze 1 with the supplied HeapPriorityQueue.
For the AVLDict:
Depth Statistics for find(): 0: 0 1: 2 2: 10 3: 10 4: 22 5: 32 6: 83 7: 112 8: 81 9: 49 10: 0 ...
For the LinearHashDict (with the primes[] array):
Probe Statistics for find(): 0: 0 1: 204 2: 51 3: 16 4: 18 5: 2 6: 9 7: 2 8: 3 9: 3 10: 10 11: 3 12: 2 13: 3 14: 0 15: 3 16: 2 17: 0 18: 0 19: 0 20: 2 21: 4 22: 9 23: 2 24: 7 25: 2 26: 2 27: 4 28: 4 More: 34
For the DoubleHashDict (with the primes[] array and hash2()):
Probe Statistics for find(): 0: 0 1: 223 2: 86 3: 31 4: 30 5: 13 6: 10 7: 2 8: 0 9: 2 10: 0 11: 2 12: 2 13: 0 ...