Week 10

Note on static and dynamic type
Zuul

Variables (including Array & ArrayList components) have static type; objects have dynamic type.
Or, to phrase that the other way, the type of a variable is called static, because you can tell the type "statically", without running the program (the compiler can tell). The type of the contents is called dynamic because you have to run the program to identify it.

The type of any variable can be determined by the compiler, and all type-checking must be successful (with the understanding that a subclass value can be assigned to a base-class variable).

Until recently, the dynamic type of an object always matched the static type of the variable that held it. But now the dynamic type can be a subclass of the static type.

Another term for this is polymorphism: one variable (of one static type) can have "many forms": can hold any of several subclass types.

Changes to Zuul-better to create LockSerpent

  1. Add new rooms
  2. Move room declarations from being local to createRooms() to being fields in the Game class, so we can refer to them by name from anywhere in Game.java
  3. Add Room.setDescription, so a room description can be changed later (eg the steamTunnel)
  4. Create serpent_happy flag: should be in a room, but we can't do that! (Well, we could have steamtunnel.getSerpentHappy() return true or false, but that doesn't entirely help.)
  5. Add serpentCommand check to processCommand, ahead of others, so processCommand can still handle anything serpentCommand decides to pass on.
Violations of rules:

cohesion is not really doing well here. The concept is that one method should do "one thing", and we're really forced to address lots of little checks. (Note that one can argue that this is acceptable cohesion, though; it is all tied to command processing.)

responsibility-driven design is faring even worse: processCommand is dealing with too many things that should not be its responsibility.

Maybe the easiest problem to point to is coupling: we're trying to create a Room with special behavior, but we're having to put the code for that into class Game (where processCommand is)

Another way to look at coupling, which some people like to make a separate rule, is that it is important to avoid lots of if-statements that test for a specific object (eg if (currentRoom == steamTunnel) ... or if (theShape instanceof Rectangle) ...). Such code generally indicates


Zuul 3.0

We finally move responsibility to rooms.

Note processCommand() here: all the weird stuff is out, replaced with
    Room r = currentRoom.respond(command, inventory)

Look at Room.respond(Command c, ArrayList<Item> inventory), and goRoom() which it calls for the command GO. The basic strategy is that figuring out how to respond to a user command has been moved from the main class (Game) to the Room class.

Also look at subclass constructors!

Now look at how respond() works in LockedRoom and SerpentRoom.
Start with LockedRoom: note second field of constructor.
Note how LockedRoom.respond() does relatively little; it only handles room-specific situations. All other responses are passed back to super.respond().

What can go wrong? Well, it took a while to figure out how to handle GO, and in an earlier version I had the main loop distinguish between responses to GO and responses to all other commands, calling a different room method in each case. That proved unnecessary!

Another problem: what to do about inventory. It's a field that, in this version, belongs in Game. How do we access it within a special Room? We can't even add an accessor getInventory() to Game, because we don't have access to the Game object when we're in a Room class. Yet we need to access inventory just to do TAKE and DROP!

My solution: pass inventory as a parameter to Room.respond(). That way, room responses can take into account the player's inventory.

Try with GIVE COOKIE, and then after further exploring the basement, try GIVE GLOWING_DONUT

Examples from v 3.0

LockedRoom:
constructor has a lockedDir field
respond() just checks
        if (commandWord.equals("go")
            && direction.equals(locked_dir)
            && Game.findByName("key", inv) == null)

Note that all keys are the same here.

SerpentRoom:
No special constructor fields
GO: if (commandWord.equals("go")
            && !serpent_happy
            && object != null
            && object.equals("up"))

GIVE:
    note inventory checks
    note how we handle GIVEing different things
    note how we add the key or snake

TAKE SERPENT
    simple addition to get a better response than "You can't take that!"

Wednesday:

This monday: project 1
You will have extra time for this.

There is a partner option: if you wish, you can do the project with a partner. You'll have to do more (eg add three puzzle rooms instead of two).

ValveRoom (Version 3.1)
Note how we handle GO DOWN and TURN VALVE

Addition: require EAT COOKIE before you can TURN VALVE, and it must be the immediately preceding turn.

    turn valve:
       check state of hasEaten; if it's not true, say we're "too weak and hungry"
    hasEaten: set to false after every response
       trick: avoid all those inconvenient returns?
    eat cookie
       do we have the cookie?
       remove from inventory
       hasEaten = true;
    eat glowing_donut??
      

Note how we can sneak around "from behind" here!
Do we care about that?

How can we fix this?
How can we do this?



Zuul 4.2

    DarkRoom and the Flashlight
    DustyRoom
    ZooRoom
    DarkRoom
       Flashlight; Light generally
       Note that an Item can now have added attributes besides its name! Yet TAKE, DROP still work without changes.

Adding a Player class
Holds:
Note that isAlive would have to be checked in Game.java

What can we do with this approach to puzzles?
One limitation is the two-word command; we can't say
    UNLOCK CHEST WITH KEY
Would we ever need that?

Basic puzzle ideas:
Puzzles usually require us to have found a particular object / item. The item may suggest its use, such as the "cookie", and the valveroom hint "you are too weak and hungry".

Suggestions as to a particular verb should be built into the game. Ideally, the user should not be left groping with synonyms. Some game guides would list all possible verbs in the book.