1
CS 215 – Spring 2021 Project 2
Learning Objectives: - use of a combination of arrays and structures to organize data - implementation of free functions given detailed design specifications
General Description: You are to complete a Mini-MUD game. The game allows the player to explore a world made up of “rooms” (which may be outdoor locations) that may contain items that can be “taken” and “dropped”. The player can move room to room by taking an exit, denoted by “north”, “south”, “east” or “west”. The player must discover a quest (task/mission) to perform which involves finding and taking certain objects and dropping them in a “win room”. Each room and item has a short description and a long description. Each room may have a list of 0 to 5 items (the room’s inventory) and should have one to four exits (north/south/east/west). There is also a player inventory consisting of 0 to 5 items. To make the game flexible for non-programmers, the description of the rooms, its objects, and the details of how to win, are stored in a text file that can be written by anyone who knows the rules of writing the file. Player commands: The game presents a ===> prompt to the user to enter a command. The first word of any input made by the player should be one of the following commands, possibly followed by additional text; otherwise, the game responds with the message What?? Most commands have an abbreviation that may be used, shown in square brackets below.
- look [l] Prints the long description of the current room. Prints You notice the following: followed by a comma-separated list of the short description of the items, when there are items in the room. (Prints nothing if no items). Prints You can go: followed comma-separated list of the available exits. Examples:
===> look
You are in a dark cave with very
little light.
You notice the following: torch, rock.
You can go: north, south.
===> l
You are in a dark cave with
very little light.
You can go: east.
2
- inv [i] (player inventory) Prints You are holding: followed by a comma-separated list of the short description of the items currently in the player inventory. Prints You don’t have anything. when the player inventory is empty. Examples: ===> inv
You are holding: rock, torch.
===> i
You don’t have anything.
- exa <item> [x] (examine an item in the room or player inventory) Prints the long description of the item when the item exists in the room or in the player inventory (where <item> matches the short description of a game item). Prints You see no <item>. when <item> is not found in the room or player inventory. Examples: ===> exa torch
It is a wooden torch burning on top.
===> x torch
You see no torch.
- take <item> [t] (take an item from the room inventory and move it to the player inventory) Prints You take the <item>. when <item> is in the room inventory and the player inventory is not full. Moves the item from the room to the player inventory. Prints You see no <item>. when <item> is not in the room inventory. Prints You already have the <item>. when <item> is in the player inventory but not the room inventory. Prints Your hands are full, you can’t take that. when <item> is in the room inventory but the player inventory is full. Examples: ===> take torch
You take the torch.
===> t torch
You already have the torch.
===> take torch
You see no torch.
===> t torch
Your hands are full, you can’t take that.
- drop <item> [d] (drop an item from the player inventory and move it to the room inventory)
Prints You drop the <item>. when <item> is in the player inventory and the room inventory is not full. Moves the item from the player to the room inventory. Prints You have no <item>. when <item> is not in the player inventory. Prints You don’t have the <item>. when <item> is in the room inventory but not the player inventory. Prints The room is full of junk, you can’t drop that. when <item> is in the player inventory but the room inventory is full. Note: dropping the last/only “win item” in the “win room” will print the “win message” and end the game (though this should be done outside the doDrop() function). Examples: ===> drop torch
You drop the torch.
===> d torch
You don’t have the torch.
===> drop torch
You have no torch.
===> d torch
The room is full of junk, you can’t drop that.
3
- north [n] (go north)
When north is an available exit in the current room, changes the current room to the one in the north direction, then performs the same action as look, except the short room description is used instead of the long. When north is not an available exit, prints You can’t go north. Examples: ===> north
In a cave.
You notice the following: rock.
You can go: north, south.
===> n
You can’t go north.
- south [s] (go south) - works the same as north but in the south direction. - east [e] (go east) - works the same as north but in the east direction. - west [w] (go west) - works the same as north but in the west direction.
- help - displays a list of commands and brief explanation of the game
(provided in the gameutils.cpp file on the course website).
- exit - Performs a system pause and exits the game.
Starting the Game: The game starts by displaying a logo (create your own logo; it must contain your name). It then asks the user to enter the name of the game to play. Appending the file extension”.txt” to the game name determines the input file name for the game to play. The input file is then read and the game data therein is stored in the program’s data structures. Most lines begin with a tag identifying the type of data on the line (see input file details below).
- If the file fails to open, the game prints Unable to open <gamename>.txt - If an unknown tag (first word of line) is found, the game prints
Unknown tag in <gamename>.txt: <theUnknownTag> - After each tag is processed, the program checks for a file read failure. When this occurs, the
game prints Failure while reading input file <gamename>.txt - After any of these three errors occurs, the game does a system pause and exits. Example: +--------------------------------+
| WANDERING WANDA MiniMUD |
| by Ada Byron King |
+--------------------------------+
Enter name of game to play: dragons
Unable to open dragons.txt
Press any key to continue...
Once the input file has been successfully read and closed, a game start message is printed: You fall asleep and dream of a place far away... (or create your own).
4
The player starts in the first room (room[0]) found in the input file). A “look” (long description) is automatically performed before the first command is entered.
Example: +--------------------------------+
| WANDERING WANDA MiniMUD |
| by Ada Byron King |
+--------------------------------+
Enter name of game to play: dragons
You fall asleep and dream of a place far away...
You stand in a dark cave with very little light,
water dripping from the ceiling. You can go deeper
into the cave to the north, while sunlight
indicates the entrance is to the south.
You notice the following: torch, rock.
You can go: north, south.
===>
Winning the game: The game is won as soon as the player drops the “win object” (or last of the “win objects” if more than one) in the “win room”. Thus the check for “has the player won the game?” should be done every time an object is dropped when the current room is the win room. After the player drops this object, a “win message” is printed and a system pause done before the game exits.
Example: assume the win objects are “rock” and “torch” ===> drop torch
You drop the torch.
===> drop rock
You drop the rock.
The dragon drops dead and explodes! You win!
Press any key to continue...
The “win data” (room number, list of items, and message) are defined in the input file.
Input File Specifications: Each line of the input file should begin with a known tag, one of those listed below. Two exceptions: the long description of a room or item is on a line by itself without a tag. Blank lines are ignored. Note each tag has a colon on the end, and must be followed by a space. The game extracts (>>) the first word of a line (the tag) from the input file. Depending on the tag, it reads the remainder of the line as one string value, or extracts (>>) an integer value. For the room and item tags, after reading the remainder of the tag line, the following line is read as a whole string for the long description. Note that any string value specified must be all on one line. It is assumed that room tags are found in order starting with room number (index) 0. Room 0 is defined as the “start” room where the game begins. All item and exit tags below a room tag are assumed to be in that room. Processing of the next room begins when the next room tag is encountered.
5
Tag and format Meaning ROOM: short description
long descript. on the next line Beginning of the definition of the room. The index of the current room being read is incremented. The remainder of the line on this tag is the short description of the room. The entire next line is the long description of the room.
ITEM: short description
long descript. on the next line An item in the inventory of the current room being read. The item’s short description is on the remainder of the line, and the long description is on the next line with no tag.
NORTH: n
n is the room number (an integer index into the room[] array) where the player will go if he/she takes the north exit from the current room. This data applies to the current room being read. Note that a room may not have all four exits. For any exit (north/south/east/west) not specified for a room, the default value is NO_EXIT (a constant
defined in gameutils.h as -1) SOUTH: n Same explanation as NORTH:, but for the south exit. EAST: n Same explanation as NORTH:, but for the east exit. WEST: n Same explanation as NORTH:, but for the west exit. WIN_ROOM: n n is the room number (an integer index into the
room[] array) of the “win room”. WIN_ tags may be placed anywhere in the file (they do not apply to the current room being read), but normally at the top or bottom.
WIN_ITEM: short description Specifies the short description of a “win item”. Win items do not need a long description, and so none is specified in the file (set it to empty string in the item structure in the program). It should exactly match the short description of an item found in some room.
WIN_TEXT: message Specifies the “win text” printed when the player wins the game.
REMARK: unused text This tag allows the “game master” to put comments in the input file. The remainder of the line is read and discarded.
END: This marks the end of the game data. Anything after this tag is not read into the game, but the tag is required.
6
Example: two rooms
Text File How interpreted by the game program: REMARK: --- return the lost cat game --- Read and discarded/ignored WIN_ROOM: 0 windata.winRoom = 0 WIN_ITEM: cat windata.numWinItems = 1
windata.winItem[0].shortDesc = “cat” WIN_TEXT: The cat is home! You win! windata.winMessage = “The cat is home…” ignored REMARK: ------ ROOM 0 ------- Read and discarded/ignored ROOM: Inside a home numRooms = 1
currentRoom = 0 rooms[0].shortDesc = “Inside a home”
You are in a home. Find & return the cat. rooms[0].longDesc = “You are…cat.” SOUTH: 1 rooms[0].south = 1 ignored REMARK: -------- ROOM 1 ------ Read and discarded/ignored ROOM: Outside a home numRooms = 2
currentRoom = 1 rooms[1].shortDesc = “Outside a home”
You are outside a home. The door is open. rooms[1].longDesc = “You are…open.” ITEM: cat rooms[1].numItems = 1
rooms[1].items[0].shortDesc = “cat” A lost cat that wants to go home. rooms[1].items[0].longDesc =”A lost…home.” NORTH: 0 rooms[1].north = 0 END: end of data
Coding note: use f >> intlocation to extract integers from the end of the line.
use cleanGetline(f,stringLocation) instead of the standard getline() to extract the remainder of a line of text, or an entire line of text. This function is written for you in
gameutils.cpp and will save you some headaches.
7
Given Code and Data Files: gameutils.h This is the header file for the gameutils.cpp code. Any .cpp that needs to use the game utilities should #include ”gameutils.h” This code should not be changed! It contains:
- constant declarations that should be used throughout the program as needed. - structure declarations for item, room and winData
- a list of prototypes for free functions available in gameutils.cpp gameutils.cpp These are functions that will be useful throughout the project. This code should not be changed! The functions include:
- gameAbort() – use this anywhere the code needs to abort the game. It is given a message to print.
- cleanString() – given a string, it removes leading and trailing white space, and reduces any intermediate whitespace to one blank. This can be used on data read from the input file, and for input from the user, to make processing this data easier. Example:
given: ” take cell phone ”
returns: ”take cell phone”
- cleanGetline() – use this instead of the standard getline() when reading from a file.
- split() – this is used to split a string into its first word and the remainder of the string. Example:
given: ”take cell phone”
results: ”take” and ”cell phone”
- printHelp()– prints the help screen for the game.
- printRooms(), printWinData(), printItems() these are used for debugging and testing purposes only. They will not be invoked in the final game code.
main.cpp Some of the main program is given here. Complete the project by finishing this code. First be sure to complete the comment header at the top with the standard information.
Finish the loadData() and main() function as described below. makeExitList(), doInventory() and goNorth() are complete and should not have to be changed. These are given as examples to help with completing the project. lunch.txt A game input file for a game of 16 rooms. Use this for final testing. dog.txt, cat.txt These are game input files for a quick game with 2 rooms. Use this for intermediate testing.
8
Detailed Design: Write the following functions as specified to complete the project. Work on each function one at a time. Use a “test” main to test it before proceeding to the next function.
Name printLogo
Given
Modifies
Returns
Prints the logo for the game at the beginning. Feel free to be creative, but your name is required to be displayed.
Name getInputFileName
Given
Modifies
Returns the name of the game input file (ex: ”dragons.txt”)
Ask the user Enter name of game to play: Append “.txt” to the value entered and return the result.
Name initItems
Given
Modifies A partial array of item structures
Returns
This function initializes a list of items for future use. It should set the short and long descriptions of all elements of the array to empty string, and sets the number of items to 0.
Name initRooms
Given
Modifies A partial array of room structures
Returns
This function initializes a list of rooms for future use. It should sets the short and long descriptions of all elements of the array to empty string, the north/south/east/west exits values to NO_EXIT, and invoke initItems() on the room’s item list.
Name initWinData
Given
Modifies a winDataStruct structure
Returns
This function initializes the win data of the game. It should set the win message to an empty string, set the win room index to NO_EXIT, and invoke initItems() on the list of win items.
9
Name removeItem
Given index into the item list of the item to remove
Modifies a partial array of items
Returns the item removed
The function should check that the given index is valid. If not, it invokes gameAbort() with the message: removeItem: invalid index = n where n is the given index. It should remove the indexed item from the list by “sliding down” items in the list of a higher index. It should return a copy of the removed item.
Name addItem
Given a new item
Modifies a partial array of items
Returns
The function should first check that the modified array has enough room to add another item. If not, abort the game with addItem: maximum number of items exceeded! Otherwise, it should “append” the given item to the partial array of items.
Name addItem (overloaded)
Given a short description and a long description
Modifies a partial array of items
Returns
This function creates a new item object and populates it with the descriptions given. It then invokes the first addItem() to actually add the item.
Name loadData
Given
Modifies a partial array of rooms and a winDataStructure
Returns
Part of this function has been written for you. Invoke the functions mentioned in the comments to initialize the room and win data. Get and open the input file name; when unable to open the file, abort the game with Unable to open filename where filename is the file name entered by the user. Finish the action for each case of the if/else structure, one per input file “tag”. You should only need one line of code for each case, but may add a block if necessary.
Name getCmd
Given
Modifies the remainder of the command entered by the user
Returns the command entered by the user
This function asks the user to enter the next command and splits it into two parts: cout << "===> "; if (cin.peek() == '\n') cin.ignore(); getline(cin, input); After this, invoke the split() function to split the input into the modified remainder and the command. Example: “take little red ball” remainder=”little red ball”, return “take”
10
Name doLook
Given - a room object - a Boolean: show the short description??
Modifies
Returns
This is the code executed when the user enters the “look” command. It displays the room description, a
list of items in the room (if any), and the list of exits from the room.
It should print either the short description or long description of the given room, depending on the given
boolean, on a line by itself.
Create and display the list of items in the room according to the following format:
0 items: print nothing 1 item: You notice the following: itemShortDesc. (add period on the end)
2 or more: You notice the following: item1ShortDesc, item2Short, itemNshort.
(add comma and space after each; except last, add a period) Invoke the given makeExitList() function and print the string it returns on one line.
Name doLook (overloaded)
Given a room object
Modifies
Returns
Invokes the first doLook() with the second argument false. This is one way to allow a “default value” for
a function argument.
Name startUp
Given
Modifies - a partial array of room objects - a partial array of items (the player inventory) - a winDataStructure
Returns
This invokes all the startup activities of the game: - print the logo - load the data (which already initializes the rooms and winData) - initialize the player inventory (invoke initItems()) - Prints You fall asleep an dream of a place far away... - invokes doLook() on the start room (room zero, but no naked literal!!! Use the constant!!)
Name goSouth (and goEast() and goWest()
Given a partial array of rooms
Modifies the current room index in the partial array of rooms
Returns
See the goNorth() function already written for you in the given code. When the south member in the current room is NO_EXIT (-1), print: You can't go south. Otherwise, change the current room to the value of the south member, and invoke doLook() giving it the current room object and a value of true, indicating the short description is to be used.
11
Name findItem
Given a string to search for (name of an item) a partial array of items
Modifies
Returns an index into the array or NOT_FOUND (-1).
Searches the array of items for an element where the item’s shortDescription is equal to the given search string. When found, the index of the array where found is returned. When not found, return the NOT_FOUND constant (-1).
Name doExamine
Given - the name (short description) of an item to examine - the room inventory: a partial array of item objects - the player inventory: a partial array of item objects
Modifies
Returns
“Examine” should work for any item in the room or in the player’s inventory (items the player is holding). First invoke findItem() giving it the room’s inventory. When found, display the found item’s longDescription member in the room array. When not found, invoke findItem() again on the player’s inventory. When found, display the found item’s longDescription member in the player’s inventory array. When not found in either inventory (partial array), print: You see no givenName
Name doTake
Given - the name (short description) of an item to take (pick up)
Modifies - the room inventory: a partial array of item objects - the player inventory: a partial array of item objects
Returns
This function is similar to doExamine(), but with a bit more complicated logic for messages and a transfer of an item from array to array First, invoke findItem() giving it the room inventory partial array. There are three possible outcomes:
- the item is found, and the player’s inventory is not full (use the MAX_ITEMS constant): o invoke removeItem() on the room’s inventory. Use a local item object to “catch” the
item returned. o Invoke addItem() on the player’s inventory, giving it the item object returned from
removeItem(). These two steps effectively “move” the item from one item list to the other.
o Print: You take the itemName. - the item is found, but the player’s inventory is full
o Print: Your hands are full, you can't take that. - the item is not found
o Invoke findItem() on the player’s inventory. o When found, print: You already have the itemName o When not found, print: You see no itemName
12
Name doDrop
Given - the name (short description) of an item to drop
Modifies - the room inventory: a partial array of item objects - the player inventory: a partial array of item objects
Returns
This function is similar to doTake(), but the item is transferred in the opposite direction. DO NOT CODE ANYTHING FOR “IF THE GAME IS WON” HERE!! First, invoke findItem() giving it the player inventory partial array. There are three possible outcomes:
- the item is found, and the room’s inventory is not full (use the MAX_ITEMS constant): o invoke removeItem() on the player’s inventory. Use a local item object to “catch” the
item returned. o Invoke addItem() on the room’s inventory, giving it the item object returned from
removeItem(). These two steps effectively “move” the item from one item list to the other.
o Print: You drop the itemName. - the item is found, but the room’s inventory is full
o Print: The room is full of junk; you can't drop that. - the item is not found
o Invoke findItem() on the room’s inventory. o When found, print: You don’t have the itemName o When not found, print: You have no itemName
Name gameWon
Given - a winData object - a partial array of rooms
Modifies
Returns true or false
This function determines whether or not all win items are in the inventory of the win room. If so, the game is won (return true) otherwise it is not won (return false). For each item in the winData’s winItem partial array, invoke findItem() on the current room of the given room array, giving it the winData’s item’s shortDescription as the string to search for. If the search for all win items results in “found”, then the game is won.
13
Name loadData
Given
Modifies - a winData object - a partial array of rooms
Returns
Most of this function has been written for you in the given code. Complete the function according to these instructions: Under the comment // initialize ..., invoke initRooms() and initWinData(), passing them the partial arrays passed into this function. Under the comment // get input file..., invoke getInputFileName() and open the input file with the name returned. When the file fails to open, invoke gameAbort() with the message
Unable to open inputFileName
Inside the if/else structure on the tag read from the file, complete the incomplete cases. Each should only need one line of code. (Hint: when the end tag is found, reading is done…a good time to close the file).
Name main
Given
Modifies
Returns 1
Much of the main() function has been written for you in the given code. Complete it according to the following instructions: Below the // declare data structures, declare the following:
- a partial array of room objects (rooms) - a partial array of items (the player inventory) - the current room: an index into the room array. Set it to the START_ROOM constant so the
game begins in the “start room”. - a boolean for “game was won” - strings for the command entered by the user, and the remainder of the command entered by
the user (ex: command=”take” and remainder=”red pencil”) - any other variables you may need in main(), if any
Below the // startup: , invoke the startup() function, giving it main()’s variables as its actual arguments. Be sure to match the data type, order, and meaning of each actual argument with the formal arguments in startup(). Inside the while loop, complete the if/else structure by adding cases for all possible valid user commands. You should only need one instruction for each case (though with the long argument lists for some functions, you’ll need to put them on 2-3 lines). Beneath // check if..., set your game won variable to the result returned by invoking gameWon().
14
Submission: When finished, submit only your completed game.cpp file. All given files will be used “as is” from the course website to compile and test your program.