Project 3: Scenes within Scenes Assigned: Wed Feb 19 2014 Due: 11:59:59 PM on Tue Feb 25 2014 Team Size: 1 Language: Python Lab:
The goal of this lab and project is to incorporate loops and
conditionals into your code as well as provide more practice in
encapsulating code and concepts for later re-use and manipulation.
Tasks
-
In your personal file space, make a folder called Proj3.
-
Open a text editor (e.g TextWrangler). Create a new file called
lab3.py. Put a comment at the top of the file with your name,
date, and the file name. Save it in the Proj3 folder.
-
After the comment line, write the command to tell python to import the
turtle package, random package, and the sys package:
import turtle
import random
import sys
-
First, let's find out what the sys package can do for us. Put the
following line of code in your file.
print sys.argv
Save your file, cd to your working directory, and then run your
lab3.py file. What do you see?
Now type some additional things on the command line after
python lab3.py. For example, try:
$ python lab3.py hello world 1 2 3
What do you see?
The sys package gives us the ability to see what the user has typed on
the command line. Each individual string (defined by spaces) from the
command line is an entry in a list, which is a data type that we
describe as a sequential container.
-
Add the following three lines to your lab3.py file.
print sys.argv[0]
print sys.argv[3] * 3
print int( sys.argv[3] ) * 3
Then run the program using the following command.
$ python lab3.py three times 3
What is going on? The first of the above three lines prints out the
first item in the sys.argv list. The second line accesses the fourth
item in the sys.argv list, which is a string with the digit '3' in it,
and multiplies it by 3, which repeats the string three times. The
third line accesses the fourth item in the sys.argv list, converts it
to an integer type and then multiplies it by 3, which prints out the
results of 3*3.
How could you use the capability to access values from the command
line in a program?
-
Remove the all of the print statements from the prior steps and type
(or copy and paste) the following code for making a star into your
lab3.py file right after the import statements.
def star(x, y, size):
'''Draws a 5-pointed star starting at location (x,y) with sides with the given size.'''
turtle.up()
turtle.goto(x, y)
turtle.down()
for i in range(5):
turtle.forward(size)
turtle.left(144)
turtle.tracer(False)
turtle.color(1.0, 1.0, 0.2)
n = int(sys.argv[1])
for i in range(n):
star(random.randint(-300, 200), random.randint(0, 200), random.randint(5, 15))
turtle.update()
raw_input('Enter')
Run the code using:
$ python lab3.py 50
Try running it with other command line values and see what
happens. Try running it with no command line value.
-
One thing you discover when you write software is that users do not
always do what they should. They don't always give you enough
information or the correct information. If you want to have a robust
program, you have to check the information coming in to see if it is
there.
For example, are there reasonable bounds on the number of stars in the
image? What if the user does not put a command line parameter?
One strategy is to pick a default value (e.g. 100) and create a
variable to hold the default value.
n = 100
If the user gives you a new value, then use the new value.
# check for user input
if len(sys.argv) > 1:
n = int(sys.argv[1])
The idea of having default behavior that the user can override is
common in computer programs.
-
Now we're going to explore the range function that is important for
common loops in Python. Open up the Python interpreter in a
terminal. Then call the built-in function range with a single
integer as its argument:
$ python
>>> range(10045)
Try it again with other arguments. (I recommend using smaller integers.) What does the function return?
Try giving the function two arguments. What does it return? Try
several different pairs of arguments.
Try giving the function three arguments. What does it return? Try
several different sets of arguments.
More information on the range function is stored in its docstring. You can access that by typing:
>>> help(range)
(You can exit the help by pressing the q-key.) How does it match with what you discovered?
-
Go back to your lab3.py file. You now know what the range function
does. Create a function called star2(rays, size) that takes
two arguments. Inside the star2 function, write a for loop using the
range function with rays as the number of times to loop.
Inside the loop, print out the loop variable. The loop variable is
the symbol after the for keyword and is also called the loop control variable. The code below is an example.
def star2(rays, size):
'''Draws a star with the given number of rays, each of length the given size.'''
# loop over the list returned by the range function
for i in range(rays):
print i
Put a call to the star2 function with the arguments 10 and 50 in your
main code section. Run your program and see what prints out.
-
In the star2 function, inside the for loop, set its heading to i * 360 /
rays and then have the turtle go forward by size and backward by size.
def star2(rays, size):
'''Draws a star with the given number of rays, each of length the given size.'''
# loop over the list returned by the range function
for i in range(rays):
turtle.setheading(i * 360 / rays)
turtle.forward(size)
turtle.backward(size)
What is this going to do? What happens if you give it different arguments?
-
Modify your main code so that it checks for a second argument from the
command line and assigns an int version of it to the variable rays.
Set the default value for the number of rays to 10. Use the variable as
the first argument to star2.
When you have it working correctly, you should be able to control the
number of lines and the length of the lines on the command line.
-
The final lesson on code organization today is enclosing all of your
top-level code in a main function and the making the execution of that
function dependent upon whether the file was imported into another
file or run from the command line.
Put all of your top-level code in the body of a new function called "main". After the
main function definition, put the following top-level code.
if __name__ == "__main__":
main()
Run your file.
The above conditional statement will be true only when you run the
python file on the command line. If you were to import this file into
another python program, the conditional statement would evaluate to
false and the main function would not run.
The real benefit is that you can write test functions for a collection
of functions--like your shapes.py file--without having your test
function interfere with importing it into other programs.
From now on, your files should always have that conditional in front of top-level code.
Assignment:
The goal of this project is to incorporate loops and
conditionals into your code as well as provide more practice in
encapsulating code and concepts for later re-use and manipulation.
Tasks
-
Create a new file called things.py. Copy the goto and block
functions from your Proj2/shapes.py file into things.py. Add a parameter called
fill to the block function.
First, re-write the block function to take advantage of looping, if
you have not already done so.
Second, edit the block function so that if the fill variable
has the value True , then the block should be filled. If the
fill variable has the value False , then the block should not
be filled. You can use an if-statement before and after the drawing
commands for your block to control whether to call the turtle's fill
function.
You may also want to add an optional color argument to your block
function. You can specify colors for the turtle using one of two
methods: as a string, or as an rgb-tuple.
The strings you can use to specify colors are given
here.
An rgb-tuple is simply three values in the range [0.0, 1.0] as a
comma-separated list surrounded by parentheses. For example:
(0.15, 0.6, 0.2)
makes a nice artificial grass green. You can use an rgb-tuple or a
string when calling the turtle.color function. The following two calls
create identical colors.
turtle.color("Forest Green")
turtle.color( (0.13, 0.55, 0.13) )
Don't forget to add appropriate documentation for your functions. Each docstring should state what shape the function draws, and where and how big the shape will be (e.g. if the scale is 1, then this will draw a house with its upper left corner at (x,y) and will be 200 pixels high and 150 pixels ide).
-
For at least 2 more of your basic shape functions from Proj 2, copy them to your
things.py file, edit them to use loops wherever it makes sense and
give them a fill parameter that controls whether the shape is filled
or not. As with the block function, you may also want to add a color
argument.
-
For at least 2 of your aggregate shapes from Proj 2, copy them to your
things.py file, rewrite them using the new functions with the fill
parameter and take advantage of looping wherever possible. The goal is
to make your code as efficient as possible.
If you wish, use conditional statements to enable variations on the
complex shapes. For example, you can make any function call dependent
upon a random number using the following type of test. In the example
below, the block will be drawn 70% of the time.
if random.random() < 0.7:
block(x, y, w, h, True)
-
Pick one of your scenes from Proj 2 (or create a brand new
scene, if you wish). Copy it to your things.py file and re-write it so
the entire scene is parameterized by x and y locations and a scale
parameter. In other words, you should be able to have your scene draw
anywhere on the screen at any size.
If you have a scene that looks like the following:
def myScene():
'''This draws a scene with .........'''
block(5, 10, 50, 100)
triangle(5, 100, 50)
goto(30, 30)
turtle.forward(10)
turtle.left(90)
turtle.circle(20)
You can easily convert it to a scalable, moveable scene using the
following rules. First, change the function to have parameters x, y,
and scale.
-
For calls to a function that takes (x, y, size) or (x, y, width,
height):
block(a, b, c, d) becomes block(x+a*scale, y+b*scale, c*scale, d*scale)
-
For calls to the goto function:
goto(a, b) becomes goto(x + a*scale, y + b*scale)
-
For calls to the turtle forward or circle functions:
turtle.forward(a) becomes turtle.forward(a * scale)
Angles do not change. Following the above rules, the myscene function
would be the following.
def myScene(x, y, scale):
'''This draws a scene with .........'''
block(x + 5*scale, y + 10*scale, 50*scale, 100*scale)
triangle(x + 5*scale, y + 100*scale, 50*scale)
goto(x + 30*scale, y + 30*scale)
turtle.forward(10*scale)
turtle.left(90)
turtle.circle(20*scale)
-
Create a task1.py file that imports things.py and uses the scene
function to draw several versions of the scene.
The first required picture is an image with three differently
sized versions of your scene.
-
Create a task2.py file that creates a new scene. The new scene should
incorporate the scene (from task1.py) at least once. For example, you could
make your it appear as a window or painting within the new
scene. You could also make the scene appear like a picture in a
travel brochure. Make sure the new scene is created inside a
function.
The second required picture is an image with your first scene
located inside a second scene.
-
Edit one of your two scenes so that some aspect of the scene depends
on a new parameter. It does not have to be fancy. Set up your program so
that the value of the parameter comes from a command-line argument.
Create two images showing how the command line argument affects the
appearance of your scene.
The third and fourth required images should be examples of one
of your scenes drawn using two different values for the command-line
parameter.
Extensions
Each assignment will have a set of suggested extensions. The required tasks constitute about 85% of the assignment, and if you do only the required tasks and do them well you will earn a B+. To earn a higher grade, you need to undertake one or more extensions. The difficulty and quality of the extension or extensions will determine your final grade for the assignment. One complex extension, done well, or 2-3 simple extensions are typical.
-
Get both of your scenes from last week (or new ones you
created this week) into the new scene as paintings or windows.
-
Make use of the range function in creative ways, using 2 or 3
arguments.
-
Demonstrate several levels of encapsulation (scenes within scenes
within scenes).
-
Make complex scenes without using complex code.
-
Have the command line arguments control a number of different aspects
of the scene. For this one, you must be sure that you use sys.argv in your main program only. If you have a function in things.py access the command line parameters then you are dramatically restricting which main programs can use that function.
-
Use a Python feature that is new to you.
Writeup and Hand-in
Before handing in your code, double check that it is well-styled:
- All file names use the case we requested.
- All variable names and function names use either camelCase or snake_case.
- All functions and files have docstrings. (One nice way to check this is to generate the documentation webpages and see that they contain everything.)
- Comments are added to explain complicated code blocks.
- All variable and function names are appropriately descriptive.
- Functions are defined before any other code is added at the top level of each file.
- Top level code is wrapped so that it won't execute if that file is imported by another.
Turn in your code by putting it into your private handin directory on the Courses server. All files should be organized in a folder titled Proj3 and you should include only those files necessary to run the program. We will grade all files turned in, so please do not turn in old, non-working, versions of files.
Make a new wiki page for your assignment. Put the label cs151s14project3 in the label field on the bottom of the page. But give the page a meaningful title (e.g. Kyle's project 3).
In general, your intended audience for your write-up is your peers not in the class. Your goal should be to be able to use it to explain to friends what you accomplished in this project and to give them a sense of how you did it. Follow the outline below.
-
A brief summary of the task, in your own words. This should be no
more than a few sentences. Give the reader context and identify the
key purpose of the assignment.
-
A description of your solution to the tasks, including any images
you created. This should be a description of the form and
functionality of your final code. You may want to incorporate code
snippets in your description to point out relevant features. Note
any unique computational solutions you developed. Code snippets
should be small segments of code--usually less than a whole
function--that demonstrate a particular concept. If you find
yourself including more than 5-10 lines of code, it's probably not a
snippet.
-
A description of any extensions you undertook, including images
demonstrating those extensions. If you added any modules,
functions, or other design components, note their structure and the
algorithms you used.
-
A brief description (1-3 sentences) of what you learned. For example, think about the answer to these questions: Did you have any setbacks or frustrations? If so, how did you overcome them? Did you encounter any surprises (good or bad)? Did you do any experimenting and, if so, how did it turn out?
-
A list of people you worked with, including students who took the course in previous semesters, TAs, and professors. Include in this list anyone whose code you may have seen. If you didn't work with anyone, please say so.
-
Don't forget to label your writeup so that it is easy for others to find. For this lab, use cs151s14project3
|