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
img
folder contains icons and images for the ants, and theants.properties
file 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 theimg
folder andantlist.properties
file 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
Place
object. 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
AntColony
class 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 thePlace
class, which abstracts a single spot in a tunnel and the insects that reside there. TheHive
is a subclass ofPlace
; it has extra variables and methods for tracking when the bees will invade. -
The insects themselves are represented by the
Insect
class, which is subclassed to representAnt
s andBee
s. All insects have a location (aPlace
) and an armor value, as well as anaction()
method that represents what that insect does on its turn. TheAnt
class is further subclassed to represent different types of ants, each of which will have their own variables and actions. Note that two basic subclasses,HarvesterAnt
andThrowerAnt
are provided for you so that the game can run and to get you started. -
The game itself is controlled entirely through the
AntGame
class. This (overly) large is at its core aJPanel
on which the bees and ants are drawn; it also has aTimer
that repeatedly draws new frames of the animation and causes the game to progress. -
Finally, you can run the game via the
AntsVsSomeBees
class, which contains the main method. This method instantiates anAntColony
(check that class' JavaDoc for parameter details) for the game, aHive
for 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 food
AntColony colony = new AntColony(3, 8, 0, 2); //makes a full tunnel layout
AntColony 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 bees
Hive hive = Hive.makeFullHive(); //makes a hive full of bees
Hive hive = Hive.makeInsaneHive(); //makes a challenging hive!
-
The code is divided into two packages. The
core
package contains the majority of the classes used to run the game (the "core" of the game). Theants
package will contain all the differentAnt
classes 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
Ants
have a food cost of 0. You can override this in the subclasses (ThrowerAnt
andHarvesterAnt
). SincefoodCost
is aprotected
variable, this is easy to do. -
If you look ahead, you'll see that all
Ants
will 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
HarvesterAnt
andThrowerAnt
(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
AntColony
parameter 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
WallAnt
inside theants
package. Also be careful to name all your ants correctly (the game relies on the ants having specific names). - The
WallAnt
will 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 theHungryAnt
is 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
FireAnt
a damage variable so you can easily change it; don't hard-code the damage in thereduceArmor()
method! - Check the
Place
class 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
Water
class that subclassesPlace
(be sure to create this class in thecore
package). -
You will need to modify the
AntColony
so it includesWater
as well as normalPlace
s. In the constructor, modify the loops so that instead of creating a newPlace
object, you periodically create a newWater
object based on themoatFrequency
parameter.-
Hint: add a simple if statement to determine whether the tunnel should be a
Place
or aWater
. You should be able to instantiate newWater
objects using the same types of parameters as the current code for making a newPlace
. Assign the newWater
object to thecurr
variable and everything else will work - You should create a
Water
object everymoatFrequency
places. You can do this by checking if thestep
variable is divisible by the targeted value. For example, if you wanted to includeWater
every 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
moatFrequency
is 0!
-
Hint: add a simple if statement to determine whether the tunnel should be a
-
Next, you will need to modify the
AntGame
class 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
Water
by simply filling in a blue rectangle before you draw this border! -
You will need some way to determine if a
Place
is actually aWater
(remember, polymorphism means that aWater
is also aPlace
). This is actually a valid place to use theinstanceof
operator.
- 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
Water
appear!
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
false
by default. - You'll probably want an accessor (a getter) for this method as well.
-
See
Bee
s can fly, make theirwatersafe
attributetrue
, overriding the default. - Once this works, you should not be able to deploy ants to
Water
spots!
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
NinjaAnt
is 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 theAnt
class 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
NinjaAnt
damage 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
Place
at 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
Containing
method 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
Place
class so that it can have aContaining
ant, and theContaining
can have another ant. You'll need to modify the method for adding an ant so that:-
If the
Ant
currently occupying thePlace
is aContaining
, you add the new ant to theContaining
. - If the
Ant
you are trying to add is aContaining
, then take the ant that is currently in the place, put it in theContaining
, and add theContaining
to the place instead. - If the
Containing
cannot 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 thePlace
in its stead! -
You'll also also need to update the
AntColony
'sgetAllAnts()
method so that both theContaining
ant and the contained ant are included in the roll call! -
You'll also need to make sure that both the
Containing
and itsant
show up in the game! To do this, you'll need to modify theAntGame's
drawColony()
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
BodyguardAnt
class! This class should implement yourContaining
interface.-
To keep track of the ant the Bodyguard contains, use an instance variable. This will start out as
null
indicating 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 theBodyguardAnt
accordingly.
-
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
damage
attribute so that you can effectively interact with all Ants no matter their subclass. You could also consider making an interface likeDamaging
with 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
(this
is the colony). Normally thequeenPlace
variable is just a normalPlace
. Implement a subclass ofPlace
calledQueenPlace
that (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
Place
with another, secondPlace
as 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 thequeenPlace
object in the colony with a newQueenPlace
object 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
queenPlace
variable so you can change it! - You can assume that the
QueenPlace
object 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
queenPlace
attribute).- 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
QueenAnt
has 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
Place
class; 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
HarvesterAnt
produces 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
Containing
interface - [1pt] You have implemented the
BodyguardAnt
, which can contain another Ant - [2pt] You have modified the
Place
class 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
QueenAnt
that doubles the damage of her allies - [2pt] You have included a
QueenPlace
class 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 arewatersafe
can be deployed toWater
places. - [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
private
vs.protected
variables) - Documentation (4pt)
- [1pt] Each class has a class comment with your name in the
@author
field - [1pt] All methods include JavaDoc comments with appropriate JavaDoc tags (
@param
and@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