程序代写代做代考 Java PSA 5: Inheritance and Critter Simulation – Google 文档

PSA 5: Inheritance and Critter Simulation – Google 文档

PSA 5: Inheritance and Critter Simulation 
 

In this programming and problem-solving assignment, you will write several lineages of Critters and test                             
your gameplay strategy by designing your own Critter for a head-to-head combat in a tournament. The                               
rules are generally simple, but there are some nuances to the rules. Your strategies can be highly                                 
complex. You will learn both a new object-oriented design paradigm using inheritance as well as entering                               
challenges against both our provided and your classmates’ Critters.  

The code you will write will have effects that can be seen mostly visually. Therefore, the action of testing                                     
out your programs will be running the simulation and observing the behaviors. In addition to writing five                                 
classes to our specifications, you will implement one more Critter . You will iteratively improve its                               
strengths in order to beat the four aptly named Critters and a Mystery Critter. The implementation of                                 
Mystery will be hidden from you. Finally, your Critter can be entered into a several-thousand Critter                               
competition with your classmates to see whose Critter will come out the strongest and luckiest. The top                                 
30 winners of the competition will receive a 3D printed sculpture of an animal. The developers who rank                                   
top ten will receive special Critters! Below is a subset of the critters you could win: 

 

For this assignment, there is no special need to think of edge cases as the program is already written for                                       
you. The program IS the simulation! If your Critter works for the program on your computer, it will work                                     
for ours.  

Thank you, to the developers of Critters. The original version of Critters was developed at the University                                 
of Washington by Stuart Reges and Marty Stepp.  

Follow the code of academic integrity. May everyone enjoy this assignment and compete in a fair game.  

 

Link to starter codes: here 

 

Helpful Information:  

● Online Communication: Using Piazza, Opening Regrade Requests 
● Getting Help from Tutor, TA, and Professor’s Hours 

○ Lab and Office Hours (Always refer to this calendar before posting.) 
● Academic Integrity: What You Can and Can’t Do in CSE 8B 
● Setting Up the PSA  
● How to Use Vim  
● Style Guidelines 
● Submitting on Vocareum and Grading Guidelines 

 

Table of Contents: 

 
The Arena 

The Assignment 

Part 1: Getting to Know the Critter Family [15 Points] 

Part 2: Completing the Critter Family [45 Points] 

Part 3: Inheritance Concepts [10 Points] 

Part 4: Your Critter [20 Points] 

Part 4.1: Your Critter, with Thousands of Others 

Part 5: Command Questions and Program Descriptions [10 Points] 

Part 6: Dragon [+10 EC Points] 

Submission and Grading 
 

 

   

The Arena 
Several classes in the starter code implement a graphical simulation of a 2D world with many animal                                 
moving around in it. You will write a set of classes that define the behavior of these animals. As you write                                         
each class, you are defining the unique behaviors for each animal. You will also notice that there may be                                     
similarities between animals of closer family relations, such as the Turtle and GreenTurtle. The Critter                             
World is divided into cells with integer coordinates. The world is 60 cells wide and 50 cells tall by default.                                       
The upper-left cell has coordinates (0, 0). The x coordinate increases to the right. The y coordinate                                 
increases downwards.  

 

Movement 

On each round of the simulation, the simulator asks each Critter object which direction it wants to move                                   
by calling its getMove method. Each round a Critter can move one square north, south, east, west, OR                                   
stay at its current location (i.e. center). The world has a finite size, but it wraps around in all four                                       
directions (for example, moving east from the right edge brings you back to the left edge). It might be                                     
tempting to allow your critters to make several moves at once using a loop, but you can’t. The only way                                       
a critter moves is to wait for the simulator to ask it for a single move and return that move. 

Fighting 

As the simulation runs, animals may collide by moving onto the same location. When two animals                               
collide, if they are from different species, they fight. The winning animal survives and the losing animal is                                   
removed from the game. Each animal chooses one of Attack.ROAR, Attack.POUNCE, or                       
Attack.SCRATCH as their attack mode. Each attack is 96% strong against one other attack (e.g. roar                               
beats scratch) and weak against another (roar loses to pounce). This means that scratch will beat roar                                 

4% of the time. In addition to considering the attacks of each animal, you need to account for the 4%                                       

off-chance that the attack will backfire. It is not a large amount, but just remember its existence. 

The following table summarizes the choices and which animal will win in each case. To remember which                                 

beats which, notice that the starting letters of “Roar, Pounce, Scratch” match those of “Rock, Paper,                               

Scissors.” If the animals make the same choice, the winner is chosen at complete random. 

The relationship of different attack actions are listed in the following table. Keep in mind that there is                                   

96% chance involved if there is a clear winner. We didn’t put this information in the table. 

      Critter #2   

    ROAR  POUNCE  SCRATCH 

  ROAR  random (50% chance)  #2   #1  

Critter #1  POUNCE  #1   random (50% chance)  #2  

  SCRATCH  #2   #1   random (50% chance) 

 

Mating 

If two animals of the same species collide, they “mate” to produce a baby. Animals are vulnerable to                                   

attack while mating: any other animal that collides with them will defeat them. An animal can mate only                                   

once during its lifetime. The “baby” will be a full adult by birth and will spawn next to the parent critters                                         

when they finish mating. 

Eating 

The simulation world also contains food (represented by the period character, “.”) for the animals to eat.                                 

There are pieces of food on the world initially, and new food slowly grows into the world over time. As an                                         

animal moves, it may encounter food, in which case the simulator will ask your animal whether it wants                                   

to eat it. Different kinds of animals have different eating behavior; some always eat, and others only eat                                   

under certain conditions. Once an animal has eaten a few pieces of food, that animal will be put to                                     

“sleep” by the simulator for a small amount of time. During the sleeping period the animal will                                 

automatically forfeit all fights, meaning it will lose to all other critters that attack it. 

Scoring 

The simulator keeps a score for each class of animal, shown on the right side of the screen. A class’s                                       

score is based on how many animals of that class are alive, how much food they have eaten, and how                                       

many other animals they have defeated.   

The Assignment 
Each class you write in this section will inherit from a superclass, and may be inherited by a subclass.                                     

We take advantage of inheritance in two ways: since subclasses automatically inherit methods from their                             

superclass, if we want a certain method to be uniform across a family of classes, we can simply define                                     

the method in the superclass. All related subclasses will inherit that method. If we want to change that                                   

behavior for all, then we only need to change the method that was defined once. Define for one, define                                     

for all. The other way we take advantage of inheritance is that we do not have to type as much code.                                         

This reduces the possibility of error. Inheritance provides the programmer assistance in streamlining the                           

code writing process. Define for one, define for all. 

You are provided with a UML diagram of the Critter family tree in Part 1 of the assignment. In this                                       

diagram, we tell you in addition to what bloodline that the Critters have, which classes are provided,                                 

which classes you do not need to edit, and which classes require you to write the file from scratch.  

First, look at the Critter.java class. It contains helpful documentation from various previous writers of the                               

Critter class and may prove very useful to knowing what each method does, which ones are provided,                                 

and which ones you might be working on. This class is an abstract class.  

Just by defining a class to “extends Critter”, you receive a default version of the methods defined in                                   

Critters.java. Look inside the file to see what the default behaviors are for each of the following methods:                                   

eat, fight, getColor, getMove, and toString. If you don’t want this default behavior, you will then override                                 

the inherited methods in your class through your own definition of the method. The method will have the                                   

exact same signature and return type, but your own implementation will be used over the inherited one.                                 

Here is an example of a class that inherits from Critter.  

import   java.awt.*;  

public   class   Stone   extends   Critter   { 

 

@Override /*   You   MUST   use   @Override   for   every   method   you   override.   We  

require   it   because   it   introduces   you   to   using   annotations   and 

ensures   that   you   will   correctly   override   methods!   */ 

 

public   Attack   fight   (String   opponent)   { 

return   Attack.ROAR; 

 

@Override 

public   Color   getColor   ()   { 

return   Color.GRAY; 

 

@Override 

public   String   toString()   { 

return   “S”;  

//This   double   quote   may   not   compile   correctly   if   you   copy   it   into   Java. 

Running the Simulator 
The steps to getting the simulator running are slightly longer than 2048’s steps. First, compile all                               
necessary classes. You can compile separately if needed, but javac *.java is most convenient. A large                               
number of new class files will show up in your folder and you may see “uses or overrides a deprecated                                       
API” but don’t worry about them. Next, run the simulator with java CritterMain . You will see the                                 
following screen. You can enable “Debug output” which will print debug messages to your terminal. You                               
can enable various Critters. 

 

You may see some warnings of deprecated APIs when you run the simulator. You can ignore these 
warnings.  

You have many options in the next screen. You can adjust the speed of the simulator. When you press                                     
Go, the simulation will take off and run. You can Stop the simulation. For visual testing, you can click                                     
Tick, which will run one round of the simulation. If you would like to see debug messages on your                                     
terminal as your simulation runs, enable “Debug”. 

 

Accounting for Randomness 

As you begin to implement your code, you will notice that there is a large presence of randomness 
involved. To match our code, each Critter that will use randomness will have its constructor initialize its 
random variable. With random related code, you can only use the following two methods: 

● Random’s one-argument constructor: Random(long seed) 
● Random’s nextInt method: nextInt( int bound ) 

 

Part 1: Getting to Know the Critter Family [15 Points] 
This portion introduces you to writing classes with inheritance. If you have not read the Critter.java file,                                 
do so now. Critter is the abstract class from which all subclasses will be derived, directly or indirectly.                                   
This file will also contain enums that are important for you to use in the following tasks. There are five                                       
classes in total you will work on, hence there will be five classes you will write with style. See the UML                                         
diagram on the next page for a graph of the family. Note that Critter is an abstract class though it                                       
doesn’t have any abstract method. We didn’t list instance variables in the UML. The general rule is you                                   
should appropriately define instance variables that the specification requires. You can have additional                         
instance variables if needed for all the class that you implement. 

 

Inheriting from Critter 

Next, take a look at HappyAnimal.java, which is a provided class that you do not need to edit. Its                                     

functions are incomplete though. So what would happen if you instantiated HappyAnimals on the                           

simulation? Try it now by compiling and run the simulation on HappyAnimal. You don’t have to modify                                 

the HappyAnimals class for this PSA.  

By writing a HappyAnimal class, we can define a subset of Critters that are “happy”. The subclasses of                                   

HappyAnimal will inherit its characteristics, and you will have the choice of overriding any of those                               

characteristics.  

Your turn. You will implement a class that is parallel to the HappyAnimal: the SadAnimal class                               
(SadAnimal.java in the starter code). SadAnimal is a partially implemented Critter whose behavior can be                             
seen in the simulation as incomplete. Notice that there is already a provided class that extends                               
SadAnimal – the Omnivore. The methods you write in SadAnimal will not only be affecting                             
SadAnimal.java, but also all subclasses that choose to extends SadAnimal but chooses to not override                             
the methods. Because of this, writing code for SadAnimal is very important to get right. The definition                                 
will affect many other classes! 

SadAnimal class 

● Instance variables: The SadAnimal knows the following things: a String that it will use to                             
identify itself, a Color it will display itself with, a boolean to know whether it has eaten yet, a                                     
Random object when it needs to be able to make arbitrary decisions or some other purpose, and                                 
an int by which the SadAnimal or its descendants will count. All these fields should be                               
protected. Again, you should define these variables appropriately, and you can have more                         
instance variables if you think they are necessary. 

● No-arg constructor: Instantiate all instance variables except the Random and count variables.                       
You will notice that SadAnimal in particular did not have a use for Random or count but its                                   
subclasses might. The boolean indicator variable should be initialized as false, the color should                           
be red, and the name of the SadAnimal is the three character String: “:-(”.   

● Override getMove method: SadAnimal has the ability to move but it is only able to alternate                               
between moving south, or west. By default, it will always move west first, and then when it eats,                                   
it changes direction to south. When it eats again, it will go west, and the pattern continues. If                                   
the World runs out of food, it’s stuck going in one direction!   

● Override eat method: When presented with food, SadAnimal will always eat.  
● Override getColor method: Return the color field. Don’t return red directly as a hard-coded                           

color. Make sure you return the field.  
● Override toString method: Return the string field. Similarly like the getColor method, don’t                         

return the hardcoded name. Return the correct field. 

Inheriting from Classes that Inherited from Critter 

Now that you have finished implementing SadAnimal, we will move one level lower. The Sloth is a fully                                   
implemented animal! Be careful though, that does not mean that Sloth overrides all the methods it                               
inherited from HappyAnimal; it means simply that all the functions will have some kind of                             
implementation, simple or hard, and inherited or overridden. Also, remember that the Sloth inherits                           
instance variables from its superclasses too.  

Sloth class 

● Instance Variables: Specific to the Sloth, it is very important to remember whether it has eaten                               
previously, and whether it moved north. You should design how many instance variables you                           
need and their types. The goal is to make sure your methods work correctly with the help                                 
from these instance variables. All instance variables should be protected. 

● Constructor: Notice that Sloth inherited the “random” reference variable from HappyAnimal.                     
Sloth will instantiate a new Random with the seed 2048, and assign this new instance to that                                 
inherited reference variable. Upon birth, Sloths are named “S”, know that they have not yet eaten                               
previously, and intuitively decide to move north first.  

● Override eat method: Sloth loves to eat. When encountering food, the Sloth will have only 95%                               
chance of eating that food. If the Sloth did choose to eat the food, the next time the Sloth                                     
encounters food, it will have a 96% chance of eating it. Otherwise, it will just remain 95%. If the                                     
Sloth had a 96% chance of eating, but did not eat, then it will return back down to 95%. If it                                         
does eat, it remains at 96%.  

● Override fight method: 10% chance of roar and 90% chance of scratch.  
● Override getMove method: The Sloth will alternate in moving north and east, starting with north                             

when it is first born.  
● Override sleep and wakeup methods: Sloth’s identity is an “S” whenever it wakes up, but                             

whenever it sleeps, it will appear to other Critters as “Zzz”.  

Now, let’s look at the Omnivore, which extends from SadAnimal that you implemented. Notice that this is                                 
not a particular animal! Although the Sloth is a fully implemented animal inherited from HappyAnimal, we                               
do not necessarily need to have the same rate of implementation completeness going down the                             
inheritance family. We fully implemented Sloth extending from HappyAnimal because we could. But we                           
can also implement a slightly complete, but not fully complete, animal from SadAnimal, because we                             
can.  

Part 2: Completing the Critter Family [45 Points] 
This part continues directly from Part 1. In this section, you will define Critter classes from scratch, and                                   
then override certain methods inherited from Critter, SadAnimal, and Omnivore. In addition, there will be                             
certain new methods that will be implemented as part of the three classes you will implement. There will                                   
be two lineages that inherit from the Omnivore: Turtle and GreenTurtle, and Leopard.   

Let’s implement the Leopard first. The Leopard is the last subclass in its lineage, which goes Critter →                                   
SadAnimal → Onnivore → Leopard. The Leopard inherits from Omnivore, which is a provided file, but                               
has inherited some fields from SadAnimal which you implemented. So, while some fields inherited from                             
Omnivore were inherited directly, others were inherited from SadAnimals. The Leopard has one unique                           
instance variable that needs to be implemented, which results in a more unique behavior for eat and                                 
fight.  

Leopard Class 

● Instance variables: Each Leopard, in addition to the instance variables inherited from its                         
superclasses, will all telepathically keep track of their confidence together. The confidence starts                         
at 10 when the simulation starts. When the confidence of one Leopard is affected, All Leopard’s                               
confidence will be affected in the exact same way. (Hint: What type of modifier can you apply to                                   
a variable to make that variable shared across all instances?)   

● No-arg constructor: Initialize the variable count (inherited from SadAnimal). The value you use                         
is up to you though it will be wise to see how you might need to use count in the getMove                                         
method. Leopards’ random will initialize with a seed of 2017. Additionally, the Leopards’                         
self-identity as “Li” and are orange.  

● Override win and lose method: If a Leopard wins a fight, all Leopards’ confidence will                             
increment if their confidence is less than 10. If a Leopard loses, all Leopards will reduce their                                 
confidence by 1 if their confidence is greater than zero. The minimum confidence they have is 0,                                 
and the maximum is 10. (Think: where do these two methods come from?) 

10 

● Override getMove method: The Leopard will move south five times, west five times, north five                             
times, and eas five times, prowling around this square motion for the remainder of its life.                               
Leopard remembers this by using its inherited memory to incrementally count.  

● Override eat method: The Leopards will always have (confidence * 10)% chance of eating. If                             
confidence is at 2, then there is a 20% chance of eating.  

● Override fight method: When fighting, if the opponent is the Omnivore class (NOT a subclass of                               
Omnivore) OR when all Leopards have a confidence HIGHER than 5, then the Leopard will                             
scratch. Else if all the Leopards have a confidence less than 2, they are too scared to attack and                                     
forfeit. Otherwise the Leopard will roar.  

The Turtle starts a lineage that diverges from Leopard. The Turtle extends from Omnivore and is in                                 
general slow and indecisive. The Turtle often likes to think about what attack it will use, and so it makes                                       
a decision not only when it is about to fight, but also after a fight and when it encounters food. Turtles                                         
are able to walk in one directly only, and gets tired easily so it always waits two times before moving                                       
again. The Turtle is thoughtful, but slow and indecisive.  

Turtle Class 

● Instance Variables: an Attack type reference and any other instance variables you may need.  
● No-arg constructor: Self-identifies as “Tu” and is color cyan. Initialize count to the value you                             

choose, and the random will instantiate with a seed of 8.  
● New method to decide attack – generateAttack(): Turtle will often think about what attack it                             

wants to use next, and this method sets the attack mode of turtle (i.e. change the attack field of                                     
Turtle). This method will randomly set with equal chance between all three non-forfeiting attacks.                           
The Turtle will decide its attack mode in three different scenarios (i.e. call this generateAttack                             
method): (1) when it wins a fight, (2) when it eats, and (3) right before it fights. The thought                                     
process is the same in all of these actions. Be careful with this description, as it affects more                                   
than one method. 

● Override getMove method: Turtle will stand still two times, and then move north, repeating this                             
pattern for the duration of the simulation. You can use the inherited count variable to keep track                                 
of the pattern. 

● Override fight method: The Turtle will decide what attack to use one more time right before the                                 
fight. Then return the attack field.  

● Override win method: Upon winning a fight, Turtle decides a new attack.  
● Override eat method: The Turtle will never eat, but upon encountering food, the Turtle decides a                               

new attack. 

Next, the GreenTurtle, which should extends from Turtle. GreenTurtle is even more thoughtful than                           
Turtle. It not only thinks about what attack is should do next, but also which direction to move.                                   
GreenTurtle always moves in some direction, and is decisive on what attack it should do. GreenTurtle                               
goes through various thoughts upon doing various actions as described below. In short, although                           
GreenTurtle is indecisive about which direction to move, it is decisive on its attack, fast, and versatile. 

GreenTurtle Class 

● Instance Variables: should remember the next intended Direction to take. You can design any                           
other fields that deem appropriate. (Think: Why did we intentionally leave out the information                           
that GreenTurtle should be able to remember what attack it wants to use? ) 

11 

● No-arg constructor: self-identity is “G” and is green. Random seed is 9. Right after it is born, it                                   
has a natural sense of direction to know it should go north first. It will be able to start counting                                       

from a value you set. (Where did the count instance variable come from?) It will also make the                                   

initial choice to roar. 

● New method to deciding the move – generateMove(): the GreenTurtle will randomly choose                         
between the four non-center directions with equal probability. It will go through this thought                           

process (i.e. call the generateMove method) if it wins a fight, right before it moves, and when it                                   

eats. Since the GreenTurtle eats only three times, there will be only three times when GreenTurtle                               

thinks of its next move while eating. This method shouldn’t take any parameter.  

● Override generateAttack() method: The GreenTurtle will go through the thought process of                       
choosing its next Attack when it mates, when it fights, and when it wins a fight. GreenTurtle will                                   

have a 10% chance to decide to roar and 90% chance of deciding to scratch.  

● Override eat method: GreenTurtle will eat three times and then never eats again. This means                             
that there is only three times where encountering food will cause the GreenTurtle decide its next                               

direction. You should use the inherited count variable to keep track of it. 

● Override fight method: The first thing GreenTurtle does is decide again what attack to use.                             
THEN, if and only if the opponent is Sloth, the GreenTurtle will roar. BUT, if the Sloth is