The Critter Zoo Program

This program extends the previous critter caretaker program to allow us to manage lots of critters, we create a critter zoo!

We can then feed or play with our critters to improve their hunger and boredom to improve their mood.

Our new CritterZoo class has an attribute called critters which is a dictionary that stores each of the Critter instances.

We can then interact with individual Critter instances through this dictionary.

In the next unit, we will see a different way of doing this by extending Python's built-in dictionary type dict.

Create a file called critter.py and copy in the following:

# critter.py
# A virtual pet to care for
class Critter:
  """A virtual pet"""

  total = 0

  def __init__(self, name, hunger=0, boredom=0):
    self.name = name
    self.hunger = hunger
    self.boredom = boredom
    Critter.total += 1

  def __str__(self):
    desc = ""
    desc += f"Name: {self.name}\n"
    desc += f"Hunger: {self.hunger}\n"
    desc += f"Boredom: {self.boredom}\n"
    return desc
  
  def pass_time(self):
    self.hunger += 1
    self.boredom += 1
    if self.hunger > 16:
      self.hunger = 16
    if self.boredom > 16:
      self.boredom = 16

  # indicate that the method is internal (non-public)
  def _mood(self):
    unhappiness = self.hunger + self.boredom
    if unhappiness < 5:
      m = "happy"
    elif 5 <= unhappiness <= 10:
      m = "okay"
    elif 11 <= unhappiness <= 15:
      m = "frustrated"
    else:
      m = "mad"
    return m

  def talk(self):
    print(f"I'm {self.name} and I feel {self._mood()} now.\n")

  def eat(self, food=5):
    print("Brruppp. Thank you.")
    self.hunger -= food
    if self.hunger < 0:
      self.hunger = 0

  def play(self, fun=5):
    print("Wheee!")
    self.boredom -= fun
    if self.boredom < 0:
      self.boredom = 0

class CritterZoo:
  """ A critter zoo"""
  def __init__(self, no_critters):
    self.critters = {}
    for i in range(no_critters):
      crit = Critter(f"Critter {i+1}")
      self.critters[f"Critter {i+1}"] = crit

  def __str__(self):
    returnstring = ""
    for critter in self.critters.values():
      returnstring += critter.__str__()
    return returnstring
  
  def feed_critter(self, name):
    self.critters[name].eat()
    self._pass_time()

  def play_with_critter(self, name):
    self.critters[name].play()
    self._pass_time()

  def list_critter_names(self):
    for name in self.critters.keys():
      print(name)

  def list_critter_moods(self):
    for critter in self.critters.values():
      critter.talk()
    self._pass_time()

  # indicate that the method is internal (non-public)
  def _pass_time(self):
    for critter in self.critters.values():
      critter.pass_time()

Take some time to look at the CritterZoo class and some of the amendments made to the Critter class. For, example pass_time() is now public and is called from within the CritterZoo class so that we can pass the time for all of the critters in one go.

Our main.py file contains the following:

# main.py
# Critter Zoo
from critter import CritterZoo

def main():
  no_critters = input("How many critters would you like?: ")
  zoo = CritterZoo(int(no_critters))

  choice = None
  while choice != "0":
    print \
    ("""
    Critter Caretaker
    0 - Quit
    1 - Listen to your critters
    2 - Feed a critter
    3 - Play with a critter
    4 - List critters (does not pass time)
    """)
  
    choice = input("Choice: ")
    print()
    # exit
    if choice == "0":
      print("Good-bye.")
    # listen to your critter
    elif choice == "1":
      zoo.list_critter_moods()
    # feed your critter
    elif choice == "2":
      print("Which critter do you want to feed?")
      zoo.list_critter_names()
      crit_num = input("Please enter the number you wish to feed.\n")
      zoo.feed_critter(f"Critter {crit_num}")
    # play with your critter
    elif choice == "3":
      print("Which critter do you want to play with?")
      zoo.list_critter_names()
      crit_num = input("Please enter the number you wish to play with.\n")
      zoo.play_with_critter(f"Critter {crit_num}")
    # list critters
    elif choice == "4":
      print(zoo)
    else:
      print(f"\nSorry, but {choice} isn't a valid choice.")

if __name__ == "__main__":
  main()