RU beehive logo ITEC dept promo banner
ITEC 120
2019fall
asbrennem
ibarland

gRUe

Due Nov.1820 in class.

Update

I have changed the deadline, and streamlined the requirements and suggested-implementation a bit. There will not be a wiki and/or reading Treasures from it. In particular, I have changed the references to set the explorer's status to… and instead just have those methods return the value. However, I will still give full credit if you took that approach from an earlier version.


When playing the Grand Role-playing Underground Expedition (gRUe), an explorer wanders around different rooms, gathering treasures. An explorer can carry three treasures in their backpack; if they ever grab one treasure they will have to drop some other treasure. (Initially, an explorer's treasures are just three pieces of lint. The growth potential is huge!) A game session might look something like this:

Welcome to the world of gRUe.

Davis 225 lab:
This room is dark, the only light coming from an eerie screen saver.
Lying on the ground, there is:
[1] some caffeinated mints (0.2 lbs).
[2] a thumb drive (0.1 lbs)
[3] a 72" golden iMac (45.0 lbs)
[4] a whiteboard marker (0.2 lbs)


>> What do you wish to do? help

Please type one of the following commands:
  look
  inventory
  swap
  go
  help
  quit
  

>> What do you wish to do? look

Davis 225 lab:
This room is dark, the only light coming from an eerie screen saver.
Lying on the ground, there is:
[1] some caffeinated mints (0.2 lbs).
[2] a thumb drive (0.1 lbs)
[3] a 72" golden iMac (45.0 lbs)
[4] a whiteboard marker (0.2 lbs)


>> What do you wish to do? inventory

You are carrying:
[1] lint (0.0 lbs)
[2] lint (0.0 lbs)
[3] lint (0.0 lbs)


>> What do you wish to do? swap

You are carrying:
[1] lint (0.0 lbs)
[2] lint (0.0 lbs)
[3] lint (0.0 lbs)
What item do you wish to drop? 2
Lying on the ground, there is:
[1] some caffeinated mints (0.2 lbs).
[2] a thumb drive (0.1 lbs)
[3] a 72" golden iMac (45.0 lbs)
[4] a whiteboard marker (0.2 lbs)
What item do you wish to grab? 1

You drop lint (0.0 lbs) -- a ball of fuzz.
You grab some caffeinated mints (0.2 lbs) -- they smell like peppermint coffee.


>> What do you wish to do? inventory

You are carrying:
[1] lint (0.0 lbs)
[2] some caffeinated mints (0.2 lbs)
[3] lint (0.0 lbs)


>> What do you wish to do? look

Davis 225 lab:
This room is dark, the only light coming from an eerie screen saver.
Lying on the ground, there is:
[1] lint (0.0 lbs)
[2] a thumb drive (0.1 lbs)
[3] a 72" golden iMac (45.0 lbs)
[4] a whiteboard marker (0.2 lbs)


>> What do you wish to do? go

The adjacent rooms are:
[1] Davis 2nd floor hallway
[2] sidewalk between Davis and Stuart
Which room would you like to go to? 2

sidewalk between Davis and Stuart:
The sidewalk is covered in leaves.
Lying on the ground, there is:
[1] A scrap of paper.


>> What do you wish to do? quip

I'm sorry, I don't know how to quip.

What do you wish to do? quit

Bye!

Program Structure

The exploring will be done by a “top level” function explore which prompts “What do you wish to do? ” and then (depending on the response) calls the appropriate helper-function. E.g. if the user types “look”, it would call a helper-function which returns a string, and then it would print that result (but the helper-function would not call println itself).

In general, the I/O (input and output) should all be localized just to one or two top-level explore/handleOneCommand function(s). As another example: if the user types “go” then this function might call one helper to get a long string listing the adjacent rooms; it would print the string and read the target room-number; and then actually "move the explorer" (update the Explorer's current-Room field), and finally get the new room's description and print that.

For full credit, you should make sure user-input doesn't crash the program. (However this is a lower priority; you might work on that last. You will get most credit if you assume the user always enters a valid value (e.g. a valid backpack-index, etc.).)

pro tip: If you do want to make sure a valid number is entered, a good helper-function would be readNumber(int max) which returns a number in 1..max, prompting the user repeatedly if necessary.

Read all the instructions below before starting; re-read them periodically as you are writing your code.

  1. Make a new project(directory), which includes class Explorer and class Treasure. You can make new files and copy/paste from the old ones, or (if using BlueJ) you can use Edit > Add Class from File….
  2. Explorers carry Treasures

    1. Every Explorer has a knapsack, which is an array of Treasures. (In the example transcript above, the knapsack size was 3, but changing the knapsack to hold 97 items should just require just one change.)
      Add a field accordingly. This will replace our previous left/right pockets.
    2. Modify the constructor so that a brand-new Explorer's knapsack is initially full of pieces of lint.
    3. Add a method inventory, which returns sets an explorer's status to be You are carrying followed by a string representing all the Treasures in the knapsack.
    4. Modify Explorer's handleOneCommand to allow for handling a user typing inv (or inventory).
  3. Rooms


    Make a class Room:
    1. Read the transcript above, to see what sort of information each different room needs to contain, and make fields appropriately.
      For now: Do not deal with Rooms being connected to other Rooms. That will be left for extra credit.
    2. Include a method which returns a description of the room.
      hint: Both Rooms and Explorers need to get a string that represents an array of Treasures. You won't repeat code1, of course; instead you will have a method to do this one sub-task. Which of your three different classes should best hold a method that takes in an array of Treasure, and returns a String description?
    3. Write a method createAStartingRoom(), which just returns one particular room (which in turn contains at least three specific Treasures).
      We will call this method later, to create the very-first-room for an Explorer to start in. (To think about: Should this method be static? Why or why not?)
  4. We willmight eventually have ways for an explorer to interact with the world around them, but that will have to wait since we don't yet have any classes to represent the world around them! However, we will set up a framework suitable for future expansion.

    (8pts) Write Explorer methods:

  5. (5pts) Write a function void handleOneCommand( /* Explorer this, */ String cmd), which is passed in one String. If the string is one of {"go", "look", "swap", "eat", "wait", "help"}, then call the corresponding method for this Explorer. If a different string is passed in, set this Explorer's status to doesn't know how to cmd.. (Use one big, straightforward if-else-if2.)

    You need only include 2 tests for this function3. Those tests should be pretty easy, since if you pass in (say) "look", you'll then copy/paste the same test you used for look() above.
    Note: this function does not read anything from the keyboard! (See the next function, for that.)

  6. (5pts) Finally, putting it all together:
    Write a method public static4 void main(), which prompts the user to type in a name and reads it; creates an explorer with that name; and then does the following, so long as they aren't ready to retire:

    Note that the above description asks to do three things initially, and then repeatedly do four things. This means that your code will have approximately three lines, followed by a loop whose body is four lines. Note that you'll have one Scanner, stored in a local variable.

At this point, you are off to an awesome start to having written an entire adventure game, which we'll now finish upcan be expanded in the future!

Every Explorer has a current-room:

  1. Make sure your Explorer has a field to represent the current-room.
  2. Have the Explorer constructor initially set a new Explorer's room to the result of calling createAStartingRoom.
  3. Update the Explorer's method look, so that it returns a description of the explorer's current room.
  4. Write an Explorer method String swapItems(int knapsackIndex, int roomItemIndex ), which swaps the contents of an explorer's knapsack and one of the items in their current room. It returns a string describing the swap that just happened.
  5. Write an Explorer method swap(), which prompts the user for item-numbers, and then effects the swapItems. (You may presume that the user enters valid item-numbers, as in the transcript above.)
    Note: This method supercedes the grab and drop methods from hw07's class Explorer. You will want to update the handleOneCommand accordingly.

    Note how between this method and the previous, we are de-coupling input/output (I/O) from actually updating the This is important if we ever (say) have an Explorer controlled by an AI — they still need to swapItems, but they never prompt for input. We have separated the model (objects) of the game from the controller (I/O) of the game.

I should be able to run your program by typing java Explorer from the command line.


Extra Credit:

Connecting Rooms

Handling the connection of rooms is slightly tricky. I recommand creating room-connections in two passes: First create many rooms, but don't (yet) initialize the field for its neighbors. Then, once all your rooms are mostly-initialized, you can add connections. Something along the lines of:

  /** Create all the rooms in the game, connect them, and return
   * the particular room that a player will start in.
   * This method should be called exactly once, at the very start of the game.
   */
  static Room setUpWorld() {
    Room rm1 = new Room (  );  // rm1's "neighbors" field not yet initialized.
    Room rm2 = new Room (  );
    Room rm3 = new Room (  );
    Room rm4 = new Room (  );
    Room rm5 = new Room (  );

    Room[] neighborsOfRm1 = { rm4, rm2, rm5 };
    r1.neighbors = neighborsOfRm1;
    

    return r1;
  }
Of course, connections don't have to be symmetric (you can jump out the window from Da225 to the Stuart/Davis sidewalk, but once on the sidewalk you can't move directly back), and a room might even lead right back to itself.


What next?

This is a very open-ended assignment. Some possible extensions (in approximate order of complexity):


1 After making this task its own separate helper method, be sure to remove any now-redundant old copies of this code from Explorer, if you had put it there for step (Ic) above.      
2 In ITEC220 and later, you'll learn how to automate this if-else using the Command pattern: You'll keep a list of "Command" objects — each Command object would include its own code and its own string, and then you would loop over that list until you found an object with the desired string.      
3 In a real software environment, you would want to have at least one test per if-else-if branch, since conceivably each branch could contain its own, independent bug.      
4 Why is this method static?      

logo for creative commons by-attribution license
This page licensed CC-BY 4.0 Ian Barland
Page last generated
Please mail any suggestions
(incl. typos, broken links)
to ibarlandradford.edu
Rendered by Racket.