For this exercise, you are going to practice defining and instantiating classes to simulate a small river ecosystem with bears and fish! You will see that some “skeleton code” has been set up for you to fill in.
Part I
0. Pull the skeleton code
You will find the starter files needed by “pulling” from the course workspace repository. Before beginning:
- Ensure you are in your course workspace. Open the file explorer and you should see your work for the course. If you do not, open your course workspace through File > Open Recent.
- Open the Source Control View by clicking the 3-node (circles) graph (connected by lines) icon in your sidebar or opening the command palatte and searching for Source Control.
- Click the Ellipses in the Source Control pane and select “Pull” from the drop-down menu. This will begin the pulling process from the course repository. It should silently succeed.
- Return to the File Explorer pane and open the
exercises
directory. You should see it now contains another directory namedEX04
. If you expand that directory, you should see the starter files for the code you’ll be writing. - If you do not see the
EX04
directory, try once more but selecting"Pull From"
and selectorigin
in step 2.
Troubleshooting
If you’re having trouble pulling:
- Make sure you PUSHED all of your changes to backup first!!!
- In your terminal, type
git config pull.rebase false
- In your Visual Studio command center, select
Pull From...
->Upstream
->Upstream/Head
. (If not an option, doOrigin
->Main
.)
If you’re still having issues, please come to office hours!
1. Create Bear Class
All of the work for this part will be done in the file bear.py
.
1.1 class Bear
attributes
For this part, you are going to define and initialize a class to represent the Bears living by the river. In the file bear.py
, you will see a class definition with the name Bear
. Give it the attributes age
and hunger_score
which will both be integers. (You won’t use hunger_score
in Part I, but it’ll be useful later!)
1.2 Bear#__init__
Within the Bear
class, modify __init__
so that it initializes both self.age
and hunger_score
with the value 0
.
2. Create Fish Class
Now, we are going to define a class to represent the fish in the river.
2.1 class Fish
attributes
In the fish.py
file, there will be a class definition called Fish
. Like Bear
, give it an age
attribute, which will be an integer. (It does NOT need a hunger_score
attribute.)
2.2 Fish#__init__
Within the Fish
class, modify __init__
so that it initializes self.age
with the value 0
.
3. Create River Class
Now that you have some animals, you can create and populate a river!
3.1 class River
attributes
In river.py
, give the class River
the following attributes:
day
: anint
that tells you what day of the river’s lifecycle you are modelingbears
: alist
ofBear
objects – each representing a different bear – to represent the river’s bear populationfish
: alist
ofFish
objects to represent the river’s fish population
The __init__
method is already defined for you. It takes as parameters: self
, num_fish: int
, num_bears: int
and does the following:
- initializes
self.fish
to containnum_fish
many Fish - initializes
self.bears
to containnum_bears
many Bears - initializes
self.day
to be0
3.2 Create a new River
Open the river_simulation.py
module. In this file, you will be modeling daily life in this river ecosystem. Construct a River
object named my_river
with 10 Fish
and 2 Bears
. (Don’t forget to import the River
class!)
3.3 view_river()
method
Now, you are going to modify the existing view_river
method inside your River
class. Initially, this method just returns None
, but you will modify it to print the status of the bear and fish populations in a given River
object.
Define
Modify view_river
such that:
It takes no parameters other than
self
and returnsNone
.It should print the following:
~~~ Day x: ~~~ Fish population: y Bear population: z
Where x
is the current day of the river simulation, y
is the number of Fish in the river, and z
is the number of Bears in the river.
Call the method
At the bottom of river_simulation.py
, try viewing your River
object by calling my_river.view_river()
.
When you run python -m exercises.EX04.river_simulation
, the output should be:
~~~ Day 0: ~~~ Fish population: 10 Bear population: 2
4. Simulating one day and one week in the River
Now that you have a River
with Bear
s and Fish
, you can model how their populations update day-to-day.
Bear
and Fish
each have their own one_day
method. Modify them so they have the following behaviors:
4.1 Bear#one_day()
The method one_day()
in the Bear
class takes no parameters other than self
and does not return anything. It should increase the value of the age
attribute by 1.
4.2 Fish#one_day()
The method one_day()
in the Fish
class takes no parameters other than self
and does not return anything. It should increase the value of the age
attribute by 1.
4.3 River#one_river_week()
method
The method one_river_day()
in the River
class is defined for you. It’ll do more once you’ve finished Part II, but notice that it calls the one_day()
method for both the Fish
and the Bear
s.
Within the River
class, define a method one_river_week()
that takes no parameters other than self
and does not return anything. It should simply call one_river_day()
seven times.
At the bottom of river_simulation.py
, test out the functionality of one_river_week
by calling it. (You’ll notice a pretty boring output. Don’t worry, in Part II we will model population changes!)
Part II
For Part II we will represent the circle of life… you will be simulating the life cycle of both the Bear
s and the Fish
in the River
!
1. Removing Animals
1.1 River#check_ages()
As animals reach an old age and pass away, they should be removed from the River
. Modify the check_ages
method so it has the following functionality: If a Fish
’s age is > 3, it should be removed from fish
. If a Bear
’s age is > 5, it should be removed from bears
. (Note that fish and bears can both live much longer than this! We just don’t want this simulation to go on for ages.)
Implementation hint: You don’t want to be removing things from a list while you’re looping through it. Instead, create a new list[Bear]
and copy all surviving Bear
s over to that list rather than removing Bear
s directly from self.bears
. Then update self.bears
to be equal to that copied list. Do the same thing for self.fish
.
1.2 River#remove_fish()
Within the River
class, create a remove_fish
method that has self
and amount: int
as parameters and returns nothing. It should remove amount
many Fish
from the River
. You should remove the FRONTMOST Fish
. (The “front” being the Fish
starting at index 0.)
2. Modelling Bear’s Hunger
Now, we’ll simulate the circle of life. A bear’s gotta eat! This will involve modifying the one_day()
method in the Bear
class and making a new eat()
method in the Bear
class. Let’s do these one at a time:
2.1 Modifying Bear#one_day()
Modify the method one_day()
in the Bear
class such that the hunger_score
attribute decreases by 1 each day.
2.2 Defining the Bear#eat()
method
Now, you are going to create a new method in the Bear
class called eat()
. It has two parameters, self
and num_fish: int
and returns nothing. It should update the Bear
’s hunger_score
so that it increases by num_fish
. (For example, if num_fish = 2
, a Bear
ate 2 fish, so its hunger_score
should increase by 2.)
2.3 Modifying River#bears_eating()
Modify the bears_eating()
method, so that, for each Bear
, if there are at least 5 Fish
in the river, the Bear
will eat 3 Fish
. This involves removing 3 Fish
from the river using the remove_fish
method and calling eat()
with the number of fish the Bear
eats.
2.4 Modifying River#check_hunger
Unfortunately, if a Bear
gets hungry enough, it’ll starve. Modify the check_hunger
method so that it checks the hunger_score
of every Bear
in the river. If hunger_score < 0
, then remove the Bear
from the river.
Implementation hint: You don’t want to be removing things from a list while you’re looping through it. Instead, create a new list[Bear]
and copy all surviving Bear
s over to that list rather than removing Bear
s directly from self.bears
. Then, update self.bears
to be equal to that copied list.
3. Modelling Reproduction
Now we are going to model the reproduction of the Bears and the Fish!
3.1 Modifying River#repopulate_bears
Modify the repopulate_bears
method to add the following functionality: each pair of Bear’s will produce 1 offspring. In other words, if there are 2 bears, 1 new bear will be born and added to bears
. To generalize, for n
bears, there will be n//2
new Bear
s added to bears
.
3.2 Modifying River#repopulate_fish
Modify the repopulate_fish
method to add the following functionality: each pair of fish will produce 4 offspring. In other words, if there are 2 fish, 4 new fish will be born and added to fish
. To generalize, for n
fish, there will be (n//2) * 4
new Fish
added to fish
.
4. Make a Backup Checkpoint “Commit”
As you make progress on this exercise, making backups is encouraged.
- Open the Source Control panel (Command Palette: “Show SCM” or click the icon with three circles and lines on the activity panel).
- Notice the files listed under Changes. These are files you’ve made modifications to since your last backup.
- Move your mouse’s cursor over the word Changes and notice the + symbol that appears. Click that plus symbol to add all changes to the next backup. You will now see the files listed under “Staged Changes”.
- If you do not want to backup all changed files, you can select them individually. For this course you’re encouraged to back everything up.
- In the Message box, give a brief description of what you’ve changed and are backing up. This will help you find a specific backup (called a “commit”) if needed. In this case a message such as, “Progress on Exercise” will suffice.
- Press the Check icon to make a Commit (a version) of your work.
- Finally, press the Ellipses icon (…), look for “Pull/Push” submenu, and select “Push to…”, and in the dropdown select your backup repository.
5. Submit to Gradescope for Grading
Log in to Gradescope and select the assignment named “EX04 - River Simulation”. You’ll see an area to upload a zip file. To produce a zip file for autograding, return back to Visual Studio Code.
If you do not see a Terminal at the bottom of your screen, open the Command Palette and search for “View: Toggle Integrated Terminal”.
To produce a zip file for EX04
, type the following command (all on a single line):
python -m tools.submission exercises/EX04
In the file explorer pane, look to find the zip file named “yy.mm.dd-hh.mm-exercises-EX04.zip”. The “mm”, “dd”, and so on, are timestamps with the current year, month, day, hour, minute. If you right click on this file and select “Reveal in File Explorer” on Windows or “Reveal in Finder” on Mac, the zip file’s location on your computer will open. Upload this file to Gradescope to submit your work for this exercise.
Autograding will take a few moments to complete. For this exercise there will be points manually graded for style – using meaningful variable names and snake_case. If there are issues reported, you are encouraged to try and resolve them and resubmit. If for any reason you aren’t receiving full credit and aren’t sure what to try next, come give us a visit in office hours!