Lab 3 - Star Trek


CS2390 - Lab 3 - Star Trek

fed_logo picture title picture


The Story

Captain Picard and Commander Riker are on a diplomatic mission to discuss the possibility of the Smoltoks joining the Federation. The Smoltoks have sent two representatives (Coad and Nicola) to meet Picard and Riker. The Smoltoks are an unusual race in that they have an elaborate protocol for sitting down before an important meeting. This protocol is discussed in more detail below. Naturally, Picard and Riker have been trained in the protocol.

OOA

Well, the most obvious candidates for classes are the people: the Humans and the Smoltoks. Picard, Riker, Coad, and Nicola will be instances of their respective classes. What sort of variables/methods will we want? Well, Humans have a name and a rank, like "Captain". Should we make Captain a subclass of Human? Or maybe we should have another class called StarfleetOfficer? So what happens if Picard is an instance of the Captain class and he gets promoted to Admiral? Now Picard is in the wrong part of the class hierarchy. Do we make an new Picard derived from Admiral and destroy the old Picard? That doesn't seem right. We can't go changing the class hierarchy every time someone is promoted. A person's rank must be just a variable--a temporary classification--let's not make it subclass. You can make a similar argument for a person's job (i.e. StarfleetOfficer). A person's job doesn't really matter for the situation we've been given, so let's just leave it out entirely.

So far we've got name and rank for a Human. But wait--Smoltoks also have a name and rank. Let's make a superclass called Lifeform for their commonalities. Hey - what if we just made everything an instance of Lifeform? Do we really need separate classes for Humans and Smoltoks? What if we just had a variable for race? There is at least one major difference: their protocol for offering their chair to someone else. The rules are:

We could handle this by just testing the race variable in the offerChair method. [This is a classic dilemma in OOA/OOD: test variable vs. separate class.] I'm going to argue here that separate classes make more sense. Even though this is the only difference I can think of right now, I've got a feeling that there could be others. Also, it makes it easier to add other races (i.e. Klingon) later if necessary.

We're going to have to compare ranks at some point and Humans and Smoltoks don't use the same ranking system. Let's also store some numeric representation of the rank to make things easier to compare. (Should rank be a class with two variables: name and index? I think you can make a reasonable argument either way. I'm going to say no, for simplicity's sake.)

Are there any other classes needed? Well, we could make a Chair class. Yes, I think we're going to need that so that we can tell who is in what chair and what chairs are empty. Consider the alternative: a variable in each lifeform that tells what number chair they are in. How do we represent empty chairs? Does a chair only exist once someone sits in it? No, chairs should definitely be objects.

Let's try to formalize this a little more by doing some object scripts:

Lifeform
I am a lifeform. I know my name and can set my name. I know my rank and can set my rank. I can say things to other lifeforms or just say them out loud to no one in particular. I can also sit down in a chair or get up. I can only get up if I am sitting down. Before I sit down, I must get up. If I am sitting down, I can offer my chair to someone else. If I am sitting down, I know what chair I am siting in.
Human
I am a human. I can do everything a lifeform can do, but I only offer my chair to higher ranking officers.
Smoltok
I am a smoltok. I can do everything a lifeform can do, but I only offer my chair to humans or to higher ranking smoltoks.
Chair
I am a chair. I know my number which distinguished me from other chairs. I know if I am occupied or not. If I am occupied, I know who my occupant is. I can also set my occupant. I can report the name of my occupant.

Which gives us the diagram:

lab3 picture

Two important things to note in the above diagram. First, the Lifeform class is shown as an abstract class. We will not create any instances of Lifeforms. In the Lifeform class there is shown a offerChairTo: method which is abstract. Any subclass of Lifeform (Human and Smoltok in our example) must implement its own version of offerChairTo:

Secondly, we will almost certainly need an initialize method in both Human and Smoltok classes. The rule of thumb is that initialize methods are not generally shown on the OOA class diagrams, but they're necessary at OOD time.

OOD

Now, in more detail:

Lifeform
I am a lifeform. I have the instance variable name that I access with the methods name and name:. I also have the instance variables rankString which contains the name of my rank and rankIndex which is a numeric representation of my rank. The most highly ranked officers will have rankIndex = 1, so a higher rank is indicated by a lower number. I have an initialize method that takes my name, rankString, and rankIndex. I can speak (i.e. write to the Transcript) with the method say: (in the format "[my name]:[my words]" (see the sample output)) or I can speak to someone with say:to: (in the format "[my name]:[my words],[listener's name]"). I have a variable chair which holds a reference to the chair I am currently sitting in. If I'm not sitting, it holds "nil". I have a method offerChairTo: which doesn't do anything--It's just a place holder for more specific methods in subclasses. I have a method getUp which removes the reference from me to the chair and tells the chair that it is no longer occupied. It returns this empty chair. Finally, I have a method sitDown: which takes a chair as an argument. If I am already sitting down, I must first get up. Then I check if the chair is already occupied. If it is, I apologize for trying to sit on the occupant. If it is not, I sit in the chair and tell the chair that I am its occupant.
Human
I am a human. I implement the method offerChairTo:. First, I make sure I am currently in a chair. If I'm not, I apologize for offering a chair I do not have. Next, I compare my rank to the rank of the person I'm offering to. If I outrank them, I tell them to find another chair. If they outrank me, I offer my chair, get up, and tell the other lifeform to sit down.
Smoltok
I am a smoltok. I also implement the method offerChairTo: but with a slight difference. If the lifeform I'm offering it to is human, I don't have to check their rank--I offer my chair to all humans. (The way to test if a lifeform is human is:
(aLifeform isMemberOf: Human)
  ifTrue:[ ...your code...] ifFalse: [ ...your code... ]. 
This evaluates ifTrue if aLifeform is an instance of Human and ifFalse: otherwise.)
Chair
I am a chair. I have an instance variable number which is set when I am initialized. I have another instance variable, occupant which is a reference to the lifeform currently sitting on me. If I am empty, occupant is set to nil. Note that this variable does not contain the name of the lifeform, but the whole lifeform. I have a method occupied which returns true if I have an occupant and false otherwise. I have a method showOccupant which prints to the Transcript in the format: "Chair[number]: [name of occupant]".

OOP

This is your part. The OOA/OOD above does not contain every detail of what you need to do, but it's pretty close. Here's a set of commands to test your code.

|picard riker coad nicola chair1 chair2 chair3 chair4 |
riker := Human new initialize: 'Riker' rankString: 'Commander' rankIndex: 2.
picard := Human new initialize: 'Picard' rankString: 'Captain' rankIndex: 1.
chair1 := Chair new initialize:1.
chair2 := Chair new initialize:2.
chair3 := Chair new initialize:3.
chair4 := Chair new initialize:4.
riker sitDown: chair1.
riker offerChairTo: picard.
riker sitDown: chair1.
picard offerChairTo: riker.
riker sitDown: chair2.
chair1 showOccupant.
chair2 showOccupant.
coad := Smoltok new initialize: 'Coad' rankString: 'Alpha' rankIndex: 1.
nicola:= Smoltok new initialize: 'Nicola' rankString: 'Gamma' rankIndex: 3.
nicola sitDown: chair3.
nicola offerChairTo: coad.
coad offerChairTo: riker.
nicola sitDown: chair3.
nicola sitDown: chair4.
nicola offerChairTo: picard.
nicola offerChairTo: riker.
coad sitDown: chair2.
coad offerChairTo: nicola.
nicola sitDown: chair1.
chair1 showOccupant.
chair2 showOccupant.
chair3 showOccupant.
chair4 showOccupant.

If all is working correctly, you should get the following on the transcript:

Riker: It feels good to sit down.
Riker: Please take my chair, Captain Picard
Picard: It feels good to sit down.
Riker: Sorry for sitting on you, Captain Picard
Picard: Find another chair, Commander Riker
Riker: It feels good to sit down.
Chair1: Picard
Chair2: Riker
Nicola: It feels good to sit down.
Nicola: Please take my chair, Alpha Coad
Coad: It feels good to sit down.
Coad: Please take my chair, Commander Riker
Riker: It feels good to sit down.
Nicola: Sorry for sitting on you, Commander Riker
Nicola: It feels good to sit down.
Nicola: Please take my chair, Captain Picard
Picard: It feels good to sit down.
Nicola: Oops, I'm not sitting down yet.
Coad: It feels good to sit down.
Coad: Find another chair, Gamma Nicola
Nicola: It feels good to sit down.
Chair1: Nicola
Chair2: Coad
Chair3: Riker
Chair4: Picard

Debugging hint: use the "chair showOccupant." method to help you check who is in the chairs at various points.

What to Do

Create a new category in the leftmost pane of the smalltalk browser called StarTrek. Then create the new classes (Chair, Lifeform, Human and Smoltok) you need in the StarTrek category. Create the methods previously discussed in each of the classes and test your code with the above test script (Hint, you don't need to re-type this test code, you can just cut and paste it from the Netscape window).

 

Turning In

FileOut the entire StarTrek category. If you do this correctly, you should end up with a StarTrek.st file in you current directory. Send the StarTrek.st file to your TA by using the mail command.


cat
yourfile.st |elm -s "TI,Lab3,<your studentNumber>" cs2390@prism.gatech.edu

For example:


cat
StarTrek.st |elm -s "TI,Lab3,420701234" cs2390@prism.gatech.edu

For more information on turning in code, look at the Lab FAQ.

When you are done, EXIT FROM VISUALWORKS! It's very important that you explicitly exit from VisualWorks, using the File menu. Also, be sure NOT to Save, just Exit.


News Page | CS2390 Sum'97 Home Page | MMC-CaMILE | STABLE
Questions/comments/concerns to guzdial@cc.gatech.edu
Page last updated 7/10/97; 11:44:06 AM