Bird Class and Subclasses [50 pts]
Write the Bird, Penguin, and MessengerBird classes so that they pass testBirdClasses and use the OOP constructs we learned in class as appropriate.
def getLocalMethods(clss):
import types
# This is a helper function for the test function below.
# It returns a sorted list of the names of the methods
# defined in a class. It's okay if you don't fully understand it!
result = [ ]
for var in clss.__dict__:
val = clss.__dict__[var]
if (isinstance(val, types.FunctionType)):
result.append(var)
return sorted(result)
def testBirdClasses():
print("Testing Bird classes...", end="")
# A basic Bird has a species name, can fly, and can lay eggs
bird1 = Bird("Parrot")
assert(type(bird1) == Bird)
assert(isinstance(bird1, Bird))
assert(bird1.fly() == "I can fly!")
assert(bird1.countEggs() == 0)
assert(str(bird1) == "Parrot has 0 eggs")
bird1.layEgg()
assert(bird1.countEggs() == 1)
assert(str(bird1) == "Parrot has 1 egg")
bird1.layEgg()
assert(bird1.countEggs() == 2)
assert(str(bird1) == "Parrot has 2 eggs")
assert(getLocalMethods(Bird) == ['__init__', '__repr__', 'countEggs',
'fly', 'layEgg'])
# A Penguin is a Bird that cannot fly, but can swim
bird2 = Penguin("Emperor Penguin")
assert(type(bird2) == Penguin)
assert(isinstance(bird2, Penguin))
assert(isinstance(bird2, Bird))
assert(bird2.fly() == "No flying for me.")
assert(bird2.swim() == "I can swim!")
bird2.layEgg()
assert(bird2.countEggs() == 1)
assert(str(bird2) == "Emperor Penguin has 1 egg")
assert(getLocalMethods(Penguin) == ['fly', 'swim'])
# A MessengerBird is a Bird that can optionally carry a message
bird3 = MessengerBird("War Pigeon", message="Top-Secret Message!")
assert(type(bird3) == MessengerBird)
assert(isinstance(bird3, MessengerBird))
assert(isinstance(bird3, Bird))
assert(not isinstance(bird3, Penguin))
assert(bird3.deliverMessage() == "Top-Secret Message!")
assert(str(bird3) == "War Pigeon has 0 eggs")
assert(bird3.fly() == "I can fly!")
bird4 = MessengerBird("Homing Pigeon")
assert(bird4.deliverMessage() == "")
bird4.layEgg()
assert(bird4.countEggs() == 1)
assert(getLocalMethods(MessengerBird) == ['__init__', 'deliverMessage'])
print("Done!")
Marble, ConstantMarble, and DarkeningMarble classes [50 pts]
Write the Marble, ConstantMarble, and DarkeningMarble classes so that the following test code passes (and without hardcoding any cases, so any similar code would also pass). Also, you must use OOP properly.
def testMarbleClasses():
print("Testing Marble classes...", end="")
# A Marble takes a string (not a list) of comma-separated color names
m1 = Marble('Pink,Cyan')
assert(m1.colorCount() == 2) # pink and cyan
assert(Marble.getMarbleCount() == 1) # we have created 1 marble so far
# When converted to a string, the Marble includes the color names,
# each separated by a comma and a space, and all lower-case, and listed
# in alphabetical order:
assert(str(m1) == '<Marble with colors: cyan, pink>')
m2 = Marble('Red,Orange,yellow,GREEN')
assert(str(m2) == '<Marble with colors: green, orange, red, yellow>')
assert(m2.colorCount() == 4)
assert(Marble.getMarbleCount() == 2) # we have created 2 marbles so far
# This also works in a list:
assert(str([m1]) == '[<Marble with colors: cyan, pink>]')
# Equality works as expected:
m3 = Marble('red,blue')
m4 = Marble('BLUE,RED')
m5 = Marble('red,green,blue')
assert((m3 == m4) and (m3 != m5) and (m3 != "Don't crash here!"))
assert(Marble.getMarbleCount() == 5) # we have created 5 marbles so far
# You can add colors, which only change the marble if they are not present:
assert(m3.addColor('Red') == False) # False means the color was not added,
# because it was already there
# and no changes here:
assert(m3.colorCount() == 2)
assert(str(m3) == '<Marble with colors: blue, red>')
assert((m3 == m4) and (m3 != m5))
# Once more, but with a new color:
assert(m3.addColor('green') == True) # True means the color was added!
# and so these all change:
assert(m3.colorCount() == 3)
assert(str(m3) == '<Marble with colors: blue, green, red>')
assert((m3 != m4) and (m3 == m5))
# A ConstantMarble is a marble that never changes its color:
m6 = ConstantMarble('red,blue')
assert(isinstance(m6, Marble))
assert(str(m6) == '<Marble with colors: blue, red>')
assert(m6.addColor('green') == False) # constant marbles never change!
assert(str(m6) == '<Marble with colors: blue, red>')
assert(Marble.getMarbleCount() == 6) # we have created 6 marbles so far
assert(getLocalMethods(ConstantMarble) == ['addColor'])
# A DarkeningMarble is a marble that prefixes 'dark' to any colors
# that are added after it is first created.
# Note: for full credit, you must use super() properly here!
m7 = DarkeningMarble('red,blue')
assert(isinstance(m7, Marble))
assert(str(m7) == '<Marble with colors: blue, red>') # not darkened
assert(m7.addColor('green') == True) # but green will become darkgreen
assert(str(m7) == '<Marble with colors: blue, darkgreen, red>')
assert(Marble.getMarbleCount() == 7) # we have created 7 marbles so far
assert(getLocalMethods(DarkeningMarble) == ['addColor'])
print("Passed!")