Exercises for Lesson 18

Back to Lesson 18

Exercise 1: Modularizing cannonball

Here is the full cannonball program:

# cannonball_main.py

import math

def main():
    # Get inputs
    angle = float(input("Enter the launch angle (in degrees): "))
    vel = float(input("Enter the initial velocity (in meters/sec): "))
    h0 = float(input("Enter the initial height (in meters): "))
    dt = float(input("Enter the time step: "))

    # Convert angle to readians
    theta = math.radians(angle)

    # Set the initial position and velocity in x and y directions
    xpos = 0
    ypos = h0
    xvel = vel * math.cos(theta)
    yvel = vel * math.sin(theta)

    # Loop until the ball hits the ground
    while ypos >= 0.0:
        # Update the x position; x velocity doesn't change
        xpos += dt * xvel

        # Update the y position and velocity (due to gravity)
        yvelNew = yvel - dt * 9.8
        ypos += dt * (yvel + yvelNew)/2.0 # use average velocity
        yvel = yvelNew

    print("Distance traveled: {0:0.1f} meters.".format(xpos))

if __name__ == "__main__":
    main()

Let’s modularize this program by breaking it into different functions. (This is kind of the opposite of top-down design. We’re “refactoring” the code after it’s been written.) Here is what main will look like when we’re done:

# cannonball_main.py

import math

def main():
    angle, vel, h0, dt = getInputs()

    xpos, ypos = 0, h0
    xvel, yvel = getXYComponents(vel, angle)

    while ypos >= 0.0:
        xpos, ypos, yvel = updateCannonball(dt, xpos, ypos, xvel, yvel)

    print("Distance traveled: {0:0.1f} meters.".format(xpos))

if __name__ == "__main__":
    main()

Part a: getting input

First, write a function to get the user inputs.

Old:

    # Get inputs
    angle = float(input("Enter the launch angle (in degrees): "))
    vel = float(input("Enter the initial velocity (in meters/sec): "))
    h0 = float(input("Enter the initial height (in meters): "))
    dt = float(input("Enter the time step: "))

New:

    angle, vel, h0, dt = getInputs()

Part b: calculating the directional velocity components

Next, write a function to compute the x and y components of velocity.

Old:

    # Convert angle to readians
    theta = math.radians(angle)

    # Set the initial position and velocity in x and y directions
    xpos = 0
    ypos = h0
    xvel = vel * math.cos(theta)
    yvel = vel * math.sin(theta)

New:

    xpos, ypos = 0, h0
    xvel, yvel = getXYComponents(vel, angle)

Part c: updating the cannonball

Finally, write a function to calculate the new cannonball state.

Old:

        # Update the x position; x velocity doesn't change
        xpos += dt * xvel

        # Update the y position and velocity (due to gravity)
        yvelNew = yvel - dt * 9.8
        ypos += dt * (yvel + yvelNew)/2.0 # use average velocity
        yvel = yvelNew

New:

        xpos, ypos, yvel = updateCannonball(dt, xpos, ypos, xvel, yvel)

Back to Lesson 18

Exercise 2: The Projectile constructor

We want to rewrite our code again to use a Projectile class. Here is what main will look like now:

def main():
    angle, vel, h0, dt = getInputs()
    cannonball = Projectile(angle, vel, h0)
    while cannonball.getY() >= 0.0:
        cannonball.update(dt)
    print("Distance traveled: {0:0.1f} meters.".format(cannonball.getX()))

Fill in the constructor for the Projectile class. We want to characterize a projectile given the four values of its x and y coordinates of position and velocity. In addition, add accessor methods for the x and y positions.

class Projectile:
    pass # TODO

Back to Lesson 18

Exercise 3: Updating a Projectile’s state

The last piece we need is the ability to update the state of a projectile after some amount of time has passed. Complete the update method for the Projectile class.

    def update(self, dt):
        pass # TODO

Looking for the full code? Check out Zelle pages 326-237.

Back to Lesson 18