CSI Lab 03
Tuesday, September 4th
Objective:
To consider issues of good/bad design by "cleaning up" the world-of-zuul game
Part A: Getting Started
For this week's lab you are encouraged, although not required, to work with a
partner. Before you begin, decide between yourselves who will be Partner A and who
will be Partner B. Please notice as the lab goes on that you will change
roles several times. Sometimes you will be the "coder" - the person in
charge of the keyboard - and sometimes you will be the "recorder" - the person
in charge of the answer sheet. You must change roles when instructed to do
so.
[Partner A should manage the keyboard. Partner B should write answers
on the lab sheet].
- Log on to Partner A's Linux account.
- Create a "lab03" folder.
- Download and unzip the bad-zuul project.
- Compile the project by compiling ZuulWorld.java
- Start the game running and play around to see what the game is about.
- When you are done playing, open each of the six classes in the project and
explore what they do. TAKE YOUR TIME. Spend some time on playing
the game and examining the code so that you feel comfortable with what is
going on.
- Answer the following questions:
- [Q1] What does the application do?
- [Q2] What commands does the game accept? What does each
command do?
- [Q3] How many rooms are in the scenario? Draw a map of the
existing rooms.
Part B : What happens if we want to make a "simple" change to our game?
[Partner B should code]
Now that you have looked at the code for the zuul game, you might wonder what the big deal is. Why is this considered to
be "bad" code? Today's lab will start by having you make a couple of
"simple" modifications to the game and looking at how difficult this process is
when the code isn't well designed.
For example, suppose that we want to add a pool hall on the second floor
above the campus pub. In order to do this, we need to add in the ability
to move up and down, and we need each room to know whether there are other rooms
above it and/or below it. By adding in the concept of an upExit and a
downExit to each room in our game we can eventually tell the pub that it has an
exit going up to the pool hall and tell the pool hall that it has an exit going
down to the pub.
- Open the Room class and look at how it currently stores and sets exits.
- Add two new public instance variables - an upExit and downExit.
(I know, I told you never to use public instance variables. Do it here
anyways).
Once you do this, you need to have a way to set these values. It would
seem that the easiest way would be to update the setExits() method.
- Modify the setExits() method so that it accepts SIX parameters - the four
already there and parameters which will set the two new instance variables.
- Compile the Room class. Fix any errors that might exist.
- Attempt to compile the Game class.
- You should discover that it won't compile because you changed the way that
Game class interacts with the Room class. In particular, setExits() expects
six parameters, not four.
- Within the Game class, update all of the calls to setExits() by adding two
additional parameters to each call. For the time being, let's let these
each be "null"
- Now attempt to compile the Game class. This time, it should work.
Ok, now that we have the functionality in place to allow for rooms to have
exits up and down, let's add the pool hall to our game.
[Switch partners. Partner A should code]
- Locate the createRooms() method in the Game class.
- Find the section of code where the various Rooms are declared and
constructed. Add a line of code which declares and constructs a variable named something like "pool" Construct the pool variable using a description like "in a seedy pool
hall."
- Find the section of code where each room has it's exits set. Invoke
the setExits() method on this pool hall and set its only exit to be a down
exit to the pub (You may have to review which of the six parameters you
decided was "down" inside of the Room class.
- Modify the setExits() method for the pub so it now contains an up exit to
the pool hall.
- Compile your code and fix any errors you may have introduced.
- Play your game and navigate into the pub. Try to get up to the pool
hall. Can you? What problems exist?
OOPS! The pub doesn't tell us that it has an up exit so that we have a
way to get up to the pool hall. How do we fix that?
- Start at the top of the Game class and slowly scan down the code.
- When you get to the printWelcome() method, notice the long list of "if"
statements which check whether or not the code should tell us that there is an
exit in a certain direction.
- Update this list to include if statements for the up and down exits.
- Compile your code and fix any errors you may have introduced.
- Play your game and navigate into the pub. Try to get up to the pool
hall. Can you? What problems exist?
DANG IT! This didn't fix the problem. How come? Well,
notice we just updated the printWelcome() method. That method only runs at
the start of the game. What we REALLY wanted to change was the goRoom()
method that gets called whenever you enter a new room (like the pub).
- Notice that there are actually TWO long lists of if statements here.
Humor me and SKIP THE FIRST ONE (the one talking about direction.equals...)
but instead locate the second one (the one that checks if currentRoom.SOMEexit
is != null
- Update this list to include if statements for the up and down exits.
- Compile your code and fix any errors you may have introduced.
- Play your game and navigate into the pub. Try to get up to the pool
hall. Can you? What problems exist?
Ok, you probably figured this one wouldn't work since I told you to skip
updating the direction list earlier in the goRoom() method. You should
observe that while the pub will TELL you it has an exit going up, it won't let
you actually do this.
- Relocate the goRoom() method and update the first long list of ifs so that
it includes references to the up and down exits.
- Compile your code and fix any errors you may have introduced.
- Play your game and navigate into the pool hall. Can you do it?
- If not, why not?
- If so, navigate back out to the main entrance of the world so that you
test that the other parts work.
[SIG1] When you have done this, show your code to a TA and have them initial
your Lab Sheet.
Part C : Ok, that was harder than it should have been! - Removing Duplicate
Code
[Partner B codes]
By now, some of you are doing some serious grumbling. That should have
been easy and it wasn't. Why?
Hopefully, you recognize that this has been so hard because of code
duplication.
Code duplication is an indicator of bad design. The Game class you have
been working with contains a case of code duplication. The problem with
this is that any change to one version of the code must also be made to the
other if we are to avoid inconsistency. This increases the amount of work
a maintenance programmer has to do, and it introduces the danger of bugs.
It happens very easily that a maintenance programmer finds one copy of the code
and, having changed it, assumes that the job is done. There is nothing
indicating that a second copy of the code exists, and it might incorrectly
remain unchanged.
To illustrate this point, notice that the printWelcome() and the goRoom()
methods contained in the Game class both contain a block of code that :
- prints the description of the room and
- lists the current "Exits: " by working through a series of if statements
which decide if the code should print that there is an exit to a given
direction.
As you observed, this is a problem when it comes time to modify the code.
You have to KNOW that both exist and you have to REMEMBER to update both of them
when you make a simple change.
As we have discussed before, the easier thing to do is to remove duplicate
code to a single, private, helper method. To do this, implement and use a
separate printLocationInfo() method in your Game class and replace the duplicate
code discussed above so that it refers to this helper method instead.
- [SIG2] When you have done this, show your code to a TA and have them
initial your Lab Sheet.
Stick Around and work...
You have some time now. Use this time to get started on
PA02 based on our feedback during
session 6.