CMU 15-112 Spring 2019: Fundamentals of Programming and Computer Science
Homework 8 (Due FRIDAY March 8***, at 5pm)
- ***IMPORTANT: Due dates
- You should plan to finish this by March 8, but you can submit without grace days or any penalty until March 10 at 5pm if you really want or need to finish it over the weekend.
- WARNING! There will be NO OFFICE HOURS and limited Piazza support during spring break, and that includes March 9th and March 10th!
- Do you need new collaborator(s) for hw8? Fill out this form and we'll try to pair you up with other students in the class. We'll stop checking for new entries on Thursday at 9am, so fill it out before then!
- To start:
- Create a folder named 'week8'
- Download the hw8.py starter file to that folder.
- When you have completed hw8, submit hw8.py to Autolab. For this hw, you may submit up to 5 times, but only your last submission counts.
- Do not hardcode the test cases in your solutions.
- Style [0 pts]
As usual, write your code with good style, and following the 15-112 style guidelines. - Midsemester Course Survey [10pts]
Take the midsemester course survey here! We want your feedback on how the course is going, so we can keep trying to make it better.
Note: this survey will be anonymous. When you complete the survey, you'll get a link to a different form where you can enter your andrewID to receive the homework credit. We will not be able to map your survey response to your andrewID. You must complete the second survey with your andrewID to recieve credit. There will be no regrades. You should automatically receive an email receipt, and this is the only proof we will accept if we don't see your response.
If you want to give additional feedback, you can also give specific TAs feedback using the Midsemester TA Survey. This is not required and not worth any points, but is highly appreciated. - Bird Class and Subclasses [15pts]
Write the Bird, Penguin, and MessengerBird classes so that they pass testBirdClasses and use the OOP constructs we learned this week 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") tempBird = Bird("Parrot") assert(bird1 == tempBird) tempBird = Bird("Wren") assert(bird1 != tempBird) nest = set() assert(bird1 not in nest) assert(tempBird not in nest) nest.add(bird1) assert(bird1 in nest) assert(tempBird not in nest) nest.remove(bird1) assert(bird1 not in nest) assert(getLocalMethods(Bird) == ['__eq__','__hash__','__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(not isinstance(bird1, Penguin)) 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(not isinstance(bird2, MessengerBird)) assert(not isinstance(bird1, MessengerBird)) 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!") - OOPy Asteroids [75pts]
In this assignment, you will be completing the code for a game of OOPy Asteroids that has already been partially implemented. If you are not familiar with the game Asteroids, you may wish to try it here.
Here is a video demo of the results of completing each of the steps listed below:
Step One: read the code provided in the starter file to understand the initial setup of the game. It is very important that you understand the provided code, as you'll be using it during the next few steps! This starter file includes four classes and the central game code.
- The first two classes represent the enemies in the game, the Asteroids. Asteroids are circles that can move around the screen based on a pre-determined direction. There is a base Asteroid class and one subclass, ShrinkingAsteroid. You'll add a bit of code to these classes.
- The third class is the Rocket class, which represents the main player. The rocket stays in the middle of the screen, but can be rotated using the left and right arrow keys to point in different directions. The rocket can also fire bullets.
- The fourth class is the Bullet class. Bullets are generated by the rocket, and move in a straight line from their starting location.
- The central game code starts by drawing and allowing interaction with the main rocket object, and by creating and showing a score. You'll add a lot of code here!
Step Two: modify the game code to keep track of bullets fired by the rocket. A bullet is fired every time the user presses the space key. Make sure to read the Bullet class first- much of the work is already done in the class! For example, having the bullets move should be achieved by simply calling the .moveBullet method each time timerFired is called. You should also remove any bullets that have moved beyond the window, which you can detect using the .isOffscreen method.
Step Three: modify the game code to keep track of (normal) asteroids. An asteroid with a random radius, speed, position, and direction is added to the game every 2 seconds. You'll want to use random.randint() to determine most of these values, though random.choice() may be more useful for determining the direction. At first, asteroids don't move, and should stay on the screen permanently. Make them move by adding code in timerFired, like you did for the bullets. Again, make sure to read the Asteroid class- much of the work has already been done in there!
Step Four: add the method reactToWallHit(self, screenWidth, screenHeight) to the Asteroid class. This method should be called after moving the asteroid to determine whether it has hit a wall and react appropriately. Normal asteroids wrap around to the other side of the screen when they hit a wall. Note that screenWidth and screenHeight should be data.width and data.height.
Step Five: add code to timerFired that checks whether any of the bullets collide with any of the asteroids after movement has been completed. If a bullet hits a (normal) asteroid, the asteroid immediately disappears and the bullet is removed from the game. Note that whenever an asteroid is removed from the game, you should add 1 point to the score.
Step Six: This last step is worth 10 points out of 75, so if you are running out of time, make sure you have everything else working and submit what you have. Finally, make a change to your code so that each new asteroid has a 50/50 chance to be a ShrinkingAsteroid. Then add code to the ShrinkingAsteroid subclass (and your animation framework if necessary) so that ShrinkingAsteroids have the following behavior:- When shrinking asteroids are hit by a bullet, their radius shrinks by the specified shrinkAmount but are not immediately destroyed. The bullet should still disappear though.
- When their radius becomes 15 or smaller, they are removed from the game.
- When shrinking asteroids reach the edge of the screen, they bounce (instead of wrapping around).
- When a shrinking asteroid disappears, it should add 1 point to the score.
Hints: While we have heavily scaffolded this problem, there are multiple ways to implement these features. READ AND UNDERSTAND THE STARTER CODE. This way you won't waste time re-writing functions we already provide.
You now have a working Simple Asteroids game! Woohoo!
- More Asteroids: [2 pts] [manually graded]
Add another subclass of Asteroid that does something interesting. It's up to you what this means! The asteroid could split, change color, teleport, etc. The only real requirements are that it is a) a subclass of Asteroid and inherits from it in a nontrivial way, and b) it does not change the behavior or interactions of the other asteroids, bullets, ship, or other components of the core assignment. To help us grade this, you must add a text box on-screen that briefly but clearly describes your new feature(s). The text must be legible or we will not grade this bonus. You should define your new subclass underneath the ShrinkingAsteroids subclass, along with very descriptive comments describing what it does.
Solo problems
Collaborative problems
Bonus problems