Python Game of Rat and Berry
Once upon a time, there was an island…
- The island is 10 sq km in area.
- Every day there is a 30% chance it will rain on the island.
- When it rains, the rainfall has a normal distribution with a mean of 20 mm and a standard deviation of 5 mm.
- Rain nourishes the local plant life. The day after it rains, the plants will produce berries. The number of berries produced is equal to (previous day’s rainfall in mm) * (area of the island in sq km) * (100).
- Berries persist for 10 days after which they become inedible.
On the island there were rats...
- Initially, there are 10,000 rats on the island with ages randomly chosen in the range 1 through 20 days (uniform and inclusive).
- Every day a rat will eat a berry (randomly chosen regardless of age) if one is available somewhere on the island.
- If a rat does not eat for 3 days, it dies.
- After 50 days, the rat has a 5% chance of dying from old age. This probably increases by 5% every day thereafter (e.g. 5% after 50 days, 10% after 51 days, 15% after 52 days, etc.).
- After a rat eats a total of 10 berries and every 8 berries thereafter, it will give birth to a litter of new rats. The litter size is random and uniformly distributed between 6 and 10 inclusive.
On the island, there were also cats…
- Initially, there are 1000 cats on the island with ages randomly chosen in the range of 1 through 1000 days (uniform and inclusive).
- Every day a cat will attempt to eat a rat. The probability that a cat will catch a rat is dependent on the density of rats on the island: p = (number of rats/area of the island in sq km) * 0.10. Notice that this probability should be capped at 100%.
- With experience, cats become better at catching rats. A cat receives an additive bonus to its probability of catching a rat: b = age of cat * 0.015. Again, the total probability should be capped.
- If a cat does not eat for 5 days, it dies.
- After 2000 days, the cat has a 1% chance of dying from old age. This probably increases by 0.1% every day thereafter.
- After a cat eats a total of 50 rats and every 35 rats thereafter, it will give birth to a litter of new cats.
- The litter size is random and uniformly distributed between 3 and 6 inclusive.
Then, ten thousand days later…
- Design a simulation to capture the interaction of life on the island over 10,000 days.
- Your simulation should begin by reading parameters from a parameter file. This file should include all of the numbers in marked bold above. For example…
- island_size = 10 o rain_chance = 0.30
- rain_mean = 20
- rain_std = 5
- berry_ coefficient = 100
- berry_persist = 10 etc.
Use classes
- Save to file information about the rainfall and the daily population of berries, rats, and cats.
Subject | Value |
island_size | 10 |
rain_chance | 0.3 |
rain_mean | 20 |
berry_coefficient | 100 |
rain_std | 5 |
berry_persist | 10 |
num_of_rats | 10000 |
rat_coefficient | 3 |
rat_range | 20 |
rat_total_berries | 10 |
rat_days | 50 |
berry_after | 8 |
uniform_dist_start | 6 |
uniform_dist_end | 10 |
num_of_cats | 1000 |
max_cat_age | 1000 |
cat_rat_catch_prob | 0.1 |
exp_prob | 0.015 |
cat_days_die | 2000 |
cat_rat_eat | 50 |
cat_rat_additional | 35 |
litter_dist_start | 50 |
litter_dist_end | 35 |
# -*- coding: utf-8 -*-
import pandas as pd
from numpy import random
import numpy as np
ratList = []
catList = []
berriesBasket = []
def readFile():
'function to read a file that consist of many variables for our program'
#use pandas read_csv function to read the variable names and values
#as a dictionary
dictD = pd.read_csv("data.csv", header=0, index_col=0, squeeze=True).to_dict()
for key,val in dictD.items():
islandSize = dictD['island_size']
rainChance = dictD['rain_chance']
rainMean = dictD['rain_mean']
berryCoeff = dictD['berry_coefficient']
rainStd = dictD['rain_std']
berryPersist = dictD['berry_persist']
numRats = dictD['num_of_rats']
ratCoeff = dictD['rat_coefficient']
ratRange = dictD['rat_range']
ratTotalBerries = dictD['rat_total_berries']
ratDays = dictD['rat_days']
berryAfter = dictD['berry_after']
uniformDistStart = dictD['uniform_dist_start']
uniformDistEnd = dictD['uniform_dist_end']
numCats = dictD['num_of_cats']
maxCatAge = dictD['max_cat_age']
catRatCatchProb = dictD['cat_rat_catch_prob']
expProb = dictD['exp_prob']
catDaysDie = dictD['cat_days_die']
catRatEat = dictD['cat_rat_eat']
catRatAdd = dictD['cat_rat_additional']
litterDistStart = dictD['litter_dist_start']
litterDistEnd = dictD['litter_dist_end']
return islandSize,rainChance,rainMean,berryCoeff,rainStd,berryPersist,numRats,ratCoeff,ratDays,ratRange,ratTotalBerries,berryAfter,uniformDistStart,uniformDistEnd,numCats,maxCatAge,catRatCatchProb,expProb,catDaysDie,catRatEat,catRatAdd,litterDistStart,litterDistEnd
# getrain
def rain():
'function to determine if it rains'
# generate a number from 1-100, if 100 is less than 30
# then it will rain
if random.rand() < float(readFile()[1]) :
return 0
# if it rains, how much will it rain
return random.normal(float(readFile()[2]),float(readFile()[4]), size=(1, 1))[0][0]
def generateRat():
""" Initialize the rats in the island """
num_rat = int(readFile()[6])
for i in range(num_rat):
rat = Rats(random.randint(0, num_rat))
ratList.append(rat)
def generateCat():
""" Initilaze the cat in the island """
num_cat = int(readFile()[14])
for _ in range(0, num_cat):
cat = Cats(random.randint(0, num_cat))
catList.append(cat)
def deleteDeadObject():
""" In case rat or cat is dead. Need to remove them all"""
for berry in berriesBasket:
if not berry.isEatable():
berriesBasket.remove(berry)
for rat in ratList:
if rat.isDead():
ratList.remove(rat)
for cat in catList:
if cat.isDead():
catList.remove(cat)
# class for rats
class Rats :
'class that represents a rat that inherits from Island'
def __init__(self, age):
#define the constructor variables
self.ratsBirth_initBerries = int(readFile()[5])
self.numRats = int(readFile()[6])
self.ratCoeff = int(readFile()[7])
self.ratDays = int(readFile()[8])
self.ratRange = int(readFile()[9])
self.ratTotalBerries = int(readFile()[10])
self.berryAfter = int(readFile()[11])
self.uniformDistStart = int(readFile()[12])
self.uniformDistEnd = int(readFile()[13])
self.ratsBeginAge = int(readFile()[19])
self.days = age
self.eatDaysAgo = 0
self.berriesEaten = 0
def passDay(self):
self.days += 1
self.eatDaysAgo += 1
def tryEat(self):
berriesNum = len(berriesBasket)
if berriesNum > 0:
r = random.randint(0, berriesNum)
self.eatDaysAgo = 0
self.berriesEaten += 1
del berriesBasket[r]
def isDead(self):
""" simulate rats dead """
if self.eatDaysAgo >= 3:
return True
if self.days > self.ratTotalBerries and (random.rand() < 0.01 * 0.05 * (self.days - 49)):
return True
return False
def givingBirth(self):
""" Simulate rat birth """
if self.berriesEaten < self.ratsBirth_initBerries:
return
if (self.berriesEaten - self.ratsBirth_initBerries) % self.berryAfter == 0:
ratsBorn = random.randint(self.uniformDistStart, self.uniformDistEnd + 1)
for r in range(1, ratsBorn):
ratList.append(Rats(0))
#class for cats
class Cats:
'class that represents a cat'
def __init__(self, age):
#define the constructor variables
self.islandArea = int(readFile()[0])
self.numCats = int(readFile()[14])
self.maxCatAge = int(readFile()[15])
self.catchProb = float(readFile()[16])
self.expProb = float(readFile()[17])
self.catDaysDie = int(readFile()[18])
self.catRatEat = int(readFile()[19])
self.catAdditional = int(readFile()[20])
self.litterSizeStart = int(readFile()[21])
self.litterSizeEnd = int(readFile()[22])
self.days = age
self.eatDaysAgo = 0
self.ratsEaten = 0
def passDay(self):
self.days += 1
self.eatDaysAgo += 1
def tryEat(self):
""" Simulate eat rats """
ratsNum = len(ratList)
if ratsNum > 0 and(random.rand() < (self.catchProb * ratsNum) / self.islandArea + self.days * 5):
r = random.randint(0, ratsNum)
self.eatDaysAgo = 0
self.ratsEaten += 1
del ratList[r]
def isDead(self):
""" Simulate Cat is dead"""
if self.eatDaysAgo >= 5: # no eat in 5 days.
return True
if self.days > self.catDaysDie and (random.rand() < 0.01 * (self.expProb + self.catchProb * (self.days - self.catDaysDie))):
return True
return False
def givingBirth(self):
""" Simulate cat birth """
if self.ratsEaten < self.catRatEat:
return
if (self.ratsEaten - self.catRatEat) % self.catAdditional == 0:
rats_born = random.randint(self.litterSizeEnd, self.litterSizeStart + 1)
for k in range(0, rats_born):
catList.append(Cats(0))
class Berry:
def __init__(self):
self.ageDays = 0
self.berryPersist = int(readFile()[5])
def isEatable(self):
return self.ageDays <= self.berryPersist
def passDay(self):
self.ageDays += 1
def simulation():
""" Simulation the assignment """
rainn = int(0)
generateRat()
generateCat()
daysLimit = 10000
islandArea = int(readFile()[0])
berryCoeff = float(readFile()[3])
for i in range(1, daysLimit):
newBerries = int(rainn * islandArea * berryCoeff)
for berry in range(1, newBerries):
berriesBasket.append(Berry())
for berry in berriesBasket:
berry.passDay()
for rat in ratList:
rat.tryEat()
rat.givingBirth()
rat.passDay()
for cat in catList:
cat.tryEat()
cat.givingBirth()
cat.passDay()
rainn = rain()
deleteDeadObject()
def main():
simulation()
daysLimit = 10000
print("Simulator in {} days".format(str(daysLimit)))
print("Berries population: {} ea".format(str(len(berriesBasket))))
print("Rats population: {} ea".format(str(len(ratList))))
print("Cats population: {} ea".format(str(len(catList))))
out = open("output.txt", "w")
out.write("Simulator in " + str(daysLimit) + "days\n")
out.write("Berries population: " + str(len(berriesBasket)) + "\n")
out.write("Rats population: " + str(len(ratList)) + "\n")
out.write("Cats population: " + str(len(catList)) + "\n")
out.close()
if __name__ == "__main__":
main()