Introduction:Once upon a time, before the dawn of the Internet, as we know it, there lived a forgotten type of computer game called interactive fiction. First written in the late '70s, these games were sort of a choose-your-own-adventure book, but for geeks. These games contain no graphics, just a 2nd person (everybody remembers English class right?) description of your character, and a box for entering commands. With the birth of the kindle and other Internet-enabled e-readers, these games are experiencing something of a rebirth, as their screens are a perfect match for these games.
To play one for yourself, go to http://www.portablequest.com
Your project is to create an interactive fiction. In this game, you will navigate a map (moving east, west, north, south when possible). In each “room” of the map, the game will print a description of the room to the screen. As you navigate through the map, you will be looking for a light to light up the dark rooms, a key to open a treasure chest, and a chest (that contains the treasure!). Once you have found the key, you can open the chest. While going through the map, you must watch out for the deadly grue! To help you get started on the game, a couple of classes have been written for you. You only need to make the guts of the game, called the engine. You will find Map.java, Room.java, Lamp.java, Key.java, and Chest.java on the course website. Some of these classes are completely finished and others are just skeletons (containing comments and method signatures). You will also find a tester file we have created for you called InteractiveFictionTesting.java. This file provides you with unit test cases to individually test the different classes you will be implementing. You should test your classes with this file as you implement them.
Begin by taking a quick a look at the Map class, which is completely implemented for you (do not modify the Map class, just know how to use it). In this game, a map is a square of size NxN where each cell contains a room. Each room contains a description of the room and possibly a few other items. You call the getRoom(X,Y) to retrieve the Room object for a given square. The first number (X) gives the row and the second (Y) gives the column. The starting room is at (0,0).
To the right is a picture of a general map. Note that the map can be of any size. To clarify the X and Y positions, we have marked the map at position (2,1) with an O. In this cell, we would say that the X value is 2 and the Y value is 1.
While debugging your code, you can run the program in “simple map” mode where the map contains only a single room (see below). This is useful in debugging because no one wants to walk through a huge map only to find that the final command doesn’t work. When you have tested your code and want to play the entire game, set the simpleMap variable to false for a larger map. The larger map we have provided is of size 5x5.
Now take a look at the Room class. This class is implemented for you as well. It contains a large number of methods for you to use during the game. As you can see, there are no setters, only getters. This means that for the most part, you cannot modify any Room objects you receive. The exceptions are the clearKey() and clearLamp() methods that modify two of the room's sub-objects. Note: these methods allow you to modify a Room object. You should never modify the Room.java code. You'll see down below when you need to call these methods. If a room does not have a specific sub-object (key, lamp), its variable will be set to null. You will need to test for this condition to see if a room has a sub-object or not. The description of the interface for this class is given at the end of this pdf.
Now, take a look at the Key class, it is written for you. You do NOT need to update anything in the Key.java file. The Key class only has one method: public void use(Chest onChest). Calling this method simply calls the unlock method on the given chest. The description of the interface for this class is given at the end of this pdf. Program Requirements – General Algorithm
You should NOT modify Room.java or Map.java or Key.java to get your game working. Your project will be tested with our own versions of these two files, so any modifications you make could result in your project not compiling or not working correctly.
Also – you should never create new Key or new Chest objects. This is done already in the preexisting code. So, if you add the words “new Key()” or “new Chest()”, you are making a mistake. The key, lamp and chest in the game will be initialized for you in the Map class – and since we don’t want more than one key, lamp, or chest in our game, we shouldn’t create any more.
1. You should start your work by implementing the Chest class (a skeleton is provided for you). You should use the following information to determine what instance variables you will need to create in the Chest class. You should store the following information about your Chest object:
• whether it is locked or not
• a String describing the contents
• which key object it was locked with.
You do not need to initialize these variables – it is done for you elsewhere. The method stubs for this class are provided with comments, be sure to implement them the way they are described. You should not add any more methods to this class. Once you have implemented this file, test your Chest class with the InteractiveFictionTesting.java file.
You will need to comment out the methods that test Lamp and Player and their method calls in main.
2. Next, implement the Lamp class (the class definition is provided for you), it only needs one variable to store whether it is lit or not – you do not need to initialize its value – it is done elsewhere. You need a method named setIsLit that sets whether or not the lamp is lit to the boolean value entered by the user. You should also provide a getIsLit method to return the current status. Once you have implemented this class, you can test it with InteractiveFictionTesting.java. Simply uncomment the method ‘testLampClass’ and call in main. Ensure that any classes you have not yet implemented are commented out.
• Note: You will need to define your methods exactly as specified in order to test them with InteractiveFictonTesting.java
3. Then, create a Player class. No skeleton is provided for you, you must create it from scratch. You're responsible for adding instance methods and variables. A player object will represent the user playing the game and should store the following things:
• Which map square they are currently on – given by integer x and y coordinates
• A Lamp object that should initially be null – since the player will not initially have
a lamp (objects that are not initialized default to null anyways).
• A Key object that should initially be null – since the player will not initially have a key (objects that are not initialized default to null anyways).
• Be sure to follow encapsulation/information hiding rules here too. The accessors and mutators that you create should follow normal naming conventions and be defined to work with the method calls in InteractiveFictionTesting.java. When defining these methods, remember – you should never be calling new Key() or new Lamp().
• When the player collects the lamp and the key, you will call setLamp and setKey to set these variables. In the case that setKey() is called -- we want the Key object in the player class to point to the same memory location as the Key object passed in. If you call getKey() or getLamp() and it returns null – then the player does NOT currently have them.
You can now test your Player class with InteractiveFictionTesting.java. Uncomment the ‘testPlayerClass’ method and its method call in main.
4. Once these are done, create a class called Adventure and write the main method of your program in it (remember that the class that contains the main method is the one that you run). This is where all of our different classes will be interacting. We will need a Player – someone playing the game, a Map for that Player to traverse through, and a way to store the Player’s current Room in the Map. We will also be implementing our logic here that actually runs the game.
• Create a new Player object and set its starting coordinates to (0,0). – This means our Player will be starting in the top left of our Map.
• Create a new Map object – this is the Map that the user will be moving through during the game.
• Declare an object of type Room (note: you should not be creating a new object) – this variable should hold the current room object that the player is in – given by the x and y coordinates on the map. You can get the current Room by calling a method in the Map class if you know the Player’s current x and y coordinates, initially (0,0). Display your initial room’s description.
The idea in the Adventure class is that you loop repeatedly until the player dies (attacked by grue – see below), or finds the treasure (opens chest – see below). Every time the player moves (either North, South, East, or West) you should update the player's position (coordinates) and get the appropriate Room object from the map. Using your current Room object, display the appropriate text to the user based on what command they type in. A list of commands is given below. Ignore case on the user input.
• GET LAMP – If the lamp is present in the current room (there is a method in the Room class (i.e. getLamp()) that allows you to check this. Note the method’s return type and assign the return value accordingly), this transfers the lamp from the room to the player. Be sure to clear the lamp from the room afterwards – there is a method for that. Print “OK” if successful, or “No lamp present” if not.
• LIGHT LAMP – If the player has the lamp (it won’t be null), this sets it to lit. Print “OK” if successful, or “You don't have the lamp to light” if the player doesn't have the lamp.
• NORTH, SOUTH, EAST, WEST – If the current room (prior to the move) isDark(), AND the player doesn't have the lamp OR the lamp is not lit, the player is eaten by a grue and the game is over. (see below for an example). Otherwise, move the user North one square (-1 x), South one square (+1 x), East one square (+1 y), or West one square (-1 y). See table below to understand x and y in the context of the map. Ensure that you update both the player’s coordinates and the current room based on those coordinates.’
• Once you move into a new room, you should print out its description, so the user doesn't have to type LOOK every time. Be sure to check the current room object to see if the given direction is valid. If not, print (“Can't go that way”). If the room (after the move) isDark() AND the player does not have the lamp OR the lamp is not lit, then instead of printing the description, tell them: “It is pitch black, you can't see anything. You may be eaten by a grue!”. (see below for an example)
• LOOK –If the room isDark() and the player does not have the lamp or the lamp is not lit, then instead of printing the description, tell them: “It is pitch black, you can't see anything. You may be eaten by a grue!”. (see below for an example).
This is all it should print since it is dark & you cannot see anything. Otherwise, this prints the description of the current room, any objects that are in the room, and which exits from the room are valid.
i. If the lamp is present in the room, print “There is an old oil lamp here that was made long ago” after you have printed out the room description.
ii. If the key is present in the room, print “You see the outline of a key on a dusty shelf that's covered in dust.” after you have printed out the room description.
iii. If the chest is present in the room, print “There is a large, wooden, massive, oaken chest here with the word “CHEST” carved into it” after you have printed out the room description.
• GET KEY – If the key is present in the room, this transfers the key to the user's inventory. Be sure to clear the key from the room afterwards. Print “OK” if successful, “No key present” if not.
• OPEN CHEST – If the chest is present in the room and is unlocked, then this should print out the chest's contents and end the game. If the chest is locked, print “The chest is locked”. If the chest is not present in the room, print “No chest present”.
• UNLOCK CHEST – If the user has the key, call the Key object’s use() method with the chest object to unlock it, then print “OK”. If the user doesn't have the key, print “Need a key to do any unlocking!”. If the chest is not present, print “No chest to unlock”.
• (anything else) – Just print “I'm sorry I don't know how to do that.”