Introduction
#Question 2————————————-
WORLD0 = (waiting_youdee,normal_slingshot,far_target)
#Question 3————————————-
def move_youdee(youdee):
if youdee[4]:
x = youdee[0] +youdee[2]
y = youdee[1] +youdee[3]
vy = youdee[3] +GRAVITY
else:
x= youdee[0]
y = youdee[1]
vy = youdee[3]
produced_youdee = (x,y,youdee[2],vy,youdee[4])
return produced_youdee
#Question 4————————————-
def handle_tick(world):
youdee,slingshot,target = world
youdee = move_youdee(youdee)
produced_world = (youdee,slingshot,target)
return produced_world
#Provided functions for Question 5————–
def print_youdee(ayoudee):
“””
prints YoUDee at his given position.
PARAMETERS:
ayoudee -YoUDee
RETURN:
None
“””
(x,y,vx,vy,is_moving) = ayoudee
print(“YoUDee——“)
print(“x,y:”,x,y)
print(“vx,vy”,vx, vy)
if not is_moving:
print(“Ready for lift off!”)
else:
print(“CLUCKAAAAAWWWWK!”)
def print_target(atarget):
“””
prints target
PARAMETERS:
atarget - target
RETURN:
None
“””
x,y = atarget
print(“Target——-“)
print(x,y)
def print_slingshot(aslingshot):
“””
prints the slingshot
PARAMETERS:
aslingshot - slingshot
RETURN:
None
“””
angle,v0 = aslingshot
print(“Slingshot——“)
print(“angle:”,angle)
print(“v0:”,v0)
#Question 5————————————-
def print_world(world):
youdee,slingshot,target = world
print_youdee(youdee)
print_slingshot(slingshot)
print_target(target)
#Provided functions for Question 6————–
def run_simulation(aworld):
print_world(aworld)
aworld = handle_input(aworld)
while not win_or_lose(aworld):
print_world(aworld)
aworld = handle_tick(aworld)
print_world(aworld)
def handle_input(aworld):
“””
repeatedly ask the user for valid input until the user presses l
which then launches the bird. Creates the new world that results from pressing the below keys:
a and d change the initial slingshot velocity
w and s arrow change the slingshot angle
l launches the bird.
PARAMETERS
aworld - World
RETURN
modified_world - World:
“””
(ayoudee, aslingshot, some_target) = aworld
input_string = get_valid_input()
while input_string != “l”:
if input_string == “w”:
aslingshot = update_angle(aslingshot, 1)
elif input_string == “s”:
aslingshot = update_angle(aslingshot, -1)
elif input_string == “d”:
aslingshot = update_velocity(aslingshot,1)
elif input_string == “a”:
aslingshot = update_velocity(aslingshot,-1)
input_string = get_valid_input()
ayoudee = launch_bird(ayoudee,aslingshot)
return ayoudee, aslingshot, some_target
Requirement
Project 1
Lab Motivation and Goals
This lab is designed to help you practice:
Defining tuples
Writing programs which consume multiple arguments
Working with loops
Writing interactive code
Please submit your work on the quiz server after completing your project in Thonny. Name your local python file project1.py. Do all work in pairs. Include the names of both partners at the top of the file in a comment. You need only to submit one lab per pair. For each function, you must write 3 unit tests.
Prior to working on this lab, see installingmatplotlib.pdf on canvas.
Review of Tuples
Consider representing a snake’s name, length, and color inside of a tuple:
A snake is a (str, float, str)
Creation
In order to create a snake, we need create a tuple with 3 elements—the first is a string, the second is a float, and the last is another string.
snake_fred = (“fred”, 21, “green” )
Extraction
In order to extract elements from the snake, we can do the following:
name, length, color = snake_fred
where name is assigned the first element in snake_fred—“fred”, length is assigned the second element in snake_fred —21, and color is assigned the third element in snake_fred —“green”.
Examples
snake_fred = (“fred”, 21, “green” )
snake_matt = (“matt”, 1, “blue”)
snake_katie = (“katie”, 0, “gold”)
snake_tommy = (“tommy”, 6, “red”)
Project 1
Physics sim games seem to be all the rage, and UD wants you to prototype a new one. You will fire YoUDee out of a slingshot from one side of the green and try to hit a target on the other side of the green. You can control YoUDee’s angle and initial velocity as he leaves the slingshot.
Up until now, we have only been able to pass a single argument to represent data. Now that we have learned to create compound data structures (tuples) from atomic and other compound components, we can create much more interesting programs.
The first step in developing an interactive program is to consider what we need to represent about that world in the computer—especially anything that will change in the world because of time passing or user interactions (e.g. input function).
A little thinking might give us this:
YoUDee: will be flying through the air using a simple ballistics model from physics. YoUDee will have a changing x and y position, and a changing velocity due to gravity (and air resistance, but let’s ignore that for now). These will change over time, although the initial position is fixed and the initial velocity will come from the slingshot.
Slingshot: will have an angle of fire and initial velocity (how far we pull it back) that the user can change.
Target: will have a location. It’s a harder game if the target is moving over time, or if a 2nd player can move the target.
Here are some data definitions to get you started. This code (including the checker module’s unit tests that I’ve left out here) is available as an attachment.
GRAVITY = -9.8
SCREEN_WIDTH = 600
SCREEN_HEIGHT = 500
“””
DATA DEFINITIONS
A target is a (x,y) where both x and y are floats
INTERPRETATION
x (float): the x position of the target
y (float): the y position of the target
EXAMPLE
close_target = (3,2)
far_target = (10,3)
EXTRACTION
x1,y1 = close_target #x1 will be 3, y1 will be 2
x2,y2 = far_target #x2 will be 10, y2 will be 3
Note: For testing, I’d suggest writing more examples!
———————————————-
A slingshot is a (angle, v0) where angle and v0 are both floats.
INTERPRETATION (pay attention here)
angle (float): the angle of release in DEGREES
v0 (float): the initial velocity of the released object
EXAMPLE
weak_slingshot = (30, 1)
normal_slingshot = (40, 5)
strong_slingshot = (45, 10)
Note: For testing, I’d suggest writing more examples!
———————————————-
A youdee is a (x y vx vy moving?) where x,y,vx, vy are all floats. moving is a boolean
INTERPRETATION
x (float): the x position of YoUDee
y (float): the y position of YoUDee
vx (float): the x velocity (change in x position) of YoUDee
vy (float): the y velocity (change in y position) of YoUDee
moving? (bool): True if YoUDee is released and flying. False if in the slingshot.
EXAMPLE
waiting_youdee = (0,0, 0, 0, False)
flying_youdee = (10, 20, 5,2, True)
Note: For testing, I’d suggest writing more examples!
“””
1.Develop a data definition for a world that contains YoUDee, a slingshot, and a target. Write out the interpretations, examples, and how to select the attributes for each data definition (we won’t ask for or give this).
2.Create an example of a world, in particular the initial world WORLD0, with YoUDee in the slingshot at time/tick 0 and not moving. You may want some other examples later for unit testing. Note: Because YoUDee is in the slingshot, the initial y should be positive and initial x should be 0!
Put WORLD0 below your world data definition.
3.Write a function called move_youdee that consumes a YoUDee and produces a YoUDee. If the YoUDee is moving, then the produced YoUDee has the same vx velocity as the original YoUDee, but the vy velocity and the x and y position are changed based on simple physics:
The new x is the old x + vx.
The new y is the old y + vy.
The new vy is the old vy + GRAVITY
If YoUDee is not moving, there is no change to the YoUDee (the YoUDee is not yet moving).
Go through the design recipe. Write Documentation and Write 3 unit tests! At this time, we will no longer remind you to write documentation and cisc106AssertEqual unit tests for your function.
4.Develop a function handle_tick that consumes a world and produces a new world at the next tick. The function should make use of the move_youdee function above. Note that the target and the slingshot don’t change when the clock ticks.
5.Consider the following python functions:
Develop the function print_world, which consumes a World and prints out everything in the world. Use print_youdee, print_target, and print_slingshot in your answer.
Put the following lines of code at the bottom of your file:
When you press Run, and call input_main from the shell/python console. Thonny will print the world.
Now, we want to let the user control the game by input the “w” and “s” keys to increase/decrease the angle and “a” and “d” to increase/decrease the initial launch speed. The “l” key will launch YoUDee. Note: WASD is commonly used for left-hand directional keys.
Consider the following function that handles user input.
Note that this code calls some functions we have not yet defined. This is a fairly typical top-down design approach. Each function should do at most one thing, so we push off the details to other, smaller, simpler functions. We can write down a “wish list” of these functions with a signature and short purpose statement, as a reminder like we did below.
#get_valid_input
“””
repeatedly asks the user to input something until it is valid.
Input is considered valid if it is either:
“w”, “a”, “s”, “d”, or “l”
PARAMETERS:
None
Return:
input_string -str
“””
#update_angle
“””
Add the increment to the angle in the slingshot
Parameters:
aslingshot - slingshot
increment - int
Return:
updated_slingshot - slingshot
“””
#update_velocity
“””
Add the increment to the velocity in the slingshot
Parameters:
aslingshot -slingshot
increment - int
Return:
updated_slingshot - slingshot
“””
#launch_bird
“””
launches youdee such that the Youdee will be moving, and will have the initial x and y velocities
given by vx = v0 cos(Angle) and vy = v0 sin(angle) + .5*gravity.
Note: need to get the angle and velocity from the slingshot
Note: the slingshot angle is in degrees, while the math module’s cos/sin require radians.
Hint: Should you use math.degrees or math.radians?
Parameter:
ayoudee -YoUDee
aslingshot - slingshot
Return:
new_youdee- YoUDeee
“””
6.Develop the missing functions get_valid_input, update_angle, update_velocity, launch_bird used in the handle_input function above.
You can now uncomment the aworld = handle_input(aworld) in run_simulation
Now when you call input_main() the game will respond to presses of the w/a/s/d keys and YoUDee will “fly” when the l key is hit.
7.Our current simulation lets YoUDee fly right off the screen. Now, we want to (a) stop the simulation when the YoUDee touches the edge and (b) report either a hit or a miss on the target.
Develop a function did_hit that consumes a Youdee and a Target produces a boolean indicating whether YoUDee is currently hitting the Target. Use the distance formula below:
YoUDee is considered hit if the distance is less than or equal to 1.
8.Develop a function is_off_screen that consumes a YoUDee and produces a boolean indicating if the center of YoUDee (his current position) is off the screen on the right or the bottom (it’s OK if he flies off the top and comes back). Use the constant SCREEN_WIDTH—the maximum x position that a YoUDee can have.
9.Develop the function win_or_lose that consumes a World and produces a boolean value that is true if YoUDee either hits the target or goes off-screen and false if YoUDee is still flying across the green. If YoUDee hits a target, you should print “hit target”. If YoUDee goes off screen, you should print “off screen”.
10.You can uncomment the rest of the while loop and it’s body now and the complete simulation should run for one starting condition. We would now like to be able to plot the trajectory of YoUDee using python’s matplotlib module similar to the graphs like below.
Matplotlib is MATLAB-like 2D plotting library which produces publication quality figures.
Let’s examine how to create a figure. First, we need to import matplotlib and the pyplot module.
We use the as operator in order for us to create a shortcut to call the pylot module’s functions.
Instead of writing matplotlib.pyplot.function_name, we can now call a function with the following: plt.function_name
Similar to the Turtle module, we need to get a reference to the figure and axes. The axes are what you think of as “a plot”—the region of the image with the data space. A figure can have multiple axes, but a given axes object can only be in one figure. Imagine a figure is like a book and an axes is like a page within the book.
fig, ax = plt.subplots()
In order to plot data onto the axes, you can call the plot function.
ax.plot(xs, ys, color=”g”, label=”some label for the legend” )
where xs is a list of x values and ys is a list of y values corresponding to the x values. For example, xs could be something like [0,1,2,3,4] and ys could be [0, 1, 4, 9, 16]. This would model the function y = x^2
xs = [0,1,2,3,4]
ys = [0, 1, 4, 9, 16]
ax.plot(xs, ys, color=”g”, label=”some label for the legend” )
color=”g” specifies that the color of the line should be green and label=”some label for the legend” specifies that the line should have the corresponding legend “some label for the legend”
Now that we have a label for the legend, we need to make the legend appear on the axes. In order to do this, we can add the following after the plot calls:
ax.legend()
Lastly, in order for the figure to display, we need to call:
plt.show()
Putting it all together, we will have the following:
import matplotlib
import matplotlib.pyplot as plt
fig,ax = plt.subplots()
xs = [0,1,2,3,4]
ys = [0, 1, 4, 9, 16]
ax.plot(xs, ys, color=”g”, label=”some label for the legend” )
ax.legend()
plt.show()
You should get the following figure when you run the above code:
Though this graph has a pretty green color, this figure lacks finesse. We can add grid lines, a x axis label, a y axis label, title, and more.
For example, we can add grid lines using the following code before the show command:
ax.grid()
We can also add shapes onto the axes. Let’s add a circle to the above plot. You will need to first create a circle object and store it in a variable. For example:
some_circle = plt.Circle(position, radius, color=’g’)
where position is an (x,y) (Note: Just like a target!), radius is the radius of the circle (for example, this could be 1), and g is the color.
We would then need to add the circle to the axes.
ax.add_artist(some_circle)
Now, you should see a green circle and a green line on your figure. Note: anything added to the plot must be done prior to the plot being shown via plt.show()
Matplotlib is a powerful plotting tool. Be sure to look at the documentation for more details:
We would like to launch YoUDee from two starting locations with two different slingshots and hit two different targets and plot the trajectories of YoUDee with these starting conditions. Consider the following function run_quiet_simulation which does exactly everything of the run_simulation previously shown, but also returns the trajectory of the path as a list of xs and a list of ys required by the matplotlib’s plot function.
In order to run this code, we developed the following plotting_main with 2 YoUDee starting at (0,100) and (0,50) being flung to hit a target at (38,10), and (26,20) respectively. We extract the xs and ys from each of the flight paths and pass them into the plot_positions functions.
Develop a function plot_positions that consumes a list of xs from the first trajectory, a list of ys from the first trajectory, the target for the first trajectory, a list of xs from the second trajectory, a list of ys from the second trajectory, and the target for the second trajectory.
Plot the trajectories of the paths using the xs and ys. The line color of the first trajectory should be green. The line color of the second trajectory should be red. The legend for these lines should have “trajectory 1” and “trajectory 2” respectively. Additionally, add circles to represent the targets. The first target should be green and the second target should be red. The radius of both targets should be 1. Label the y axis as “Height” and the x axis as “Distance”. Set the title to be “Angry YoUDee Trajectories” Finally, show the grid lines and the legends for this figure. This function should return both the figure and axes. (hint: return fig,ax)
One essential skill that all proficient programmers have is to be able to read the documentation. Use MatPlotLib’s documentation to determine how to create the figure as describe. If you’re stuck, feel free to ask a TA or instructor.
11. At this point, you should be able to run the simulation and have the graph of the trajectory shown; however, YoUDee misses because the slingshot is malfunctioning. The slingshots are launching YoUDee with an initial velocity of 10 m/s. Adjust the angles defined in angle1() and angle2() in order for YoUDee to hit the target.
You can use the kinematic equations OR by trying multiple values using the simulation! We strongly suggest you to use the plots you generated to guide your search since simulating YoUDee’s trajectory doesn’t cause any damage compared with actually launching YoUDee across the green. After correcting your angles, you should have a plot that looks exactly like the one below.