## 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()