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!")