Purpose: to practice basic class design and implementation, practice with 2D data structures, and write code to track simulations.
In this lab, you’ll work with basic class design and implementation to modify a predator-prey simulation.
Step 1: Setup ¶
To get started with this lab exercise do the following things.
-
Download the starter code.
-
Extract the ZIP file to a folder named
bear_fish(or similar) in your class OneDrive (or similar). -
Read the
README.txtfile. This is a common way of describing a program that spans over several files. -
Run the
bearfishsimulation.pyfile and see that it works.
Step 1.5: Add some documentation ¶
The code has very little documentation. Find two methods that could use some documentation and try to add some. Ask the professor or lab assistant for help if you can’t figure out what something is doing.
Step 2: Report bear and fish counts ¶
Notice that the simulation reports 0 bears and 0 fish constantly. That’s because the counting functionality hasn’t been implemented.
Check that the printout is correct now.
Alternative approaches
We could have also used a few other approaches to count the bears and fish:
- By looping through the
thing_list - By keeping count whenever
add_thingordel_thinggets called.
But we chose to loop through the grid to practice working with 2D data structures.
Step 3: Log the bear and fish counts ¶
Make a list of dictionaries, like:
[
{'step': 0, 'num_bears': 10, 'num_fish': 10},
{'step': 1, 'num_bears': 10, 'num_fish': 10},
{'step': 2, 'num_bears': 10, 'num_fish': 9},
...
]
We’ve already initialized an empty log list that you can append to.
Step 4: Save the logs to a JSON file ¶
We could simply make a plot at this point using the log data we have. But there’s two big limitations to this:
- If we want to change something about how the plot looks, we’d have to re-run the entire simulation, which takes a while.
- If we want to look at typical behavior across many runs of the simulation, it would really take a lot of time to run all those, so we better have a way to save our work.
To address both issues, let’s save the results of the simulation in a file. We could use a CSV file, but that’s limited in some ways. A more general file format is JSON; it can basically store any kind of data structure. Let’s practice making and storing some data.
Step 5: Make a plotting script ¶
Make a new script, called plot_results.py. Load the trial data from trial_1.json:
with open('trial_1.json') as f:
trial_data = json.load(f)
# TODO: get the log out of the trial data
# (this is a single assignment statement.)
# Make a dataframe of the results
trial_dataframe = pd.DataFrame(log)
Now plot the bear and fish counts over time. I’d suggest a line plot.
You can use whatever framework (plain Python or Streamlit) and plotting toolkit you’d like (I’d suggest Plotly, but matplotlib is fine too). The key thing is that this is a separate script.
Note: if you use plotly, you can pass a list of column names for y.
Step 6: Fix the simulation ¶
Once you have all this working, try changing the size of the world to be 25x25. Then, try changing the number of steps the world simulates to be 5000 or 10000.
What I see is that all the fish always die out, but the bears live on – even after the fish are gone. Why is this? Let’s try to fix it:
You might want to add print statements to see every time a bear is born
and when a bear dies (and why).
Optional Extensions ¶
- Run multiple trials.
- Save each one in a new
jsonfile (e.g.,trial2.json,trial3.json… ortrial-2022-11-18T17_05_35.json)- You can generate that timestamped filename using
datetime.datetime.now().isoformat().replace(':', '_'). - Remember to set different seeds each time. You might use something like
seed = random.randrange(2**32). - The CONSTANTs that you introduced for the bear energy and breeding would make good additional parameters.
- You might try different starting configurations or different parameters.
- You can generate that timestamped filename using
- Plot multiple trials on the same plot.
- Use
glob.glob('trial*.json')to get all the filenames. - Put all of the dataframes in a list, then use
pd.concatto put them all in a giant dataframe.
- Use
- Save each one in a new
- Try making the simulation more realistic in some way.
- Replace
starve_tickwithenergy_reserves: bears are born with some amount of energy, living takes energy, breeding takes more energy, and eating fish gives energy. - Bear mating?
- Gestation time?
- World climate or seasons (e.g., breeding season)?
- Some structure to the world (e.g., land vs water)
- Replace
- Add more kinds of entities to the simulation
- Inheritance will be useful here, we’ll see that next week.
Submit your lab ¶
Create a new ZIP file with your completed project code and upload it to Moodle.
If you don’t know how to do make a ZIP file, here are a few references: https://www.wikihow.com/Make-a-Zip-File, https://www.digitaltrends.com/computing/how-to-zip-a-file-in-windows-10/