CS1322 - Program 2: Its a zoo out there! =============================================================================== Assigned: Monday, September 18th, 2002 Due: Monday, September 30th, 2002 at 23:59:59 Stop Accepting: Tuesday, October 1st, 2002 at 08:00:00 Phase I Instant Feedback Deadline: Monday, September 23rd, 2002 at 23:59:59 Phase V Instant Feedback Deadline: Monday, September 30th, 2002 at 23:59:59 ======================================================================= TOPICS ======================================================================= Topics you should understand coming into this assignment: o Creation and usage of objects and methods o Iteration and Recursion o Arrays Topics that you should understand as a result of doing this assignment: o Inheritance o Interfaces o Polymorphism o Dynamic Binding o Linked Lists o Stacks/Queues o Constructor Chaining =============================================================================== Program Overview =============================================================================== In this program, you are going to be writing code for a zoo. This zoo has Animals of different types: Sharks, GoldFish, Gators, Birds, Ducks, and Bats. You will keep track of the Animals in various places via LinkedLists. ------------------------------------------------------------------------------- Phase 1: Your basic Animals *THIS IS AN INSTANT FEEDBACK PHASE* This phase should take you no more than 2 hours, 10 minutes to complete ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The first step is to make an abstract class Animal. This class should have the following variables and methods: public abstract boolean isDangerous(); public abstract void eat(String food); a private boolean called "isHungry" and appropriate accessor/modifier (setIsHungry/getIsHungry). a private String called "name" and appropriate accessor (No modifier). a .equals method which behaves as follows - if the parameter passed in is not an Animal, return false - if the parameter passed in has a different name return false - if one animal is dangerous and the other is not, return false - if one animal is hungry and the other is not, return false - otherwise, return true a constructor that takes in a name and sets the name variable from it, and should set isHungry to false. Next, you should make the following subclasses of Animal: o Fish, which is abstract - Fish have an private int depth, with appropriate accessor and modifier. Since fish cannot swim at a negative depth, anything less than 0 should be replaced by 0 in the modifier. - Fish have a .equals method which behaves as follows * if the parameter passed in is not a Fish, return false * call the super class's .equals method- if it returns false, then return false. * if the parameter passed in is at a different depth, return false * otherwise, return true - Fish have a constructor that takes a name and an initial depth. They should use super() to call the parent constructor with the name. o Gator, which is NOT abstract - Gators are dangerous, so implement the isDangerous() method appropriately. - The Gator should implement the eat method to compare the food passed in to "chicken", "beef", "pork", "human", and "mystery meat", and if it is one of those, setHungry to false. If the food is not acceptable, the Gator ignores it and does not change its isHungry status. - Gators have a private int depth, with appropriate accessor and modifier, however, Gators do not swim below 50 feet under the water- so if a value of more than 50 is passed to the modifier, it is set to 50. Unlike fish, Gators may come out of the water, so they can have a negative depth. (A gator at -5 feet under the water would be on the ground, 5 feet above the water). - Gators have a .equals method which behaves as follows * if the parameter passed in is not a Gator, return false * call the super class's .equals method- if it returns false, then return false. * if the parameter passed in is at a different depth, return false * otherwise, return true - Gators have a constructor that takes a name. The super constructor should be called with this name, and the depth should be set to 0. - Gators have a toString that returns the following: A Gator named at depth which is [hungry/not hungry]. For example, A Gator named Joe at depth 4 which is hungry. o Bird, which is NOT abstract - Some Birds are dangerous, others are not. Make a private instance variable "dangerous" which is a boolean. Implement isDangerous to return this value. There should be no modifier for this variable. - Birds have a "species" which is a String. This variable should have an accessor, but no modifier. - Birds have an "altitude", which is a private int. Make the variable, accessor, and modifier for altitude. - Birds have a constructor public Bird(String name, String species, boolean dangerous, int alt) which calls the super constructor and set the variables appropriately. - Birds have an eat method which checks if the parameter is "bird seed", and if so the bird eats it and becomes not hungry. - Birds have a toString() method that returns the following: A named at altitude that is [dangerous/not dangerous] and is [hungry/not hungry]. For example: A wren named Chirpy at altitude 50 that is dangerous and hungry. - Birds have a constructor public Bird(String name, String species,boolean dangerous) which chains to the other constructor with an altitude of 0. - Birds have a .equals method which behaves as follows: * if the parameter passed in is not a Bird, return false * call the super class's .equals method- if it returns false, then return false. * if the species or altitudes are not the same, return false. * otherwise, return true. At this point, you should have written 4 classes- Animal, Fish, Gator, and Bird. Since Animal and Fish are abstract, you cannot make instances of them directly, however, you should test Gator and Bird in main methods inside those classes prior to submitting for instant feedback. When you think that your code is ready for feedback, submit it as p2-phase1 on WebWork and get feedback. Reminder: Don't forget about "Add as Zip". Since this program will have several files to submit, you will want to use this feature. Zip your java files up, then select the zip file- choose "Add as Zip" instead of add. WebWork will upload the zip file, then unzip it. When it redisplays the page, it will list all of the java files that were inside the zip. Since you do not have to choose each file separately- this will save you time! ------------------------------------------------------------------------------- Phase 2: More animals! This phase should take you no longer than 3 hours, 30 minutes to complete. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ At this point, you should have made your Animal, Fish, Gator, and Bird classes working correctly from getting instant feedback on them- this should also mean that you are comfortable with - inheritance - abstract classes - .equals methods - toString methods Now you are going to write some more Animal types on your own. For each type, you will write the eat() method similarly to what was done before. You will simply be given a list of foods that the Animal will eat. o Bat is subclass of Animal - Bats eat "insects" - Bats are not dangerous [implement isDangerous() accordingly]. - Bats have an altitude, which is an int, with appropriate accessor and modifier methods. - A Bat is equal to another Object iff (if and only if) the other object is a Bat at the same altitude, and the super class's .equals returns true. - Bats have a toString() that returns the following: A Bat named at altitude that is [hungry/not hungry]. - Bats have a constructor public Bat(String name) which chains to the super constructor with their name. o Shark is a subclass of Fish - Sharks eat "human", "chicken", and "fish". - Sharks have a constructor that takes a name and an initial depth. They should use super() to call the parent constructor with both values. - Sharks are dangerous [implement isDangerous() accordingly]. - A Shark is equal to another Object iff the other Object is a Shark, and the superclass .equals returns true. - Sharks have a toString() that returns the following: A Shark named at depth that is [hungry/not hungry]. o GoldFish is a subclass of Fish - GoldFish eat "fish food" - GoldFish have a constructor that takes a name and an initial depth. They should use super() to call the parent constructor with both values. - GoldFish are not dangerous [implement isDangerous() accordingly]. - A GoldFish is equal to another Object iff the other Object is a GoldFish, and the superclass .equals returns true. - GoldFish have a toString() that returns the following: A GoldFish named at depth that is [hungry/not hungry]. o Duck is a subclass of Bird - Ducks use their inherited behavior to eat. - Ducks can also swim, so they have a depth below the water- the depth variable should be an int, with appropriate accessor and modifier [see next item]. - Ducks have a boolean to indicate whether they are swimming or flying. This boolean should be called "flying" and should have an accessor ONLY [called isFlying]. The modifier for setAltitude from the parent class should be overridden to - set flying to true - call the method in the parent class The modifier for depth should - set the depth appropriately - set flying to false - A Duck is equal to another Object iff the other Object is a Duck, the two Ducks are at the same depth, both are flying or both are swimming, and the super class's .equals returns true. - Ducks have a toString that depends on whether the duck is flying or swimming. o If the Duck is flying, the toString should simply call the super class's toString and return the value it returns. o If the Duck is swimming, the toString should return the following: A swimming duck named at depth that is [hungry/not hungry]. - Ducks have a constructor public Duck(String name) which chains to the super constructor and passes in the name, the species "Duck", false for dangerous. After calling the super constructor, setDepth should be used to set the depth to 0. At this point, you should have the following concrete [not abstract] classes which should each have test mains that completely test them: - Shark - GoldFish - Gator - Bird - Duck - Bat ------------------------------------------------------------------------------- Phase 3: Things that fly and things that swim- Interfaces This phase should take you no longer than 20 minutes to complete ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Did you notice that many of the Animals had method that were similar? Go back and look at which Animals can fly [have an altitude] and which Animals can swim [have a depth]. Flying Animals: Birds (includes Ducks) and Bats Swimming Animals: Fish (includes Sharks & GoldFish) Gators, and Ducks Wouldn't it be nice to have a type for things that can fly and a type for things that can swim? They all have common behaviors, so it seems logical. One idea would be to make some parent class- maybe have FlyingAnimal and SwimmingAnimal as abstract subclasses of Animal.... But what about the Ducks? We can only inherit from one class, and Ducks can both swim and fly! So we need interfaces. Interfaces are useful in situations where you want to have a type for "all things that can _________"- in this case, "all things that can fly" and "all things that can swim". Note that a class is an actual type of object. An interface is a type also, but it tends to be more for a category of types that can do similar things. So now we will create two interfaces: o The FlyingType interface should have two methods in it: public void setAltitude(int alt); public int getAltitude(); o The SwimmingType interface should have two methods in it: public void setDepth(int depth); public int getDepth(); Now, go back to Bird and Bat- declare them as implementing FlyingType. Then, go back to Fish, Gator, and Duck- declare each of them as implementing SwimmingType. Note that their subclasses automatically implement the interfaces since their parent classes do. By this time, you should have the following java files made: - Animal.java - Fish.java - Shark.java - GoldFish.java - Gator.java - Bird.java - Duck.java - Bat.java - FlyingType.java - SwimmingType.java ------------------------------------------------------------------------------- Phase 4: Making a LinkedList *THIS IS AN INSTANT FEEDBACK PHASE* This phase should not take you longer than 4 hours ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Now, we are going to move to something slightly different. We have spent the past three phases creating an inheritance structure for animals. Now we are going to make a LinkedList that we can use to hold things in a dynamic data structure. LinkedLists in java are slightly different from those in scheme, but they have some striking similarities. - First, you will need to create a class LLNode. o This class should have two instance variables: private Object data; private LLNode next; Each of these should have an appropriate accessor and modifier. o There should be three constructors public LLNode() //both next and data are initialized to null public LLNode(Object o) //next is initialized to null, data to o public LLNode(Object o, LLNode next) //both fields initialized from the //params o There should be a toString() method which simply returns the data's toString() For those of you who took scheme, this should sound quite similar to a cons cell. Cons cells had "first" and "rest", LLNodes have "data" and "next". - Now, create a class LinkedList. o This class should have two instance variables private LLNode head; private LLNode tail; head should always reference the front (first item) of the list tail should always reference the back (last item) of the list o There should be a default constructor which initializes both variables to null. o There should be a method public void addToFront(Object o) which puts o into a new LLNode and adds it to the front of the list. When this method returns, head should reference the LLNode containing o. Tail should reference this node iff it is the only node in the list. o There should be a method public void addToBack(Object o) which puts o into a new LLNode and adds it to the end of the list. When the method returns, tail should reference the LLNode containing o. Head should reference this node iff it is the only node in the list. o There should be a method public Object getFirst() which returns [without destroying] the first item in the list. This should return the data, not the node. o There should be a method public Object getLast() which returns [without destroying] the last item in the list. This should return the data, not the node. o There should be a method public Object removeFromFront() which removes and returns the first item in the list. This should return the data, not the node. o There should be a method public Object removeFromBack() which removes and returns the last item in the list. This should return the data, not the node. Note that for both removes methods, if the list becomes empty, both head and tail should be set to null. o The method public int size() which returns a count of the number of items in the list. o The method public Object[] asArray() which returns an array containing all of the items in the list in order. Element 0 of the array should have the data from the head of the list. o The .equals method should return true iff the lists are both the same length and the corresponding elements all are equal to each other according to their .equals methods. NOTE: THIS SHOULD NOT HAVE ANY SIDE EFFECTS ON THE LIST. Be VERY CAREFUL NOT TO DESTROY YOUR LIST. Also: Note that using Strings to compare the lists is NOT a valid approach. The LinkedList containing the String "1" and the LinkedList containing the Integer 1 are completely different, but have the same String representations. o The toString method should return a String that looks like [ first elem, second elem, third elem ] (where "first elem" "second elem" and "third elem" are the toString()s of the first, second, and third items in a three item list respectively..) There should be a "[", followed by the toString() of each data item in order, separated by commas, and ending with a "]". o The method public boolean contains(Object o) which returns true iff there is an Object in the list that .equals(o). Test your LinkedList and LLNode classes, then submit LLNode.java and LinkedList.java for instant feedback as p2-Phase4. ------------------------------------------------------------------------------- Phase 5: Aviaries and Aquariums. This phase should not take longer than 1.5 hours ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Now we are going to make Aviaries (places where flying things live) to hold our flying creatures, and Aquariums to hold our swimming creatures. In our zoo, Aviaries have a net which can be closed across the aviary at 75 feet up. It is safe to enter an aviary (to feed animals etc) iff the net is closed, and all dangerous animals are above it. It is safe to enter an Aquarium iff all dangerous animals are below 30 feet deep. Note that you may assume that only FlyingType Animals live in Aviaries, and only SwimmingType Animals live in Aquariums. - Make an abstract class ZooBuilding which has - public abstract boolean isSafeToEnter() - a private LinkedList called "theAnimals" - an accessor for theAnimals (no modifier) - a private String for name - an accessor for name (no modifier) - a constructor which takes in a name, sets the name variable to that name and initializes theAnimals to a new LinkedList. - public int getHungryAnimals() which returns a count of how many hungry animals are in the Zoo. - public void feedAnimals(String food) this method first checks if it is safe to enter the building. if it is not safe, this method should print "The building is unsafe to enter!" and then return. if it is safe, it should call make all Animals eat() the food passed in (some of them will not like it, but that is their choice) - Make a class Aviary which is a subclass of ZooBuilding and has - an instance variable (with accessors and modifiers) called netClosed which is a boolean. The accessor should be called getNetClosed and the modifier should be called setNetClosed. - the method public boolean isSafeToEnter() which returns true if the building is safe to enter, false if not- according to the criteria above. - a constructor which takes the name and chains to the super constructor - a toString() method which returns An Aviary named . - Make a class Aquarium which is a subclass of ZooBuilding and has - the method public boolean isSafeToEnter() which returns true if the building is safe to enter, false if not- according to the criteria above. - a constructor which takes the name and chains to the super constructor - a toString() method which returns An Aquarium named . Be sure to test your Aviary and Aquarium completely before proceeding to phase 6. ------------------------------------------------------------------------------- Phase 6: This phase should not take longer than 1 hour ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In this phase, you will be making a menu to control your program. Since we have not covered IO yet, most of this code is given to you. -> Open and look over Zoo.java <- Zoo.java contains a mostly complete implementation of the zoo menu. You only have to do a few things. Look for the places that say //***YOUR CODE GOES HERE*** (some number) These are where you will be adding code to this file. The directions below are numbered to match the numbers in those comments. 1. Use IOHelper.readLine() to read a line of input from the user. Store that line of input into the "line variable". 2. Print out the message "That is not a valid choice, try again" when the user's selection is not valid. 3. Replace the line int depth=0; with the appropriate line of code to get the depth from the current SwimmingType animal. 4. Add a line of code to set the depth of the current SwimmingType animal to be depth. 5. Add the Animal that the user created (toAdd) to the selected building (zb). 6. Prompt the user to select a building, then list all of the animals in the building by printing the toString() of its LinkedList of animals. When prompting for a building, find and use the method in Zoo specifically designed for that. 7. Use the food (food)that the user picked to feed the animals in the selected building (zb). 8. Print the menu (find the appropriate constant). 9. Fill in (and javadoc!) the method doMoveNet() so that it - prompts for a building number - checks if the building is an Aviary - if the building is not an Aviary, print "That building is not an Aviary, it has no net" - otherwise toggle (change true to false, false to true) the value of the netClosed on that aviary. 10. Add a case to the menu switch case statement to handle the choice for moving the net. Be sure to use the appropriate constant. ------------------------------------------------------------------------------ DON'T FORGET TO SUBMIT AS P2 SO YOUR ASSIGNMENT WILL BE GRADED. ALSO- DON'T FORGET TO PRACTICE "SAFE SUBMIT" Files to turnin for p2 [make a zip file and use "Add as Zip", since there are 17 files to submit- it will be much faster for you]. Animal.java Fish.java Shark.java GoldFish.java Gator.java Bird.java Bat.java Duck.java FlyingType.java SwimmingType.java LLNode.java LinkedList.java ZooBuilding.java Aquarium.java Aviary.java Zoo.java IOHelper.java [any other files needed to make your submission compile and run]