Lab 3: More Functions and Drawing with Turtle Graphics

If you find typos or problems with the lab instructions, please let us know.

Goal

The goal of this exercise is to begin to implement more complex programs and to become familiar with Python’s Turtle package. In particular, you will:

  • Read data from a (csv) file

  • Use a loop to process data

  • Create graphical programs using Python’s Turtle package

  • Visualize the path and strength of hurricanes

There is both a pair and an individual component of this lab. The individual component will be completed first. You may not start the pair portion until both you and your partner have completed the individual component. When you get to the pair portion, you must use pair programming. Remember that this means two people will work at the same computer, one driver and one navigator (since this is over Repl, obviously you can't be at the same computer, but there should still be one driver and one navigator). The driver does the typing and using the mouse, while the navigator makes suggestions, points out errors, and helps guide the process. You should switch roles every 15-30 minutes.

Setting up lab03 git repo (with your partner)

You will create one repository for this assignment between the two of you, but you will need to import some starter code. Since you're importing starter code, we'll be creating the repo a little differently than normal.

Create a joint git repo on github (in the UCSD CSE SPIS 2021 group) for you and your partner for lab03, and name it spis21-lab03-name1-name2. Make sure it's public and that it's a completely empty repository with no readme, no .gitignore, and no license. We will make the repo private a bit later, but it must initially be public.

After you create the new repository, you will see a new screen with the option to import code from another repository. You should import the code from this repository:


https://github.com/ucsd-cse-spis-2021/lab03starter.git


It will take a few minutes, but when you return to the repo on github you should see some starter code.

Now, let's open this project in Repl. Go to the Repl.it website, click the blue add button in the top right corner, click the "Import from GitHub" tab and then search for your newly made github repo (it should be under ucsd-cse-spis-2021/new_repo_name which should be spis21-lab03-name1-name2) and click "Import from GitHub".

If Repl.it pops up a prompt asking if you want to subscribe to the "Hacker" plan, that means that you forgot to make your github repo public: Repl.it requires you to pay for an upgraded account to clone from private github repos (which is why we created a pubic github repo). Just click "Cancel" at the bottom of the popup to ignore it, then go to your github repo's "Settings" page, scroll all the way down to "Danger Zone", click "Change visibility", select "Make public", type your repo's name to confirm, and click the "I understand, change repository visibility." button. After doing this, your github repo should now be pubic, and you can try connecting your repl to it again using the instructions in the previous paragraph.

Now, in Repl.it, there should be three windows: the code editor, the terminal, and a configuration tool (if you don't see the configuration tool, it should be fine, just skip the configuration instructions). For the configuration tool, choose Python as the language, ignore the "configure the run button", and then click "Done". Now, share this Repl project and the github repo you previously made with your partner.

Your repl is now connected with your github repo, but your github repo is still public, so we need to make it private! Go to your github repo's "Settings" page, scroll all the way down to "Danger Zone", click "Change visibility", select "Make private", type your repo's name to confirm, and click the "I understand, change repository visibility." button. Now, your github repo is private, but your repl is still able to push to it, and all for free!

Now, share both the Repl project and github repo with your partner, and you should be ready to begin the individual portion!

Next, you will complete the individual portion of your assignment, adding your files to this shared repo.

The Individual Portion: Getting Familiar with the Turtle

To warm up with the Turtle, you will use the Turtle to draw your first initial (the first letter of your first name) on the screen.

You should complete the entirety of step 1.1 and 1.2 individually. You may talk to your partner and have them help you, or give help to your partner, but you should try to do as much of it on your own as possible, and all the code you write should be done individually.

Before writing any code, we have to change the indentation of this project. By default, Repl projects' indentation is 2 spaces, but the starter code has an indentation of 4 spaces. If the files don't have consistent indentation, you will get errors when trying to run your code! To do this, go to your project settings (the button that looks like a gear under the left navbar), scroll down to indent size, and select 4. If your indentation is already 4, then no worries!


Step 1.1: Get familiar with the Turtle

Create a new file named lab03Warmup_YourName.py where YourName is replaced with your first name. At the top of this file put a comment with your name and a description of what this file will do (a program to draw the first letter of your name).

In order to work with the Turtle, you need to import the turtle module. Do this by putting the line:

import turtle

at the top of your file, either before or after the comment you wrote. This above line tells Python about the turtle library and allows you to call its functions.

Next, let’s write a simple function that uses the Turtle package to draw a shape. Copy the following code into your file.

def draw_picture(the_turtle):

''' Draw a simple picture using a turtle '''

the_turtle.forward(100)

the_turtle.left(90)

the_turtle.forward(100)

the_turtle.left(90)

the_turtle.forward(100)

the_turtle.left(90)

the_turtle.forward(100)

the_turtle.left(90)


my_turtle = turtle.Turtle() # Create a new Turtle object

draw_picture(my_turtle) # make the new Turtle draw the shape

What happens when you run your file? Use python file_name in the terminal to run your file. (The first time you run this, the Repl output screen might be frozen or laggy, so you might have to run the code a few times before seeing the correct output. You might have to do this throughout the rest of the lab as well.).

Suggested to get rid of lag: We won't go into too much detail at this point, but basically the reason that there is serious lag is because Repl.it computes the Turtle results on a server and then sends it back -- so it takes a while to get the results back! Repl.it has figured out a way to fix this by having client-side Turtle Graphics (if you don't understand what this means, it doesn't matter, just continue reading). To use the client-side Turtle Graphics and get rid of the lag, create a new Repl.it with the language "Python (with Turtle)", and then copy over the code you were planning on running in your original project to this new project. Tada, no more lag! Note: This will only work for part 1 and the challenge problems. For part 2, there's no way to get rid of the lag. Bigger Note: Once you've finished coding in this new project, make sure to copy the code back over to the old project! This is necessary so that you can add it to you Github repo.

Modify the function in various ways to see what happens: Change the number in the first the_turtle.forward() call in the draw_picture function. What’s the role of the number?

Change the values in the calls to the_turtle.left(). What units are being used?


What’s the difference between the_turtle, my_turtle and turtle?

You might notice that there seem to be three names “turtle” in the code above. What’s going on?! The Turtle library works a little differently than other libraries we’ve looked at so far, in that it uses a style of coding called “Object Oriented Programming”. You’ll learn much more about objects in CSE 8A or CSE 11, but for now you can think of objects as complex types of data that also have built-in functions associated with them.

So, turtle on the line

my_turtle = turtle.Turtle()

is the name of the package, i.e. the built-in Python library imported at the top of the file where you will find all of the functions for the Turtle. my_turtle and the_turtle are variable names. They each store references to (the same) Turtle object. Finally Turtle() is a special function that creates a new Turtle object.

We can create more than one Turtle to work with at a time. For example, try adding the following code to the end of your warmup file:

turtle1 = turtle.Turtle()

turtle2 = turtle.Turtle()

turtle1.setpos(-50, -50)

turtle2.setpos(200, 100)

turtle1.forward(100)

turtle2.left(90)

turtle2.forward(100)

Can you explain what’s happening?


Python’s “anonymous” Turtle

In the code above you noticed that by calling Turtle() three times we got three Turtles that we could control independently. However, if you know you only want to use one Turtle, Python will provide an “anonymous Turtle” that you can control without actually creating explicitly. So you might sometimes see lines of code that look like

turtle.forward(100)

turtle is still the package name, and the forward call will control the first Turtle created. Python will always create this first Turtle, even if you do not include any call to Turtle().


The turtle documentation

It’s a good idea to check out the library documentation (a.k.a. reference manual, API docs, etc.) when you’re learning how to use a new library (aka set of methods).

Here's the entry in the documentation for the function that lets us move forward:

turtle.forward(distance)

turtle.fd(distance)

Parameters: distance – a number (integer or float)

Move the turtle forward by the specified distance, in the direction the turtle is headed.


Add and commit your code

Now is a good time to make sure you’ve got helpful comments in your file and that you’ve saved it (Repl should save it automatically). Also add your file to your repository at this point (if you don’t remember how, check the instructions in lab02) and then commit your code so far. You do not need to push it to github yet.


Step 1.2: Write a method to draw the first letter of your first name

Create a new file named drawLetter_YourFirstName.py. In that file, write the following method:

draw_A(the_turtle)

Note that the name of this method should correspond to the letter you are drawing. So if my name is Chris, my function would be named draw_C. The parameter to this method, the_turtle, is the turtle you should use to draw the letter.

Feel free to be creative here. Right now, you can draw the letter any size, using any style. You will probably find the functions penup and pendown useful, but check the documentation for other functions that will allow you to change the style of the lines your turtle draws.


Test your function

Test your function to see if it works by creating at least two different Turtles, moving one of these Turtles away from its default position (you probably want to lift the pen before moving the Turtle), and then calling your draw_A function with each Turtle. You should see two letters drawn, one drawn by each Turtle (one after the other). Does the output look good? Do both the Turtles draw? If there are bugs in your code (we’d be surprised if there weren’t!) fix them before moving on (though remember you can always add and commit non-working code to your repo with an appropriate comment). Be careful not to move your turtle off the screen, because you won't able to see it drawing!


Add, commit and push

At this point you are almost finished with the individual portion and ready to commit and push your code so far. Here’s a checklist to make sure you haven’t forgotten anything:

  1. Do you have a comment at the top of your files?

  2. Do you have a draw function for your first initial?

  3. Does this function have one parameter: a turtle?

  4. Does this function have a reasonable docstring (recall from class what a docstring is)

  5. Did you test your function with at least two Turtles to make sure it’s working correctly? (And is it?) If so, you are ready to submit!

To submit, use the command line tools git add, git commit and git push. You must only push working versions of your code (though you can commit code in progress locally). Make sure your code is pushed to git by navigating to your repo on github.com and viewing your latest changes (you may have to reload the page).

What happens if it won’t let you push?

You might get a message at this point telling you that your push failed. This will happen if your partner has pushed before you. Now you need to incorporate their changes to the central repository into your local version of the repository before github will allow you to push. To do this you will need to execute a pull command in the terminal:

git pull origin master

Then you will be able to push and everything should be okay. Since you and your partner have been editing different files, you should not have any merge conflicts, but if you do, stop and ask a mentor for help.

See the documentation on this page for a bit more information.

At this point you are done with the individual portion. If your partner is not yet done, DO NOT CONTINUE. Here are some things you can do while you wait for your partner:

  • Work on APS

  • View and respond to the enrichment video

  • Make your letter prettier/more interesting

  • Make more functions to draw more letters (try drawing out your whole name!)

The Pair Portion: Doing more with the Turtle

STOP! Do not start on this part of the lab until BOTH partners have completed the individual portion. When you do start, make sure you use pair programming.

Step 2.0: Discuss with your partner

Discuss the following questions with your partner, then put your joint answers into comments at the top of a new file named lab3Letters_pair.py.

  1. What is the “anonymous turtle”?

  2. In the code below, what is the difference between turtle and Turtle()?

my_turtle = turtle.Turtle()

draw_picture(my_turtle)

  1. Imagine that I have a turtle in a variable named my_turtle. What line of code will change that turtle’s y-position to 100?


Step 2.1: Extend your draw_A function

Choose one of your draw_A (or whatever letter you used) functions and copy it into your lab03letters_pair.py file. Then, modify the function as follows:

Add another parameter to your draw_A function: draw_A(the_turtle, size)

  1. size will determine the size of your letter.

  2. Modify the code in the method so that it respects the size parameter. You are free to use any interpretation of size that you wish, but your letter must be drawn in different sizes for different values of that parameter. Make sure you modify the docstring for your modified function so that it accurately reflects what this new version of the function does.

Finally, test your new function to make sure that it respects the size parameter. Fix any bugs you find, then add this file to your repository, commit and push.


Step 2.2: Tracking Hurricanes!

Switch driver and navigator if you have not yet done so.

This part of the assignment is based on a SIGCSE Nifty Assignment.

In this part, you and your partner will use the Turtle to animate the paths of some real hurricanes! Your goal is to build a program that functions like the one in this video. Here are the details:


Understand the starter code

Open the starter file irma.py.

In the irma_setup() function, the following are done for you:

  • Creating the screen and turtle

  • The turtle’s shape is changed to that of a hurricane

  • Loading a background image of the Atlantic

  • Setting the world coordinates of the screen to match the latitude and longitude on the map

Do not change the irma_setup() function!

You will add your code into the function irma(). Read the comments and the code in that function and make sure you understand what it does so far. Try moving the turtle (t) around and see it animate. Notice the coordinates of the world have been changed from their default. The x values in the new coordinate system range from -90 to -17.66 and the y values range from 0 to 45. Since the Turtle starts at (0,0) you cannot see it. Try moving it to a location where you can see it in the new coordinate frame and making it move.

You will also notice that this starter code uses a file named irma.csv in the data directory. This data was scraped from Weather Underground, last access 9/14/2017. This file contains data about hurricane Irma. Each line contains 6 columns separated by commas (thus the .csv file extension). The file can be opened directly in Repl or opened in Excel for a columnar view. The first line of the file describes what each column is. Here are the first 3 lines of the file, separated into their columns:

Date Time Lat Lon Wind Pressure

30-Aug 15:00 GMT 16.4 -30.3 50 1004

30-Aug 21:00 GMT 16.4 -31.2 60 1001

The only columns relevant to your code are Lat (the latitude), Lon (the longitude), and Wind (the wind speed in miles per hour). Carefully check out the Lon (longitude) and Lat (latitude) values -- which value correlates with x and which value correlates with y?


Add code to make the Turtle trace the hurricane’s path

You might have to run the turtle code several times before seeing correct output, as the Repl output screen sometimes freezes or is laggy.

Using the data in irma.csv, your irma function must show hurricane Irma’s path. Your solution should look like the video and must include the following:

  • Correctly show each point in the data file (together with lines between each point)

  • At each point, if the storm has hurricane strength winds, you must write what category the storm is, otherwise, draw no text. You can use Google to find the wind speeds for each category of hurricane.

  • Color code the hurricane strength:

    • Red for Category 5

    • Orange for Category 4

    • Yellow for Category 3

    • Green for Category 2

    • Blue for Category 1

    • White if not hurricane strength

  • The thickness of the line should change in proportion to the hurricane category.

Check out the video example listed earlier if you're wondering how this should look like.

Notice that the starter code already uses the csv package to read the lines from the data file. The csv package is already imported at the top of the irma.py file, and we’ve provided some comments and code to help you understand how you can read the lines and get the data out of the lines in the file. Make sure you understand how this works before you attempt to change the code. If you have questions, ask a mentor.

We have provided some comments in the starter code to help you out, but this is a more open-ended task than you’ve done in the past. Make a plan with your partner before you attempt to start coding


Run, test and debug your code

Make sure you run your code, and look at the data, to test your code.

Ensure the following:

  • Does your line start in the same position as the demo? Remember, you need to move the turtle to the starting latitude/longitude with the pen UP so you don’t draw a line that’s not part of the hurricane data.

  • Do the number and order of 1s, 2s, 3s, etc, on your path as well as the color of the points in your path, match the demo?

  • Does the path go in the same direction as in the demo?

  • When you run your code on other data files, do you get the path you’d expect (after looking at the data)? You can change which file is opened inside of the irma() function (look for hurricaneFile)


Submit everything!

Once you’ve got your hurricane tracker working, make sure of the following:

  • Do you have your names and a comment at the top of each file?

  • Do you have docstrings for each function you wrote?

  • Did you use meaningful variable names?

  • Did you use appropriate commenting in your code when something might be unclear to the reader?

Once you can answer yes to all of the following make sure you add ALL of your files from this lab (the two files from the individual part (4 between the two of you) and the two files you created for the pair part) to your repo, then commit and push to github. Then you are done! But of course, you’re never done, so keep working on creative extensions of your own!

Challenge Problem - Build your own game

For this challenge problem, you are asked to build your own game with turtle. Check out the sample code below. The only really new concept is how to react to key strokes with the onkey function: for each key stroke event (i.e., pressing that key), there is an associated function that is executed in response. For example, turtle.onkey(speedup,"d") causes the speedup() function to be called each time the “d” key is pressed. That line of code doesn’t actually call the function; it simply informs the program that each time “d” is pressed, the function should be executed.

Also note the use of the keyword global in the speedup() function. It tells the function that the variable speed1 is a global variable, which means that it is defined outside of the function. Without specifying that speed1 is something Python can find outside the function, it would complain that inside the function is has never heard of speed1 before. Remember, inside a function, only the variables that are defined there (such as the arguments that are passed to a function) are available. The way you have modified global variables before was to pass them as arguments to a function and then return the result. Directly modifying a global variable is an alternate way of doing this. It is generally considered less desirable, as it is not as obvious what is going on to someone reading your code and if you make a mistake it can cause undesired effects that are hard to debug. However, since we are tying a function to a keystroke in our interactive turtle example and we cannot return anything, it is useful here.

Important: For the onkey function to work while you're running the python program, you need to be focused on the output window. So click on the output window with your mouse after starting the program in the terminal window.


import turtle

import time


# Create a turtle

player1 = turtle.Turtle()


# Set the simulation speed to max. This is not the speed of the turtle, but specifies

# how fast the animations are updated. A value of "0" is best for smooth animations

player1.speed(0)


# Function that will be executed on a specific key stroke (see below)

# It causes player1 to turn left

def turnleft():

player1.left(30)


# Function that will be executed on a specific key stroke (see below)

# It causes the speed of player 1 to double

def speedup():

global speed1

speed1 = speed1 * 2


# This code makes the turtle library listen to key strokes

# Then for the keys listed, e.g., the left arrow or the "d" key,

# it specifies which function will be executed when that key is pressed.

# You can list additional keys and tie them to your own functions

turtle.listen()

turtle.onkey(turnleft, "Left")

turtle.onkey(speedup,"d")


# The initial speed of player 1

speed1 = 0.25


# Print the current time

# This is Unix time, i.e., the time in seconds since 1/1/1970

print(time.time())


# This is the main game loop

# It is an infinite loop; this code is executed forever

while True:

player1.forward(speed1)


Task 1: Expand the game where the speed of the player is doubled automatically every 5 seconds. Remove the “d” key input, but instead use the right arrow to turn right. The player dies when they go outside of the field, past the boundary (think, how does the player "die"?). Define as the score, the number of seconds the player was able to stay alive.

Task 2: Add other fun features to the game. Maybe have another turtle run around randomly, which you also must avoid. You can also use another turtle to implement objects you can grab, which would lower the speed again. Maybe the right and left key swap functionality every so often. Think of some more variations …

Task 3: Create your own game. How about a multiplayer game? We’d all love to see what you can come up with.