# CMU 15-112 Summer 2018: Fundamentals of Programming and Computer Science Homework 13 (Due Tue 19-Jun, at 5pm)

• This assignment is SOLO. This means you may not look at other student's code or let other students look at your code for these problems. See the syllabus for details.

• To start:
1. Create a folder named 'week5'
2. Edit hw13.py using Pyzo
3. When you are ready, submit hw13.py to Autolab. For this homework you will have 20 submissions.
• This homework is fully autograded.
• Do not hardcode the test cases in your solutions.
• This homework may be graded for style.

1. Book Class [50 pts]
Write the Book class so that it passes testBookClass, and uses the OOP constructs we learned as appropriate.
def testBookClass(): print("Testing Book class...", end="") # A Book has a title, and author, and a number of pages. # It also has a current page, which always starts at 1. There is no page 0! book1 = Book("Harry Potter and the Sorcerer's Stone", "J. K. Rowling", 309) assert(str(book1) == "Book<Harry Potter and the Sorcerer's Stone by " + "J. K. Rowling: 309 pages, currently on page 1>") book2 = Book("Carnegie Mellon Motto", "Andrew Carnegie", 1) assert(str(book2) == "Book<Carnegie Mellon Motto by Andrew Carnegie: " + "1 page, currently on page 1>") # You can turn pages in a book. Turning a positive number of pages moves # forward; turning a negative number moves backwards. You can't move past # the first page going backwards or the last page going forwards book1.turnPage(4) # turning pages does not return assert(book1.getCurrentPage() == 5) book1.turnPage(-1) assert(book1.getCurrentPage() == 4) book1.turnPage(400) assert(book1.getCurrentPage() == 309) assert(str(book1) == "Book<Harry Potter and the Sorcerer's Stone by " + "J. K. Rowling: 309 pages, currently on page 309>") book2.turnPage(-1) assert(book2.getCurrentPage() == 1) book2.turnPage(1) assert(book2.getCurrentPage() == 1) # You can also put a bookmark on the current page. This lets you turn # back to it easily. The book starts out without a bookmark. book3 = Book("The Name of the Wind", "Patrick Rothfuss", 662) assert(str(book3) == "Book<The Name of the Wind by Patrick Rothfuss: " + \ "662 pages, currently on page 1>") assert(book3.getBookmarkedPage() == None) book3.turnPage(9) book3.placeBookmark() # does not return assert(book3.getBookmarkedPage() == 10) book3.turnPage(7) assert(book3.getBookmarkedPage() == 10) assert(book3.getCurrentPage() == 17) assert(str(book3) == "Book<The Name of the Wind by Patrick Rothfuss: " + \ "662 pages, currently on page 17, page 10 bookmarked>") book3.turnToBookmark() assert(book3.getCurrentPage() == 10) book3.removeBookmark() assert(book3.getBookmarkedPage() == None) book3.turnPage(25) assert(book3.getCurrentPage() == 35) book3.turnToBookmark() # if there's no bookmark, don't turn to a page assert(book3.getCurrentPage() == 35) assert(str(book3) == "Book<The Name of the Wind by Patrick Rothfuss: " + \ "662 pages, currently on page 35>") # Finally, you should be able to compare two books directly and hash books book5 = Book("A Game of Thrones", "George R.R. Martin", 807) book6 = Book("A Game of Thrones", "George R.R. Martin", 807) book7 = Book("A Natural History of Dragons", "Marie Brennan", 334) book8 = Book("A Game of Spoofs", "George R.R. Martin", 807) book9 = Book("A Game of Thrones", "George R.R. Martin", 200) assert(book5 == book6) assert(book5 != book7) assert(book5 != book8) assert(book5 != book9) s = set() assert(book5 not in s) s.add(book5) assert(book6 in s) assert(book7 not in s) s.remove(book6) assert(book5 not in s) book5.turnPage(1) assert(book5 != book6) book5.turnPage(-1) assert(book5 == book6) book6.placeBookmark() assert(book5 != book6) print("Done!")

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