Project 3: Ants Vs. SomeBees
The bees are coming!
Create a better soldier
With inherit-ants.
Introduction
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.
The ants.zip archive contains several files, but all of your
changes will be made to ants.py
.
ants.py
: The game logic of Ants Vs. SomeBeesants_gui.py
: An older GUI for Ants Vs. SomeBeesgui.py
: An new GUI for Ants Vs. SomeBeesgraphics.py
: Utilities for displaying simple two-dimensional animationsstate.py
: Abstraction for gamestate forgui.py
utils.py
: Some functions to facilitate the game interfaceucb.py
: Utility functions for CS 61Aassets
: A directory of images and files used bygui.py
img
: A directory of images used by ants_gui.pyok
: The autograderproj3.ok
: Theok
configuration filetests
: A directory of tests used byok
Certain questions are designated for each partner and are appropriate as solo
questions, in case you choose to divide up the work. Any question not marked as
A
or B
should be solved together with your partner. 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.
Logistics
This is a 10-day project. You may work with one other partner. You should not share your code with students who are not your partner or copy from anyone else's solutions.
In the end, you will submit one project for both partners. The project is worth 22 points. 20 points are assigned for correctness, and 2 points for the overall composition of your program.
You will turn in the following files:
ants.py
You do not need to modify or turn in any other files to complete the project. To submit the project, run the following command:
python3 ok --submit
You will be able to view your submissions on the OK dashboard.
For the functions that we ask you to complete, there may be some initial code that we provide. If you would rather not use that code, feel free to delete it and start from scratch. You may also add new function definitions as you see fit.
However, please do not modify any other functions. Doing so may result in your code failing our autograder tests. Also, please do not change any function signatures (names, argument order, or number of arguments).
Testing
Throughout this project, you should be testing the correctness of your code. It is good practice to test often, so that it is easy to isolate any problems.
We have provided an autograder called ok
to help you with
testing your code and tracking your progress. The first time you run
the autograder, you will be asked to log in with your OK account using your web browser. Please do so. Each time you run
ok
, it will back up your work and progress on our
servers.
The primary purpose of ok
is to test your implementations, but there
is a catch. At first, the test cases are locked. To unlock tests,
run the following command from your terminal:
python3 ok -u
This command will start an interactive prompt that looks like:
===================================================================== Assignment: Ants Vs. SomeBees OK, version ... ===================================================================== ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Unlocking tests At each "? ", type what you would expect the output to be. Type exit() to quit --------------------------------------------------------------------- Question 0 > Suite 1 > Case 1 (cases remaining: 1) >>> Code here ?
At the ?
, you can type what you expect the output to be.
If you are correct, then this test case will be available the next time
you run the autograder.
The idea is to understand conceptually what your program should do first, before you start writing any code.
Once you have unlocked some tests and written some code, you can check the correctness of your program using the tests that you have unlocked:
python3 ok
Most of the time, you will want to focus on a particular question.
Use the -q
option as directed in the problems below.
The tests
folder is used to store autograder tests, so make sure
not to modify it. You may lose all your unlocking progress if you
do. If you need to get a fresh copy, you can download the
zip archive and copy it over, but you
will need to start unlocking from scratch.
Core Concepts
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
together. The exit
of each Place
leads to another Place
.
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
Place
.
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,
and the ThrowerAnt
, which throws a leaf at a bee each turn.
The Code
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. ants.py
knows
nothing of graphics or turn time limits.
To start a text-based game, run
python3 ants.py
To start a graphical game, run
python3 ants_gui.py
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 the game
anyway! You'll need to place a lot of ThrowerAnt
s (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 --help
.
usage: ants.py [-h] [-d DIFFICULTY] [-w] [--food FOOD]
Play Ants vs. SomeBees
optional arguments:
-h, --help show this help message and exit
-d DIFFICULTY sets difficulty of game (easy/medium/hard/insane)
-w, --water loads a full layout with water
--food FOOD number of food to start with when testing
Phase 1
Problem 0 (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 or ask a question on Piazza.
- What is the significance of an insect's
armor
attribute? What happens whenarmor
reaches 0? - What are all of the attributes of the
Ant
class? - Is the
armor
attribute of theAnt
class an instance attribute or class attribute? - Is the
damage
attribute of the Ant class an instance attribute or class attribute? - Which class do both
Ant
andBee
inherit from? - What attribute(s) do
Ant
andBee
inherit from their superclass?
You can test your understanding by running
python3 ok -q 0 -u
Problem 1 (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 Ant
starts out with a base food_cost
of
zero. Override this value in each of the subclasses listed below with
the correct costs.
Class | Food | Armor |
HarvesterAnt |
2 | 1 |
ThrowerAnt |
4 | 1 |
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 action
.
Test your implementation before moving on:
python3 ok -q 1 -u
python3 ok -q 1
Try playing the game again (python3 ants_gui.py
). Once you have placed a
HarvesterAnt
, you should accumulate food each turn. Vanquishing the bees
using the default game setup is now possible.
Problem 2 (1 pt)
Add code to the Place
constructor 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
entrance
.
However, simply passing an entrance to a Place
constructor will be
problematic; we would need to have both the exit and the entrance before
creating 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 Place
constructor should specify
that:
- A newly created
Place
always starts with itsentrance
asNone
. - If the
Place
has anexit
, then theexit
'sentrance
is set to thatPlace
.
Test your implementation before moving on:
python3 ok -q 2 -u
python3 ok -q 2
Phase 2: Water and Fire (Partner A)
Problem 3A (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 Place
called Water
.
Only an ant that is watersafe
can be deployed to a Water
place. In
order to determine whether an Insect
is watersafe
, add a new
attribute to the Insect
class named watersafe
that is False
by
default. Since bees can fly, make their watersafe
attribute True
,
overriding the default.
Now, implement the add_insect
method for Water
. First call
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
. Try not to copy and paste code.
Instead, use methods that have already been defined and make use of
inheritance to reuse the functionality of the Place
class.
Test your implementation before moving on:
python3 ok -q 3A -u
python3 ok -q 3A
Once you've finished this problem, play a game that includes water. To
access the wet_layout
that includes water, add the --water
option
(or -w
for short) when you start the game.
python3 ants_gui.py --water
Problem 4A (2 pts)
Implement the FireAnt
. A FireAnt
has a special reduce_armor
method: when the FireAnt
's armor reaches zero or lower, it will
reduce the armor of all Bee
s in the same Place
as the FireAnt
by its damage
attribute (defaults to 3
).
Class | Food | Armor |
FireAnt |
6 | 1 |
Hint: Damaging a bee may cause it to be removed from its place. If you iterate over a list, but change the contents of that list at the same time, you may not visit 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." You can copy a list by calling the
list
constructor or slicing the list from the beginning to the end.
Once you've finished implementing the FireAnt
, give it a class
attribute implemented
with the value True
. This attribute tells
the game that you've added a new type of Ant
.
Test your implementation before moving on:
python3 ok -q 4A -u
python3 ok -q 4A
After implementing FireAnt
, be sure to test your program by playing a game or
two! A FireAnt
should destroy all co-located Bees when it is stung. To
start a game with ten food (for easy testing):
python3 ants_gui.py --food 10
Phase 2: Extended Range (Partner B)
Problem 3B (2 pts)
Implement the nearest_bee
method for the ThrowerAnt
class. In
order for a ThrowerAnt
to 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 ThrowerAnt
will throw_at
the nearest bee in front of it that is not still in the Hive
.
The nearest_bee
method returns a random Bee
from the nearest place that
contains bees. Places are inspected in order by following their entrance
attributes.
- Start from the current
Place
of theThrowerAnt
. - For each place, return a random bee if there is any, or consider the
next place that is stored as the current place's
entrance
.
Hint: The
random_or_none
function provided inants.py
returns a random element of a sequence.
Test your implementation before moving on:
python3 ok -q 3B -u
python3 ok -q 3B
After implementing nearest_bee
, a ThrowerAnt
should be able to
throw_at
a 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 (for easy testing):
python3 ants_gui.py --food 10
Problem 4B (2 pts)
Now that the ThrowerAnt
has been completed, implement two subclasses
of ThrowerAnt
.
- The
LongThrower
can onlythrow_at
aBee
that is found after following at least 5entrance
transitions. So theLongThrower
can't hitBee
s that are in the samePlace
as it or the first 4Place
s in front of it. If there are twoBees
, one too close to theLongThrower
and the other within its range, theLongThrower
should throw past the closerBee
, instead targeting the farther one, which is within its range. - The
ShortThrower
can onlythrow_at
aBee
that is found after following at most 3entrance
transitions. So theShortThrower
can only hitBee
s in the samePlace
as it and 3Place
s in front of it.
Neither of these specialized throwers can throw_at
a Bee
that is
exactly 4 Place
s away. Placing a single one of these (and no other
ants) should never win a default game.
Class | Food | Armor |
ShortThrower |
2 | 1 |
LongThrower |
2 | 1 |
To implement these behaviors, modify the nearest_bee
method to
reference min_range
and max_range
attributes, and only return a bee
that is in range.
For the base class, ThrowerAnt
, set min_range
to 0 and max_range
to
float('inf')
(infinity). Then, implement the subclasses LongThrower
and
ShortThrower
with appropriately constrained ranges and correct food costs.
Set the implemented
class attribute of LongThrower
and
ShortThrower
to True
.
Test your implementation before moving on:
python3 ok -q 4B -u
python3 ok -q 4B
Phase 3: Seen and Unseen (Partner A)
With your Phase 2 ants, try python3 ants_gui.py -d easy
to play against a
full swarm of bees in a multi-tunnel layout and try -d normal
, -d hard
, or
-d insane
if you want a real challenge! If the bees are too numerous to
vanquish, you might need to create some new ants.
Problem 5A (1 pt)
We are going to add some protection to our glorious AntColony
by implementing
the WallAnt
, which is an ant that does nothing each turn. A WallAnt
is
useful because it has a large armor
value.
Class | Food | Armor |
WallAnt |
4 | 4 |
Unlike with previous ants, we have not provided you with a class header.
Implement the WallAnt
class from scratch. Give it a class attribute name
with the value 'Wall'
(so that the graphics work) and a class attribute
implemented
with the value True
(so that you can use it in a game).
Test your implementation before moving on:
python3 ok -q 5A -u
python3 ok -q 5A
Problem 6A (2 pts)
Implement the NinjaAnt
, which damages all Bee
s that pass by, but can never
be stung.
Class | Food | Armor |
NinjaAnt |
6 | 1 |
A NinjaAnt
does not block the path of a Bee
that flies by, and so it is
never stung. To implement this behavior, first modify the Ant
class to
include a new class attribute blocks_path
that is True
by default. Set the
value of blocks_path
to False
in the NinjaAnt
class.
Second, modify the Bee
's method blocked
to return False
if either
there is no Ant
in the Bee
's place
or if there is an Ant
, but
its blocks_path
attribute is False
. Now Bee
s will just fly past
NinjaAnt
s.
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 Bee
s
in the same place
as the NinjaAnt
by its damage
attribute. Similar to
the FireAnt
, you must iterate over a list of bees that may change.
Test your implementation before moving on:
python3 ok -q 6A -u
python3 ok -q 6A
For a challenge, try to win a game using only HarvesterAnt
and NinjaAnt
.
Phase 3: By Land and Sea (Partner B)
Problem 5B (1 pt)
Currently there are no ants that can be placed on Water
. Implement
the ScubaThrower
, which is a subclass of ThrowerAnt
that is more
costly and watersafe
, but otherwise identical to its base class.
A ScubaThrower
should not lose its armor when placed in Water
.
Class | Food | Armor |
ScubaThrower |
5 | 1 |
Unlike with previous ants, we have not provided you with a class header.
Implement the ScubaThrower
class from scratch. Give it a class attribute
name
with the value 'Scuba'
(so that the graphics work) and a class
attribute implemented
with the value True
(so that you can use it in a
game).
Test your implementation before moving on:
python3 ok -q 5B -u
python3 ok -q 5B
Problem 6B (2 pts)
We will now implement the new offensive unit called the HungryAnt
, which will
select a random Bee
from its place
and eat it whole. After
eating a Bee
, it must spend 3 turns digesting before eating again.
Class | Food | Armor |
HungryAnt |
4 | 1 |
To implement, give HungryAnt
a time_to_digest
class attribute that
holds the number of turns that it takes a HungryAnt
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 HungryAnt
to check if it's
digesting; if so, decrement its digesting
counter. Otherwise, eat a random
Bee
in its place
by reducing the Bee
's armor to 0 and restarting the
digesting
timer.
Test your implementation before moving on:
python3 ok -q 6B -u
python3 ok -q 6B
Phase 4
Problem 7 (5 pts)
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
.
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 takes the place of the other ant and shields it from damage.
Attacks should damage the BodyguardAnt
first and only hurt the protected ant
after the BodyguardAnt
has run out of armor. Meanwhile the ant inside of a
bodyguard should still be able to perform its original action.
To implement the BodyguardAnt
, we'll need to give it an instance attribute
ant
that stores the ant contained within the bodyguard. It should start off
as None
, indicating that no ant is currently being protected. We'll also
need to give the BodyguardAnt
a contain_ant
method that takes an ant
argument and sets the ant
instance attribute to that argument.
However, our current implementation of a Place
is incompatible with the
BodyguardAnt
, since it assumes that only a single ant can occupy a place at a
time. To finish the implementation of the BodyguardAnt
, we must also update
the Place
class to include logic for potentially holding two ants:
- We'll need to add an
Ant.container
class attribute that indicates whether an ant can contain another. For allAnt
instances, except forBodyguardAnt
instances,container
should beFalse
. TheBodyguardAnt.container
attribute should beTrue
. We also need to give
Ant
s a new method,can_contain
, that takes theother
ant as an argument and returnsTrue
if and only if:- This ant is a container.
- This ant does not already contain another ant.
- The other ant is not a container.
Right now, if we attempt place a second ant in a
Place
it will raise anAssertionError
. We still need to raise an error if we cannot place an ant (since otherwise, the game will deduct food fromcolony.food
), but we need to modifyadd_insect
to allow a container and non-container ant to exist in the same place. To this, we'll need theadd_insect
method for aPlace
to consider the following additional cases:- If the
Ant
currently occupying thisPlace
can contain theAnt
we are trying to add, then we'll simply have it do so. - If the
Ant
we are trying to add can contain theAnt
currently occupying thisPlace
, then have it do so and set thisPlace
's ant to be the newly addedAnt
. - If neither
Ant
can contain the other, then raise the sameAssertionError
as before.
- If the
If we try to remove an ant from a
Place
, the current implementation ofremove_insect
assumes that only one ant is in thePlace
and only checks whether or not the ant at a place is the ant that we're trying to remove. As it is, it will either not be able to find an ant at a place, or may even remove both ants! We'll need to add some logic for removing ants if there are two of them in a place:- If we're trying to remove the container ant, then any ant inside the container should still remain in the place.
- If we're trying to remove an ant that is inside a container ant, then the container ant should still remain in the place, and should now be able to contain a new ant.
Note: For this problem you may need to modify or move the original assertion statement outside of the solution block.
The last step is to make sure that ants that are contained by a BodyguardAnt
still perform their action. Override the action
method for BodyguardAnt
accordingly.
Hint: You may want to take a look at the next problem as well, before you start writing any code for this one. Remember that it's bad practice to write code for a geared towards a specific case, so if you write code that applies only to a
BodyguardAnt
, then you may find yourself rewriting everything when we introduce theTankAnt
. Aim to write your code as generally as possible, so as to apply to all ants that are capable of containing other ants, so that you'll save yourself a lot of time and grief when working on the next problem.
Test your implementation before moving on:
python3 ok -q 7 -u
python3 ok -q 7
Problem 8 (1 pts)
BodyguardAnts
provide us with a extra defensive option. But perhaps in a
pinch, we would like an ant that would not only protect an ant at a place, but
also fight back. For this, we introduce the TankAnt
which is not only
protects other ants in a place, but also can damage them in return.
Class | Food | Armor |
TankAnt |
6 | 2 |
The TankAnt
inherits from BodyguardAnt
, and is capable of containing an ant
and protecting it from the invading bees, while still allowing the contained
ant to perform its own action. However, the TankAnt is also capable of fending
off bees on its own, and on each turn will deal 1 damage to all bees in its
place. Of course, this all comes at the cost of requiring more resources to
produce.
Other than being able to attack ants, the TankAnt
shares all other attributes
with the BodyguardAnt
, so with good OOP practices and the use of inheritance,
it should only require changes to its action
method, and some other class
attributes. If you find yourself needing to make changes outside of the
TankAnt
class, consider how you can write your code such that it applies not
just to BodyguardAnt
and TankAnt
objects, but to container
ants in
general.
Test your implementation before moving on:
python3 ok -q 8 -u
python3 ok -q 8
Problem 9 (4 pts)
Implement the QueenAnt
. The queen is a waterproof ScubaThrower
that
inspires her fellow ants through her bravery. The QueenAnt doubles the damage
of all the ants with or behind her, updating any ants whose damage hasn't
been buffed yet each time she performs an action. Once an ant's damage has
been doubled, it should not be buffed again on subsequent turns.
Class | Food | Armor |
QueenAnt |
6 | 1 |
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.
In
AntColony.simulate
, the bees win the game wheneverlen(self.queen.bees) > 0
, whereself
is the ant colony. Normally, thequeen
attribute of anAntColony
is an instance of aPlace
. As part of the firstaction
of aQueenAnt
, thecolony.queen
should be replaced by a new object, aQueenPlace
. AQueenPlace
has abees
property method that evaluates to the list of all bees that are either in the originalcolony.queen
location or theplace
of theQueenAnt
.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 acolony.queen
attribute will be used for only one purpose: to check whetherlen(self.queen.bees) > 0
. Thus, aQueenPlace
instance does not need to support otherPlace
methods, such asadd_insect
.- There can be only one true queen. Any queen beyond the first one is an
impostor and should have 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 either. You can detect impostor queens by counting the number of times that an instance of aQueenAnt
has been constructed, using a class attribute. AnyQueenAnt
beyond the first one created is an impostor. - 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 the
remove_insect
method ofPlace
to enforce this condition. You will also have to consider the case where an imposter is placed inside aBodyguardAnt
inremove_insect
.
Some suggestions:
- You can find every
Place
in a tunnel by starting at onePlace
and then repeatedly follow both itsexit
andentrance
attributes to the ends. - To detect whether a
Place
is at the end of a tunnel, check whether itsexit
orentrance
isNone
. - To make sure that you don't double the damage of the same ant twice, keep a list of all the ants that have been doubled.
Test your implementation before moving on:
python3 ok -q 9 -u
python3 ok -q 9
Extra Credit (2 pts)
Implement two final thrower ants that do no damage, but instead replace
the action
method of a 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 subclass ThrowerAnt
.
SlowThrower
applies a slow effect for 3 turns.StunThrower
applies a stun effect for 1 turn.
Class | Food | Armor |
SlowThrower |
4 | 1 |
StunThrower |
6 | 1 |
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:
make_slow
takes anaction
method and returns a newaction
method which performs the original action on turns wherecolony.time
is even and does nothing on other turns.make_stun
takes anaction
method and returns a newaction
method which does nothing.apply_effect
takes aneffect
(eithermake_slow
ormake_stun
), abee
, and aduration
. It then replaces the bee's action with a new action method that will call the affected action forduration
turns and then will go back to calling the original action every turn.
You can run some provided tests, but they are not exhaustive:
python3 ok -q EC -u
python3 ok -q EC
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 haven't yet, you should try playing the game! There are two GUIs that you can use. The first is an older, but tried-and-true interface that we have been using over the past few years. The command to run it is:
python3 ants_gui.py [-h] [-d DIFFICULTY] [-w] [--food FOOD]
We've also been developing a new browser GUI that we're looking to phase in. It's still in development, but we will continuously push updates to it, which it will automatically download when it runs. The command to run that is:
python3 gui.py [-h] [-d DIFFICULTY] [-w] [--food FOOD]
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!
Colin Schoen developed the new browser GUI. The beautiful new artwork was drawn by the efforts of Alana Tran, Andrew Huang, Emilee Chen, Jessie Salas, Jingyi Li, Katherine Xu, Meena Vempaty, Michelle Chang, and Ryan Davis.