CPSC 240 — OOA&D — Fall 2024
"Zork III"
Due: Friday, Oct. 25, midnight
Zork III: Items & inventory
Your mission in Zork III is twofold:
- Create support for basic items. Basic items don't actually do
anything, but they can at least generate colorful messages, and you can pick
them up and drop them.
- Refactor your rudimentary support for commands into a Command
inheritance hierarchy that will be more adequate for representing the wider
variety of commands you'll implement in Zork++.
Setting up your team development environment
In order to work effectively together, you'll set up a private github repo
that allows you to share code. Here's how.
- Each team member should create an account on github if you don't have one already. The three of you
should share these with each other, and then one of you should send me
one email with subject line "CPSC 240 Team N github usernames"
(with the "N" replaced with your team number). This email should Cc:
the other two members of your team. In the body of the email, you should
include the three github usernames for your team, along with which human name
goes with which github username. (You should now proceed to step 2. You won't
be able to do step 3 until you get a reply email from me about your github
usernames.)
- Choose a starting point. This step is an
important one which should not be taken lightly. Your team must put your heads
and your hearts together, and decide which team member's Zork II project
will be the launching point for your Zork III project.
If all has gone well to this point of the semester, your three Zork II's
should be eminently compatible from a design standpoint. Therefore, if team
member A's Zork II is chosen, it shouldn't require a great deal of mental
adjustment on the part of team members B and C to understand it. You all have
Rooms, CommandFactories, etc., that all work
essentially the same way.
How then should you choose? Basically, you should choose a Zork II program
that works well and is written cleanly. The weirder and more convoluted it
is, the flimsier the foundation it will provide on which to build. The buggier
it is, the buggier your Zork III (and beyond) is likely to be. All else being
equal, "vanilla" and "straightforward" are better than "innovative" and
"complex." All three of you should look over all three of the Zork II
programs, and make an intelligent decision as to which one to go forward
with. This will require compromise and sacrifice, humility and a team
spirit.
Theoretically — but very theoretically — you could merge your three
programs so that your Zork III starting point contains some classes from each.
I would not advise this, however, unless you really do scrutinize all three
programs in detail and convince yourselves that they really are plug-and-play
compatible. In my experience, this is rarely the case, even for programs that
were architected and envisioned identically. There's just too many little
fiddly assumptions that every piece of code makes that are likely to produce
bugs when hodgepodged together.
(You may, if you wish, begin with my own Zork II
program, which is in Canvas. To use Stephen as a starting point,
one team member should download zorkII_stephen.git from
Canvas, upload it to his/her cpsc.umw.edu account, and execute these commands:
$ git clone zorkII_stephen.git zorkProject
$ cd zorkProject
$ git remote rm origin
and then proceed with step 3.)
- (You won't be able to begin this step until you
receive the reply email from Stephen about your github usernames.) The team
member whose Zork project was chosen as the team's starting point (or the one
who copied Stephen's in step 2) should carefully add his/her project to y'all's
private shared github repo so that all three of you can henceforth collaborate
on it. Replacing "N" with your actual team number, this student should
execute the following commands from within his/her project directory:
$ git remote add origin git@github.com:UMWComputerScience/240-fall2024-teamN.git
$ git branch -M main
$ git push -u origin main
He/she/it will be prompted for a github userid and password. You will know this
step worked if you can open your browser, surf to
https://github.com/UMWComputerScience/240-fall2024-teamN, and see all
your code.
- Each of the other two team members
will, in their own cpsc.umw.edu directories, either rename (via the
"mv" command) or nuke (via the "rm -rf" command) their
zorkProject directory. Then, replacing "N" with your actual
team number, each of those two team members should execute the following
command:
$ git clone git@github.com:UMWComputerScience/240-fall2024-teamN.git zorkProject
You will know this worked if you two can each "cd zorkProject" and
browse around and see all of your first team member's code.
The requirements
Commands
Your Zork III game engine will support the following four additional
commands: "look", "take", "drop", and "i"
(for "inventory"). In addition, the dungeon file may specify
item-specific commands for certain items; for instance, "wear
necklace" or "ignite lightsaber". For Zork, item-specific
commands won't do anything except output a custom message to the player; in
Zork++, however, they will trigger events that will have some effect on
the game.
look
Typing "look" is the way a player can see again the full
description of a room they have previously entered.
Basement hallway
You can go u to Rotunda.
You can go s to Lab.
You can go n to Back hallway.
> u
Rotunda
You can go u to Rotunda balcony.
You can go d to Basement hallway.
> look
Rotunda
You are in a beautiful round entry chamber, with tall white pillars that
seemingly reach to the skies. There is an elevator here.
You can go u to Rotunda balcony.
You can go d to Basement hallway.
>
take
If the player types "take itemName", and an item with that name is
in the current room, it will be added to their inventory (presently held
items) and an appropriate message will be printed:
> take cupcake
Cupcake taken.
>
Other obvious cases should be appropriately handled:
> take ukulele
There's no ukulele here.
> take cupcake
You already have the cupcake.
> take
Take what?
>
Interestingly, a player can refer to most items by more than one name. The
name the game prints is called its primary name, and the other names
players can use to refer to it are called its aliases.
> take dessert
You already have the cupcake.
> take sword
Broadsword taken.
>
For brevity, the player can put the special word "all" after a
take command, in which case all items in the room will be taken.
> take all
Football taken.
HockeyPuck taken.
MandarinOrangeSalad taken.
>
Finally, an adventurer cannot carry more than 40 total units of
items. If he/she/it tries to pick up an item that would take them over this
limit, print a denial message:
> take notebook
Notebook taken.
> take pencil
Your load is too heavy.
> i
You are carrying:
A figurine
A laborSavingDevice
A platypus
A notebook
> drop notebook
Notebook dropped.
> take pencil
Pencil taken.
> i
You are carrying:
A figurine
A laborSavingDevice
A platypus
A pencil
>
drop
If the player types "drop itemName", and an item with that name is
in their inventory, it will be dropped into the current room:
Big Room
You are in a very large room.
> drop cupcake
Cupcake dropped.
> look
Big Room
You are in a very large room.
There is a cupcake here.
> drop sword
Broadsword dropped.
> look
Big Room
You are in a very large room.
There is a cupcake here.
There is a broadsword here.
> drop ukulele
You don't have a ukulele.
> drop
Drop what?
>
The command "drop all" is also an option, of course:
> drop all
PistonAssembly dropped.
Football dropped.
HockeyPuck dropped.
MandarinOrangeSalad dropped.
>
inventory
If the player types "i" or "inventory", their current
list of items will be displayed (as primary names):
> i
You are carrying:
A cupcake
A banjo
A trampoline
>
Print a reasonable message for empty inventories:
> i
You are empty-handed.
>
item-specific commands
Players can type arbitrary verb/noun combinations. If the noun matches the
name of an item that is either in their inventory or in the
current room, and if the verb corresponds to an item-specific verb for that
noun, the corresponding message (specified in the dungeon file) will be output.
Otherwise, they will receive an appropriate response:
> kick DrPepper
The can skitters down the hallway.
> kick soda
The can skitters down the hallway.
> break StarWarsToy
Whoops!
> break DrPepper
You can't break the DrPepper.
> teleport StarWarsToy
You can't teleport the StarWarsToy.
> eat donut
There's no donut here.
> assimilate
Assimilate what?
>
File format: dungeon file (.zork)
The Zork III dungeon file format is as follows (changes in red):
James Farmer Hall
Zork II
I
===
Items:
magicWand
5
---
WawaTravelMug,mug
10
---
DrPepper,can,soda
10
kick:The can skitters down the hallway.
shake:A liquid fizzes menacingly inside the can.
drink:Gulp, gulp -- that was GOOD! *belch*
---
StarWarsToy,Yoda
5
touch:Yoda says, "Do, or do not! There is no try."
break:Whoops!
---
chainsaw
35
---
donut
7
eat:You feel mildly guilt-ridden.
---
===
Rooms:
Rotunda
You are in a beautiful round entry chamber, with tall white pillars that
seemingly reach to the skies. There is an elevator here.
---
Basement hallway
Contents: DrPepper
A long, white hallway stretches to the east and west. It is cold here, and you
can detect the faint smell of body odor. A vending machine hums softly in the
corner.
---
Back hallway
Comfortably cool, this hallway features stylish lines and cutting-edge decor.
---
Stephen's office
Contents: StarWarsToy,WawaTravelMug,donut
This is a cluttered office, with many geeky toys sprawling on a desk. There
are posters of Dune, Star Wars, and UMW Women's Basketball on the walls.
---
Room 054
Sunlight streams through tall windows and illuminates a brilliant classroom.
---
Lab
The scent of unwashed bodies is stronger in this place. Rows of
state-of-the-art computers line the room, with happy young people typing
merrily away at several of them. They look up and wave hello to you.
The door locks behind you.
---
Rotunda balcony
Contents: chainsaw,magicWand
You stand on a circular white balcony overlooking an entry hall.
Columnar bannisters in ancient Grecian style stand between you and the
precipice.
---
===
Exits:
Rotunda
u
Rotunda balcony
---
Rotunda balcony
d
Rotunda
---
Rotunda
d
Basement hallway
---
Basement hallway
u
Rotunda
---
Basement hallway
s
Lab
---
Room 054
w
Back hallway
---
Back hallway
e
Room 054
---
Basement hallway
n
Back hallway
---
Back hallway
s
Basement hallway
---
Back hallway
n
Stephen's office
---
Stephen's office
s
Back hallway
---
===
The changes are as follows:
- A new "Items:" section follows the standard header. Zero or more
items will follow, terminated as usual by a "---" delimiter. Each
item consists of (1) a primary name plus zero or more aliases
(comma-separated), (2) a weight (in unspecified units), and (3) zero or
more item-specific commands, each of which has a verb and a message
separated by a colon.
- An item's initial location is specified in the "Contents:" line
of the relevant "Rooms:" section. It is comma-separated, with no
spaces. This line should be absent if a room is initially empty. If an
item does not appear in the Contents section of any room, then
it is initially not in the dungeon at all. (Perhaps in Zork++ it can be
conjured with a spell, created by transforming a different item or by
assembling components, etc.)
File format: save file (.sav)
The new save file format is as follows:
Zork II
I save data
Dungeon file: /home/stephen/teaching/240/zork/files/farmerv3.zork
Room states:
Stephen's office:
beenHere=true
---
Room 054:
beenHere=true
Contents: DrPepper,burrito
---
Basement hallway:
beenHere=true
---
Back hallway:
beenHere=false
Contents: chainsaw,magicWand
---
Rotunda:
beenHere=true
Contents: StarWarsToy
---
===
Adventurer:
Current room: Stephen's office
Inventory: WawaTravelMug,donut
Changes include:
- Any item that was in a room at save-time will appear in the
"Contents:" line at the end of that room entry. (The primary name of
the item, not its alias(es).)
- There is now an "Adventurer:" delimiter line, stylistic.
- If the user possessed any item(s) at save-time, their primary names will
be listed in the "Inventory:" line, comma-separated, with no spaces.
This line should be absent if the user had an empty inventory at
save-time.
The design
And now, here's how you're going to accomplish all this.
I present two UML class diagrams for Zork III. The first shows the new
Item class and the classes it's related to. Note that this diagram
only highlights the Zork-III-related changes; other variables/methods in
previously-existing classes still exist as before, as do other classes.
Notes:
- An Item has a name, weight, and a Hashtable of
verb/message pairs (called "messages"). It also has a constructor for
hydration.
- .goesBy() simply returns true if the Item is
known by a certain name. For instance, if the i variable is pointing
to a "DrPepper" item, then i.goesBy("DrPepper") and
i.goesBy("can") should return true, while
i.goesBy("HanSoloActionFigure") should return false.
- The other Item methods should be self-explanatory.
- A Dungeon maintains a Hashtable of all Items anywhere
in the dungeon so they can be easily looked up by (primary) name. You'll
find this useful for the hydration sequence.
- GameState maintains collections of
Items to represent each room's up-to-date contents, and also the
adventurer's inventory.
- Room's additional methods are probably pretty easy to figure out.
The last two on GameState, though, are a bit trickier. These getter
methods each return the Item that matches a particular name (if any)
but the .getItemFromInventoryNamed() one fetches an Item
only from the player's inventory, whereas
.getItemInVicinityNamed() looks also in the current room for
the item. The latter method is useful because Zork will allow you to kick the
DrPepper can even if you're not holding it, as long as it's there in the room
you're in. Each of these methods should throw a NoItemException if
the name they're passed doesn't correspond to any item in their
inventory (or inventory + current room).
The other explanatory diagram I'll provide is the one that depicts the new
Command type hierarchy:
Do not be afraid of the large number of classes. For one thing, they are
almost all quite small. For another, note that the universe itself is composed
of lots and lots of little things all working together, not 2 or 3 humongous
monolithic things. Get used to the idea of creating a little class that
represents one particular thing and does its little job well.
In the diagram you see:
- Command
- This class is gonna get gutted. The functionality that's in there now will
be moved to MovementCommand, SaveCommand, and maybe a few
other places. It will become a shadow of its former self: an abstract
superclass that simply defines one abstract method (.execute()) that
its subclasses will be required to implement.
Reminder: italics on a UML class diagram signifies an abstract
class/method.
- CommandFactory
- Instead of instantiating a Command object directly (which will be
impossible, since Command is now abstract), this class will
instantiate the appropriate subclass of Command. Hint: to parse its
input, the CommandFactory should split the String into words. (The
.split() method of String is useful here.)
- subclasses
- Each subclass of Command will have its own constructor and
.execute() method to do its job. It should be pretty easy to figure
out what each one of these does; let me know if you have problems. Remember:
.execute()'s job is to update the state of the game (if applicable),
and return an appropriate String to get printed to the player in response to
that command.
Sample dungeon
Also for this assignment each team member must create his/her own
.zork file in the Zork III format that is smallish but at least
mildly creative. Here are the details:
- You should create your .zork file in a new subdirectory called
"files" at the top level of your project directory (i.e.,
files should be a child directory of zorkProject, and a
sibling of src).
- Name the file something short. "spaceStation.zork" and
"pyramids.zork" are examples of a good length filename.
- Check your .zork file into git, using the same procedures you do
for .java source files.
- This sample dungeon must include at least ten rooms, at least
eight items, and at least twenty different item-specific
commands for your various items. (I don't mean 20 verbs and messages for
each item; I mean at least 20 total verbs/message among all your
items.)
Recommended sequence
Here's my suggestion for where to begin:
- Have an opening meeting in which you look at all the items below, discuss
them, and decide how to initially divvy them up. I recommend you stay
flexible with task assignments — just because Jezebel was assigned
the LookCommand at this initial meeting doesn't mean Jezebel
exclusively owns that .java file forever — but take a reasonable
guess at it.
- Do surgery on your Command class and create the beginnings of the
inheritance hierarchy. For now, just do the MovementCommand,
SaveCommand, and UnknownCommand subclasses. Make your
CommandFactory able to instantiate these two types. Get it all
working so your Zork program behaves just as it did in Zork II.
- Write the Item class in its entirety. The hardest thing here is
the constructor; write a main() to test that it can hydrate from a
file that contains only an item entry. Make sure it works with this
file:
fidgetSpinner
2
spin:Wheeeee!
---
and this one:
HeavyButBoringItem
1000000
---
and this one:
football
8
throw:The football soars through the air.
kick:Through the uprights!
deflate:*Psssssssst.* Tom Brady would be proud.
---
- Make all the changes to the Room class, including hydrating
items.
Unfortunately, you're not going to be able to fully test this step until you
finish step 4, below.
Note that when the adventurer enters a room, there should be a line printed for each item
the room contains:
There is a StarWarsToy here.
There is a WiiProController here.
- Make all the changes to the Dungeon class, including hydrating
items. Make sure you can hydrate farmerv3.zork.
- Make all the changes to the GameState class, including
persisting/hydrating items. Test that you can save and load a .sav
file in the proper format.
- Write LookCommand, TakeCommand, DropCommand,
and InventoryCommand, and get them all working. Make sure you can
look around, pick up items, take them elsewhere, drop them, look at your
inventory, save your progress, and pick up where you left off.
- Write ItemSpecificCommand and get it working with some funny
messages.
- Finally, each team member write your sample 10-room dungeon (see
above) and play each others' dungeons.
Turning it in
To turn in this assignment, one team member send an email
to cpsc240submissions@gmail.com with subject line "CPSC 240 Zork III
turn-in", Cc:'ing the other team members.
No need to include any attachments: I will simply clone your team's github repo
and test that. (Make sure all of your latest code is committed and pushed, and
also double-check that each team member's .zork file is in the
files directory.)
We need help!
Send email with subject line "CPSC 240 Zork
HELP!!!" Use a number of exclamation points reflective of the urgency of
the request.