MS 6: Locked passages
When you modified the teaching machine code for Milestone 0, you presumably defined the structure representing passages to be a dictionary that maps direction names to room names. That is, after all, how the teaching machine worked, and this guide did not give you any reason to change that model.
Unfortunately, using a dictionary does not quite work for the Adventure game. If you look closely at the list of passages in the SmallRooms.txt and CrowtherRooms.txt, you will discover that certain rooms include the same direction name more than once in the list. For example, the entry for the room above the grate that leads to the underground part of the cave looks like this:
OutsideGrate
Outside grate
You are in a 20-foot depression floored with bare dirt.
Set into the dirt is a strong steel grate mounted in
concrete. A dry streambed leads into the depression from
the north.
-----
NORTH: SlitInRock
UP: SlitInRock
DOWN: BeneathGrate/KEYS
DOWN: MissingKeys
As you can see, the motion verb "DOWN" appears twice in the list of passages. The first corresponding value ends with a slash and the work KEYS, which indicates that the item whose name is "KEYS" is required to traverse this passage. The second has no such modifier, which means that the passage is always available. This definition is an example of a locked passage, which is one that requires the player to be holding a specified item that is called its key. In this case, the key is literally the set of keys that starts off inside the building. If the keys are in the player’s inventory, applying the motion verb DOWN uses the first passage; if not, applying DOWN skips over that passage and follows the one to the room named "MissingKeys", which is described in Milestone 7.
This new feature requires you to change the implementation of the data structure used to represent passages, since a dictionary does not allow multiple values with the same key. What you need to do is change the data structure used to represent the passages from a dictionary to a list, in which the individual elements of the list are tuples containing three values: the direction name, the name of the destination room, and the key required to traverse the passage (which may be None). The code that moves from one room to another based on the player’s input must loop over and search through the list to find the first option that applies.
The changes you need to make for Milestone 6 are in the AdvRoom and AdvGame classes. You will, for example, have to change your implementation of read_room so that it stores the data for the passages in a list rather than a dictionary. The get_passages method in AdvRoom then needs to return a copy of that list. Even if the code for get_passages does not change, you need to update the doc-string so that it correctly describes what the updated method does.
You also need to change the way that the run method of AdvGame works, so that it checks to see if the player is carrying the necessary item if the passage specifies one. To do so, it makes sense to write a helper method in AdvGame that finds the next room for a given direction, taking into account any items necessary to traverse locked passages.
Once you have implemented this change, you should be able to explore the entire Adventure game, picking up items and using them as keys to get through previously closed passages. You still, however, will not be able to escape if you try to go through a locked passage without the necessary key. For that, you need to implement the final milestone.