The bees are coming!
Create a better soldier
In this project, you will create a tower defense game called Ants Vs. SomeBees. As the ant queen, you populate 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. This game is inspired by PopCap Games' Plants Vs. Zombies ®.
This project combines functional and object-oriented programming paradigms, focusing on the material from Chapter 2.5 of Composing Programs. The project also involves understanding, extending, and testing a large program with many related parts.
This project includes several files, but all of your changes will be made to the first one. You can download all of the project code as a zip archive.
||The game logic of Ants Vs. SomeBees.|
||A suite of tests for the project.|
||Graphics for Ants Vs. SomeBees.|
||General functions for displaying simple two-dimensional animations.|
||Utility functions for CS 61A.|
||Utility functions for grading.|
||A directory of images used by the graphical version of the game.|
This is a two-week project. You'll work in a team of two people, person A and person B. In each part, you will do some of the work separately and some together with your partner. For example, if a problem is marked A1, then it is a solo problem for person A. Both partners should read, think about, and understand the solution to all questions. Feel free to help each other on the solo questions. If you choose to work on the whole project alone, you must complete all questions yourself.
Start early! The amount of time it takes to complete a project (or any program) is unpredictable. Ask for help early and often -- the TAs and lab assistants are here to help. You are not alone!
The only file that you are required to edit is
You do not need to modify any other files to complete the project.
A game of Ants Vs. SomeBees consists of a series of turns. In each turn, new bees may enter the ant colony. Then, new ants are placed. Finally, 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 Colony. The colony consists of several places that are chained
exit of each
Place leads to another
Placing Ants. There are two constraints that limit ant production.
Placing an ant uses up some amount of the colony's food, a different amount for
each type of ant. Also, only one ant can occupy each
Bees. When it is time to act, a bee either moves to the
exit of its current
Place if no ant blocks its path,
or stings an ant that blocks its path.
Ants. Each type of ant takes a different action and requires a
different amount of food to place. The two most basic ant types are the
HarvesterAnt, which adds one food to the colony during each turn,
ThrowerAnt, which throws a leaf at a bee each turn.
Most concepts in the game have a corresponding class that encapsulates the
logic for that concept. For instance, a
Place in the colony holds
insects and connects to other places. A
Bee stings ants and
advances through exits.
The game can be run in two modes: as a text-based game or using a graphical user interface (GUI). The game logic is the same in either case, but the GUI enforces a turn time limit that makes playing the game more exciting. The text-based interface is provided for debugging and development.
The files are separated according to these two modes.
knows nothing of graphics or turn time limits. All graphical elements are
graphics.py. It is
possible to complete this project without ever reading the graphics files.
To start a text-based game, run
To start a graphical game, run
When you start the graphical version, a new window should appear:
In the starter implementation, you have unlimited food and your ants only
throw leaves at bees in their current
Place. Try playing a game
anyway! You'll need to place a lot of
ThrowerAnts (the second
type) in order to keep the bees from reaching your queen.
The game has several options that you will use throughout the project,
which you can view with
python3 [ants.py|ants_gui.py] [OPTIONS] Run the Ants vs. SomeBees project. -h, --help Prints this help message -t, --ten Start with ten food -f, --full Loads a full layout and assault plan -w, --water Loads a full layout with water -i, --insane Loads a difficult assault plan
You have also been provided a testing file
runs a series of unit tests for the project. To test your project, you can
python3 ants_grader.py -v
This command runs all of the unit tests along with any doctests in
ants.py. The optional
-v generates more verbose
output. You can also run tests for individual questions:
python3 ants_grader.py -q 2 python3 ants_grader.py -q A5
If you would like to learn more about Python's built-in unit testing framework, read the documentation of the unittest module. Most problems have associated tests. Make sure that the tests for each problem pass before moving on.
Problem 1 (0 pts). Answer the following questions with your partner
after you have read the entire
ants.py file. If you cannot
answer these questions, read the file again.
runis not a method)!
Hive, a subclass of
Place, is the starting location of the bees. Unlike most instances of
Hiveclass does not have an
exit. Explain how and when
Bees leave the
armorattribute? What happens when
Problem 2 (2 pts). Add food costs and implement harvesters.
Currently, there is no cost for deploying any type of
Ant, and so
there is no challenge to the game. You'll notice that
out with a base
food_cost of 0. Override this value in each of the
subclasses listed below with the correct costs.
Now there's no way to gather more food! To fix this issue, implement the
HarvesterAnt class. A
HarvesterAnt is a type of
Ant that adds one food to the
colony.food total as its
Try playing the game again. Once you have placed a
HarvesterAnt, you should accumulate food each turn. Vanquishing
the bees using the default game setup is now possible.
Problem 3 (1 pts). Add code to the
that tracks entrances. Right now, a
Place keeps track only of its
exit. We would like a
Place to keep track of its
entrance as well. A
Place needs to track only one
However, simply passing an entrance to a
Place constructor will
be problematic; we will need to have both the exit and the entrance before we
can create a
Place! (It's a
chicken or the egg problem.) To get around this problem, we will keep
track of entrances in the following way instead. The
constructor should specify that:
Placealways starts with its
exit, then the
entranceis set to that
Problem A4 (2 pts). Add
water to the colony. Currently there are only two types of places, the
Hive and a basic
Place. To make things more
interesting, we're going to create a new type of
Only an ant that is
watersafe can be deployed to a
Water place. In order to determine whether an
watersafe, add a new attribute to the
watersafe that is
False by default. Since bees
can fly, make their
overriding the default.
Now, implement the
add_insect method for
Place.add_insect to add the insect, regardless of
whether it is watersafe. Then, if the insect is not watersafe, reduce the
insect's armor to 0 by invoking
reduce_armor. Do not copy
and paste code. Try to use methods that have already been defined and make use
of inheritance to reuse the functionality of the
Once you've finished this problem, play a game that includes water. To
mixed_layout that includes water, add the
--water option (or
-w for short) when you start the
python3 ants_gui.py --water
Problem A5 (3 pts). Implement the
FireAnt has a special
reduce_armor method: when the
FireAnt's armor reaches zero or lower, it will reduce the armor of
Bees in the same
Place as the
FireAnt by its
damage attribute (defaults to
Hint: If you iterate over a list, but change the contents of that list at the same time, you may not see all the elements. As the Python tutorial suggests, "If you need to modify the list you are iterating over, you must iterate over a copy." Remember that damaging a bee may cause it to be removed from its place.
Once you've finished implementing the
FireAnt, give it a
implemented with the value
This attribute tells the game that you've added a new type of
FireAnt, be sure to test your program by
playing a game or two! A
FireAnt should destroy any co-located
Bees when it dies. To start a game with ten food, use
Problem B4 (2 pts). Implement the
nearest_bee method for
ThrowerAnt class. In order for a
attack, it must know which bee it should hit. The provided implementation will
only hit bees in the same
Place. Your job is to fix it so that a
throw_at the nearest bee in front of
it that is not still in the
nearest_bee method returns a random
the nearest place that contains bees. Places are inspected in order by
be able to
Bee in front of it that is not
still in the
Hive. Make sure that your ants do the right
thing! To start a game with ten food, use
Problem B5 (3 pts). Now that the
ThrowerAnt has been
completed, implement two subclasses of
Beethat is found after following at least 4
entrancetransitions. So the
Bees that are in the same
Placeas it or the first 3
Places in front of it. If there are two
Bees, one too close to the
LongThrowerand the other within its range, the
LongThrowershould throw past the closer
Bee, instead targeting the farther one, which is within its range.
Beethat is found after following at most 2
entrancetransitions. So the
ShortThrowercan only hit
Bees in the same
Placeas it and 2
Places in front of it.
Neither of these specialized throwers can
Bee that is exactly 3
Places away. Placing a single
one of these (and no other ants) should never win a default game.
To implement these behaviors, modify the
nearest_bee method to
max_range attributes, and only
return a bee that is in range.
For the base class,
min_range to 0
max_range to 10. Then, implement the subclasses
ShortThrower with appropriately
constrained ranges and correct food costs.
implemented class attribute of
Try playing a game with your newly implemented ants. Be sure that they do
what you expect them to! You can try running
ants_gui.py with the
--full option to go up against a full swarm of bees in a
multi-tunnel layout, and add
--insane if you want a real challenge!
If the bees are too numerous to vanquish, you might need to create some new ants
in Phase 2.
Problem A6 (1 pts). We are going to add some protection to our
AntColony by implementing the
is an ant that does nothing each turn (already the default
Ant class). A
WallAnt is useful because it has
Problem A7 (3 pts). Implement the
Bees that pass by, but is never seen.
NinjaAnt is not able to be attacked by a
because it is hidden, nor does it block the path of a
flies by. To implement this behavior, first modify the
to include a new class attribute
blocks_path that is
True by default. Set the value of
False in the
Second, modify the
blocked to return
False if either there is no
Ant in the
place or if there is an
blocks_path attribute is
Bees will just fly past
Finally, we want to make the
NinjaAnt damage all
Bee's that fly past. Implement the
action method in
NinjaAnt to reduce the armor of all
Bees in the same
place as the
NinjaAnt by 1, overriding the default
action method inherited from
Ant. Make sure that you override and
use the inherited damage variable.
For a challenge, try to win a default game using only
Problem B6 (1 pts). Currently there are no ants that can be placed on
Water. Implement the
ScubaThrower, which is a
ThrowerAnt that is more costly and
watersafe, but otherwise identical to its base class.
Water should not cause it to
Problem B7 (3 pts). We will now implement the new offensive unit
HungryAnt, which will eat a random
place, instantly killing the
Bee. After eating a
Bee, it must spend 3 turns digesting before eating again.
To implement, give
attribute that holds the number of turns that it takes all
HungryAnts to digest (default to 3). Also, give each
HungryAnt an instance attribute
digesting that counts
the number of turns it has left to digest (default is 0, since it hasn't eaten
anything at the beginning).
Now we implement the
action method of the
to check if it's digesting; if so, decrement its
Otherwise, eat a random
Bee in its
place (killing the
Bee and restarting the
Problem 8 (5 pts). Implement the
BodyguardAnt. Right now,
our 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 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
BodyguardAnt first and only hurt the protected ant after
BodyguardAnt has perished.
BodyguardAnt has an instance attribute
stores the ant contained within the bodyguard. It should start off as
None, indicating that no ant is currently being protected. Give
contain_ant method that takes an
Ant argument and sets the
ant instance attribute to
Now, change your program so that a
BodyguardAnt and another
Ant can simultaneously occupy the same
Ant.containerclass attribute that indicates whether an ant can contain another. For all
BodyguardAnt.containerattribute should be
Ants a new method,
can_contain, that takes an
otherant as an argument and returns
Trueif and only if:
add_insectmethod of the
Placeclass will immediately cause an error. Change
add_insectso that the
Placecontains the container ant and the container ant contains the other ant:
Antcurrently occupying this
Placecan contain the
Antwe are trying to add, then simply tell it to do so.
Antwe are trying to add can contain the
Antcurrently occupying this
Place, then have it do so and set this
Place's ant to be the newly added
Antcan contain the other, then raise the same assertion error as before.
Almost done! Just a few more things to do.
BodyguardAntcontaining another ant is removed, then the ant it is containing should be placed where the
BodyguardAntused to be. Update the
remove_insectmethod in the
BodyguardAnts still perform their action. Override the
Problem 9 (5 pts). Implement the
QueenAnt. The queen is a
ScubaThrower that inspires her fellow ants through her
bravery. Whenever the queen throws a leaf, she also doubles the damage of all
other ants in the same tunnel with her, including any ants protected by a
bodyguard. Once any ant's damage has doubled, it cannot be doubled again.
However, with great power comes great responsibility. The Queen is governed by three special rules:
AntColony.simulate, the bees win the game whenever
len(self.queen.bees) > 0, where
self is the ant
colony. Normally, the
queen attribute of an
AntColony is an instance of a
Place. As part of the
action of a
should be replaced by a new object, a
QueenPlace has a
bees property method that evaluates
to the list of all bees that are either in the original
colony.queen location or the
place of the
You should not have to change the implementation of
AntColony.simulate or manipulate the location of bees in any
special way. You may assume that a
colony.queen attribute will be
used for only one purpose: to check whether
0. Thus, a
QueenPlace instance does not need to support
Place methods, such as
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
queen attribute. You can
detect impostor queens by counting the number of times that an instance of
QueenAnt has been constructed, using a class attribute.
QueenAnt beyond the first one created is an impostor. You
should not have to search through the colony places to find other queens.
The true (first) queen cannot be removed. Attempts to remove the queen
should have no effect (but should not cause an error). You will need to modify
remove_insect method of
Place to enforce this
Placein a tunnel by starting at one
Placeand then repeatedly follow both its
entranceattributes to the ends.
Placeis at the end of a tunnel, check whether its
Extra Credit (2 pts). Implement two final thrower
ants that do no damage, but instead replace the
action method of
Bee instance that they
throw_at with a new method
that alters the
Bee's behavior for some duration.
We will be implementing two new ants that
SlowThrowerapplies a slow effect for 3 turns.
StunThrowerapplies a stun effect for 1 turn.
In order to complete the implementations of these two ants, you will need to set their class attributes appropriately and implement the following three functions:
actionmethod and returns a new
actionmethod which performs the original action on turns where
colony.timeis even and does nothing on other turns.
actionmethod and returns a new
actionmethod which does nothing.
bee, and a
duration. It then takes the bee's original action along with the "affected action" (the result of calling
effecton the original action) and replaces the bee's action with a new action method that will call the affected action for
durationturns and then will go back to calling the original action every turn.
Make sure to test your code! Your code should be able to apply multiple effects on a target (each new effect applies on top of whatever action method the bee already has at that point, and the target returns to the previous action when the new one runs out).
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.
Acknowledgments: Tom Magrino and Eric Tzeng developed this project with John DeNero. Jessica Wan contributed the artwork. Joy Jeng and Mark Miyashita invented the queen ant. Many others have contributed to the project as well!