CS 261 Homework 2 - Ants vs. Some Bees
Due Wed Sep 24 at 11:59pm
The bees are coming! Defend the colony with inherit-ants!
Overview
In this assignment, you will create a tower defense called Ants vs. Some Bees (inspired by the PopCap game Plants vs. Zombies). In this game, you control the Ant Queen, populating your colony with the bravest ants you can muster. Your ants must protect their queen from the evil bees that invade your territory. Irritate the bees enough by throwing leaves at them, and they will be vanquished. Fail to pester the airborne intruders adequately, and your queen will succumb to the bees' wrath.
To implement this game, you will be taking advantage of Object-Oriented Programmning, using inheritance and polymorphism to easily create the program and avoid code duplication. Furthermore, this assignment will give you a chance to practice reading, understanding, and working with a large existing project.
This assignment should be completed individually. You are welcome to ask for help from me, or from your classmates (following the Gilligan's Island rule)!
Objectives
- To practice with inheritance and polymorphism
- To practice understanding and modifying existing code
Necessary Files
You will need to download the cs261-hwk2.zip file.
This zip file contains a large number of Java files, which together implement the basic game engine. You will need to import these files into Eclipse.
-
The zip file also contains a couple of additional files. The
imgfolder contains icons and images for the ants, and theants.propertiesfile contains information about which picture goes with which ant (this is a good example of using an external file to store information, which enables reuse and modification of the program without needing to change or recompile the code). You will need to put these files in the top level directory of your Eclipse project, so that it looks something like this:
(notice how the imgfolder andantlist.propertiesfile are below the "Hwk2" directory, not in the src folder?)
The Game
You can run the program by running the main method in the AntsVsSomeBees.java class. You should see something like this:
(the blue comments are notes about how to play).
This is a fully working copy of the game! You are able to place ants and try and defend your queen against the bees. (In the starter code, ants don't cost any food).
The game is made up of a couple of components:
-
Colony:
The ants live in a colony--a set of tunnels, each of which is represented by a number
Placeobject. The colony has a stock of food which is used to breed more ants. Only one ant can occupy each Place (each spot in the tunnel), but there is no limit to how many bees can swarm in! -
Ants: Creating a new ant uses up some of the colony's food--a different amount for each ant. Each type of ant takes a different action. The two most basic ant types are the
HarvesterAnt, which will add one food to the colony during each turn, and theThrowerAnt, which throws a leaf at a bee each turn. - Bees: The bees will fly down the tunnels towards the queen (who lives off to the left). If an ant blocks its path, the bee will stop and sting the ant.
A game of Ants Vs. Some Bees consists of a series of turns. In each turn, new bees may enter the ant colony (you can deploy new ants at any time). Then all insects (ants, then bees) take individual actions: bees sting ants, and ants throw leaves at bees. The game ends either when a bee reaches the ant queen (you lose), or the entire bee flotilla has been vanquished (you win).
The Code
There are a lot of classes used to implement this game: as with any good object-oriented program, each concept in the game ends up having a class to represent it.
-
The
AntColonyclass represents the ant colony. This class enapsulates the locations in the colony, with a public interface that allows limited access to those locations. Locations are represented with thePlaceclass, which abstracts a single spot in a tunnel and the insects that reside there. TheHiveis a subclass ofPlace; it has extra variables and methods for tracking when the bees will invade. -
The insects themselves are represented by the
Insectclass, which is subclassed to representAnts andBees. All insects have a location (aPlace) and an armor value, as well as anaction()method that represents what that insect does on its turn. TheAntclass is further subclassed to represent different types of ants, each of which will have their own variables and actions. Note that two basic subclasses,HarvesterAntandThrowerAntare provided for you so that the game can run and to get you started. -
The game itself is controlled entirely through the
AntGameclass. This (overly) large is at its core aJPanelon which the bees and ants are drawn; it also has aTimerthat repeatedly draws new frames of the animation and causes the game to progress. -
Finally, you can run the game via the
AntsVsSomeBeesclass, which contains the main method. This method instantiates anAntColony(check that class' JavaDoc for parameter details) for the game, aHivefor the game, and then starts the game. Some options you might use when playing games:AntColony colony = new AntColony(1, 8, 0, 2); //is the default testing layout (one tunnel)AntColony colony = new AntColony(1, 8, 0, 10); //testing layout with 10 foodAntColony colony = new AntColony(3, 8, 0, 2); //makes a full tunnel layoutAntColony colony = new AntColony(3, 8, 3, 2); //makes a full tunnel layout with water (see below)Hive hive = Hive.makeTestHive(); //makes a simple hive with just a couple beesHive hive = Hive.makeFullHive(); //makes a hive full of beesHive hive = Hive.makeInsaneHive(); //makes a challenging hive!
-
The code is divided into two packages. The
corepackage contains the majority of the classes used to run the game (the "core" of the game). Theantspackage will contain all the differentAntclasses you create!
You will need to make a few modifications to some of these provided classes, as detailed below. You should read through the code to get a sense for how it works. I recommend you start at the main method and trace from there.
Note that the provided classes involves a number of advanced concepts: it uses Maps (which we will cover near the end of the assignment), linked-lists (which we will cover after this assignment), and reflection (which we will stay far away from). You are of course welcome to look over and study the code--get a sense for how this prorgram is put together!
Assignment Details
As always, I recommend you read through all of these instructions carefully before you begin! As with the previous assignment, there are numerous (generally small) tasks you will need to complete.
Sections marked with a star (*) are larger and more complex, and you should budget time accordingly.
1. Food and Harvesters
Currently there is no cost for deploying any type of Ant, so there is no challenge to the game. You should add food costs.
-
Notice that
Antshave a food cost of 0. You can override this in the subclasses (ThrowerAntandHarvesterAnt). SincefoodCostis aprotectedvariable, this is easy to do. -
If you look ahead, you'll see that all
Antswill have a different food cost, as well as a different armor values. Since these values will start out the same, they'll be specified in the constructor for each type of Ant. Since we need to call each kind of Ant's parent constructor anyway (why?), it would make sense to have a parent constructor that included both these values, so we could more easily set them. Add such a constructor. -
Specify the food costs for both the
HarvesterAntandThrowerAnt(see below table), and confirm that you can't deploy an ant without enough food!
| Class | Food | Armor |
HarvesterAnt
|
2 | 1 |
ThrowerAnt
|
4 | 1 |
Now you're using up food, but there is no way to produce more! To fix this, finish implementing the HarvesterAnt. As its action (defined in the action() method), the Harvester should produce 1 food for the colony.
- You can call an appropriate method on the
AntColonyparameter to add this food.
Try playing the game again. Once you have placed a HarvesterAnt, you should accumulate food each turn. Vanquishing the bees is once again possible in the default setup!
2. Wall Ants
Next you're going to create your first brand new ant. You will add some protection to your glorious colony by implementing the WallAnt, which is an ant that does nothing each turn but has a very large armor value.
| Class | Food | Armor |
WallAnt
|
4 | 4 |
- Remember to create the
WallAntinside theantspackage. Also be careful to name all your ants correctly (the game relies on the ants having specific names). - The
WallAntwill need to include theaction()method (why?), but it doesn't need to do anything.
3. Hungry Ants
Implement a new offensive unit called the HungryAnt, which will eat a random Bee from its place, instantly killing the Bee! However, after eating a Bee, it must spend 3 turns digesting before eating again.
| Class | Food | Armor |
HungryAnt
|
4 | 1 |
- You can implement this functionality by determining the
action()method whether or not theHungryAntis digesting. This will likely be a more complexaction()method. You can use instance variables to keep track of how long the ant has been digesting. - You can determine how much damage to do to a Bee to kill it by using its
getArmor()method.
4. Fire Ants
Implement the FireAnt. A FireAnt also doesn't take any actions on its turn. However, it does have one special ability: when a FireAnt's armor reaches zero (or lower), it will reduce the armor of all the Bees in the same Place as the ant by the ant's damage attribute (which defaults to 3).
| Class | Food | Armor |
FireAnt
|
4 | 1 |
- To implement this, you should override the ant's
reduceArmor()method in order to add this functionality. Be sure to call the parent's version of the method so that you retain the basic functionality. - Make sure to give the
FireAnta damage variable so you can easily change it; don't hard-code the damage in thereduceArmor()method! - Check the
Placeclass for methods that will let you get access to the list of bees to damage.
Once you've implemented the FireAnt, be sure and test your program by playing a game or two! A FireAnt should destroy any co-located Bees when it dies. You can start a game with ten food by specifying the appropriate value in the AntsVsSomeBees driver.
5. Water*
Now that you've added fire, add some Water! To make things more interesting you will add a new type of Place, representing a water-filled tunnel in the colony. Note that this will be one of the more complex portions of the assignment, as you will need to modify some of the core game code.
- Create a new
Waterclass that subclassesPlace(be sure to create this class in thecorepackage). -
You will need to modify the
AntColonyso it includesWateras well as normalPlaces. In the constructor, modify the loops so that instead of creating a newPlaceobject, you periodically create a newWaterobject based on themoatFrequencyparameter.-
Hint: add a simple if statement to determine whether the tunnel should be a
Placeor aWater. You should be able to instantiate newWaterobjects using the same types of parameters as the current code for making a newPlace. Assign the newWaterobject to thecurrvariable and everything else will work - You should create a
Waterobject everymoatFrequencyplaces. You can do this by checking if thestepvariable is divisible by the targeted value. For example, if you wanted to includeWaterevery 3rd place, you would want the water to be place 0, 3, 6, etc. (But really, you should add one so that it's place 1, 4, 7, etc). - This can be tricky--remember the modulo
%operator! - Also remember to not include any water if the
moatFrequencyis 0!
-
Hint: add a simple if statement to determine whether the tunnel should be a
-
Next, you will need to modify the
AntGameclass so that the Water shows up. This can be hard, as there is a lot going on in theAntGame!- Look for the method that draws the colony. In this method, you should see that the the "border" of the place is drawn as a simple rectangle. You can draw the
Waterby simply filling in a blue rectangle before you draw this border! -
You will need some way to determine if a
Placeis actually aWater(remember, polymorphism means that aWateris also aPlace). This is actually a valid place to use theinstanceofoperator.
- Look for the method that draws the colony. In this method, you should see that the the "border" of the place is drawn as a simple rectangle. You can draw the
-
Be sure and test that you can make
Waterappear!
Once you've added water, you will need to make the insects react to it. Only an insect that is watersafe can be deployed to a Water place.
-
Add a new attribute to the Insect class to keep track of this property. This attribute should be
falseby default. - You'll probably want an accessor (a getter) for this method as well.
-
See
Bees can fly, make theirwatersafeattributetrue, overriding the default. - Once this works, you should not be able to deploy ants to
Waterspots!
6. Scuba Ants
Make a new ant that can be deployed to Water spots! Add a ScubaThrowerAnt ant, which is a type of ThrowerAnt that is watersafe, but otherwise is identical to its parent class.
| Class | Food | Armor |
ScubaThrowerAnt
|
5 | 1 |
7. Ninja Ants
Add the NinjaAnt, which damages all Bees that pass by it, but is never seen (thus allowing Bees to pass by it).
| Class | Food | Armor |
NinjaAnt
|
6 | 1 |
-
A
NinjaAntis not able to be attacked by a Bee because it is hidden, nor does it block the path of a Bee that flies by. To implement this behavior, add another attribute to theAntclass that tracks whether an ant blocks the path of a bee (which will be false for theNinjaAnt). -
Modify the Bee's
isBlocked()method so that the Bee is not blocked if the Ant is does not block. Now Bees should fly right past theNinjaAnts. -
Finally, make the
NinjaAntdamage all Bees that fly past. Make theNinjaAnt'saction()damage all Bees in the same place as the ninja by its damage value (which should default to 1).
For a challenge, try to win a default game using only HarversterAnt and NinjaAnt!
8. Bodyguard Ants*
Right now, your ants are quite frail. We'd like to provide a way to help them last longer against the onslaught of the bees. Enter the BodyguardAnt.
| Class | Food | Armor |
BodyguardAnt
|
4 | 2 |
A BodyguardAnt differs from a normal Ant because it can occupy the same Place as another ant. When a BodyguardAnt is added to the same Place as another ant, it shields the other ant and protects it from damage. Attacks should damage the BodyguardAnt first and only hurt the protected ant after the BodyguardAnt has perished.
There are a number of steps to implement this Ant:
-
Normally, only one Ant can occupy a
Placeat a time. The first thing you'll need to do is change that. You're going to designate a particular kind of Ant that is able to "contain" another ant. Since you may someday want to make multiple kinds of "container ants" (possibly that subclass other ants, like the Scuba or Thrower ant), designate this behavior using an interface calledContaining.- The
Containingmethod should support three methods: the ability to add a contained insect (which should return whether or not the insect was successfully added), the ability to remove a contained insect (which should return whether or not the insect was successfully removed), and the ability to get the currently contained insect.
- The
-
Now you'll need to modify the
Placeclass so that it can have aContainingant, and theContainingcan have another ant. You'll need to modify the method for adding an ant so that:-
If the
Antcurrently occupying thePlaceis aContaining, you add the new ant to theContaining. - If the
Antyou are trying to add is aContaining, then take the ant that is currently in the place, put it in theContaining, and add theContainingto the place instead. - If the
Containingcannot contain the specified ant (e.g., theContaining'saddInsect()method returns false), print the same error as before. - If neither ant is a
Containing, print the same error as before.
-
If the
-
You'll also need to modify the
removeInsect(Ant)method so that if the ant removed is inside theContaining, it is removed from there. Similarly, if the ant removed is theContaining, the container is removed and the Ant it contains (if any) is put in thePlacein its stead! -
You'll also also need to update the
AntColony'sgetAllAnts()method so that both theContainingant and the contained ant are included in the roll call! -
You'll also need to make sure that both the
Containingand itsantshow up in the game! To do this, you'll need to modify theAntGame'sdrawColony()method once again. After checking whether the place has an Ant, check if that Ant is aContaining--and if so, draw the ant it contains as well as theContaining.- You can use the same positioning parameters for the
g2d.drawImage()method. Just draw the contained ant first (so it shows up in the back), and then theContaining!
- You can use the same positioning parameters for the
-
Once that's all set up, you can actually create the
BodyguardAntclass! This class should implement yourContaininginterface.-
To keep track of the ant the Bodyguard contains, use an instance variable. This will start out as
nullindicating that no ant is currently being protected. Use good encapsulation style (e.g., make the variable private!) - You'll need to make sure that the contained ant still performs its action. Override the
action()method of theBodyguardAntaccordingly.
-
To keep track of the ant the Bodyguard contains, use an instance variable. This will start out as
Be sure and text this ant rigorously---there are lots of moving parts here so lots of ways it can break!
9. The Queen Ant*
Last but definitely not least, you will implement the ability for the Ant Queen herself to take to the trenches!
| Class | Food | Armor |
QueenAnt
|
6 | 1 |
The QueenAnt is a waterproof throwing ant (like the ScubaAnt, which you should use as a superclass) that inspires nearby ants through her bravery. Whenever the QueenAnt throws a leaf, she also doubles the damage of the ants on either side of her (in the Places that are her location's entrance and exit).
- To make sure you don't double the damage of the same ant twice, keep a list of the ants that have already been doubled (and search through that list whenever you want to double something).
- You may need to adjust the inheritance of the
damageattribute so that you can effectively interact with all Ants no matter their subclass. You could also consider making an interface likeDamagingwith getters/setters you can use.
However, with great power comes great responsibility. The Queen is governed by three special rules:
-
If a bee ever enters the place occupied by the queen, then the bees immediately win the game. The game ends even if the queen is protected by a bodyguard. The bees also win if any bee reaches the end of a tunnel where the queen normally would reside.
-
The
AntColony'squeenHasBees()method returns whether or not the bees have reached the queen, which it determines by checking ifthis.queenPlace.getBees().length > 0(thisis the colony). Normally thequeenPlacevariable is just a normalPlace. Implement a subclass ofPlacecalledQueenPlacethat (effectively) represents two places: where the Queen currently is, and the normal "queenPlace" at the end of the tunnels.-
Hint: this should basically be a
Placewith another, secondPlaceas an instance variable that stores the Queen's current location. - You will need to override the
getBees()method so that it returns all the bees that are in either location.
-
Hint: this should basically be a
-
As part of the
QueenAnt'saction(), replace the thequeenPlaceobject in the colony with a newQueenPlaceobject that has a reference to theQueenAnt's current place (as it's extra instance variable).- You will need to make an accessor (setter) for the
queenPlacevariable so you can change it! - You can assume that the
QueenPlaceobject will only be used for checking if bees have hit the queen, so you will not need to modify (or even use) any other methods!
- You will need to make an accessor (setter) for the
-
The
-
There can be only one true queen. Any queen beyond the first one is an impostor and should die immediately (its armor reduced to 0) upon taking its first action, without doubling any ant's damage or throwing anything. (Impostor queens should not affect the colony's
queenPlaceattribute).- This means that the QueenAnt uses a variation of the singleton design pattern (which you will talk about more in Software Engineering).
-
In order to implement this, you can keep track of the number of times that an instance of a
QueenAnthas been constructed, using a class (static) variable. Every time you create a queen, increase this variable by 1. You should not need to search through the colonyPlaces to find other queens.
-
The true (first) queen cannot be removed--meaning it can't be moved! Attempts to remove the queen should have no effect.
-
You can do this by modifying the
Placeclass; add an overloadedremoveInsect(QueenAnt)method that has no effect. Note that this method will be called whenever you try and and remove theQueenAnt, because the most specific method signature is applied!-
Style idea: You could even make an interface (like
Unremovable) that the QueenAnt or others could implement, and then use type checking to determine if you should try and remove them or not!
-
Style idea: You could even make an interface (like
- This does mean that your Queen can't be damaged... but that's okay, because the game will end if a Bee gets there anyway!
-
You can do this by modifying the
You are now done with the project!
If you weren't able to vanquish the bees' insane-mode assault plan before, do your new ants help? Add some water or design your own layout to keep things interesting.
Be sure to also fill out the README.txt file.
Submitting
BEFORE YOU SUBMIT: make sure your code is fully documented and functional! If your code doesn't run, I can't give you credit! Your name should be in the class comment at the top of each class that you modified.
Submit your program to the Hwk2 submission folder on vhedwig, following the instructions detailed in Lab A. Make sure you upload your work to the correct folder!.
You should upload your entire src folder with all your classes (both packages!), as well as your antlist.properties file if you made any changes.
Be sure to complete the provided README.txt as well with details about your program.
The homework is due at midnight on Wed Sep 24.
Extensions
There are lots of ways you might extend this assignment!
I have supplied images (and GUI handling) for a number of additional types of ants. You may also design your own kind of ant if you wish!
| Class | Food | Armor | Description |
SlowThrowerAnt
|
4 | 1 |
Applies a "slow" effect for 3 turns. A slowed
bee only takes an action every other turn. |
StunThrowerAnt
|
6 | 1 |
Applies a "stun" effect for 1 turn. A stunned
bee takes no action |
ShortThrowerAnt
|
3 | 1 |
A ThrowerAnt that only throws leaves at
Bees at most 2 Places away
|
LongThrowerAnt
|
3 | 1 |
A ThrowerAnt that only throws leaves at
Bees at least 4 Places away
|
You could also try extending the Bees class to make a wider variety of bees (though I have no images to support this, and it would likely involve extensive modification of the provided game code).
Extensions can be worth up to 3 points of extra credit; but make sure the rest of the functionality exists and works first!
Grading
This assignment will be graded out of 35 points:
- Functionality (26pt)
- [1pt] Ants have food costs and cannot be deployed without sufficient food
- [1pt] The
HarvesterAntproduces food as its action - [2pt] You have implemented the
WallAnt(in the appropriate package!) which takes no actions - [2pt] You have implemented the
HungryAnt, which eats and digests bees - [2pt] You have implemented the
FireAnt, which explodes when defeated - [1pt] You have implemented the
ScubaThrowerAnt. - [3pt] You have implemented the
NinjaAnt, which does not block Bees - [1pt] You have created the
Containinginterface - [1pt] You have implemented the
BodyguardAnt, which can contain another Ant - [2pt] You have modified the
Placeclass so it can contain two ants (if one is aContaining) - [1pt] A contained ant shows up in the GUI and performs its action on its turn
- [2pt] You have implemented the
QueenAntthat doubles the damage of her allies - [2pt] You have included a
QueenPlaceclass so that the game ends when bees reach the queen or the end of the tunnels - [1pt] There can only be one
Highlandertrue queen, and the true queen cannot be removed - [2pt] You have implemented
Water, and only ants that arewatersafecan be deployed toWaterplaces. - [1pt] Your colony creates moats as specified through its constructor
- [1pt] Water shows up in the game's GUI display
- Style (5pt)
- [3pt] You show good use of inheritance: you override classes when possible, only override methods when necessary, and overall don't duplicate code.
- [2pt] You use good encapsulation and data hiding practices (e.g., use of
privatevs.protectedvariables) - Documentation (4pt)
- [1pt] Each class has a class comment with your name in the
@authorfield - [1pt] All methods include JavaDoc comments with appropriate JavaDoc tags (
@paramand@return). Note you only need to override the parts of the comment that change! - [1pt] Changes you have made to existing code (e.g, the AntColony and the AntGame) have inline comments describing them
- [1pt] The README is completed