Problem Set 4 - Due Tue, Oct 02 at 23:59
- Slides and notebooks from Lec 04 Functions, Lec 05 Divide/Conquer/Glue with Pictures, Lec 06: Booleans, Logical Expressions, and Predicates and Lec 07: Conditionals You do not need (in fact, should not use material from) Lec 08 Sequences and Simple Loops.
- Problems and solutions from Lab 03 Functions and Lab 04 Conditionals
- Think Python, Chapter 5: Conditionals (Secs 5.1 -- 5.7)
About this Problem Set
This problem set is intended to give you practice with conditionals and the Divide, Conquer, and Glue (DCG) problem-solving strategy.
- In Task 1 (individual task), you will write functions using conditionals to create a rock-paper-scissors game.
- In Task 2 (partner-optional task), you will make some Blob simulations using functions that involve conditionals.
- In Task 3 (partner-optional task), you will create quilt patterns using functions.
Unlike the previous two problem sets, this one has three tasks, and two of them are partner-optional. In Tasks 2 and 3, having a partner is optional, but strongly recommended. You can choose to work with a partner on both of the tasks, or just one of the tasks if you prefer. However, if you choose both of the tasks, you should work with the same partner on both tasks. If you want to have a partner, use this shared Google Doc. Remember, you can talk with other individuals and teams about high-level problem-solving strategies, but you cannot share any code with them.
- When you're done with the 3 tasks, fill out your honor code form and follow the submission instructions to submit your pset.
- The CS111 Problem Set Guide gives an overview of psets, including a detailed description of individual and partner tasks.
- Follow the style guidelines in the CS 111 Code Style Guide
In Spring 2018, students spent the following times (in hours) on the two required tasks:
Task Average Median 25% took more than 10% took more than Task1 1.9 1.5 2.0 4.0 Task2 2.5 2.0 3.0 4.6 Task3 3.5 3.0 4.0 5.5
- All code for this assignment is available in the
ps04folder in the
cs111/downloaddirectory within your
csserver account. This assignment also uses the Codder program to help you do a final check of the first two tasks before you submit. (Sorry, but we do not yet have a Codder tester for Task 3.)
Task 1: Rock, Paper, Scissors
This is an individual problem which you must complete on your own, though you may ask for help from the CS111 staff.
In this problem, you will define functions to play the game rock-paper-scissors. This is a game in which both you and your opponent each choose one of the three hand gestures rock, paper, or scissors, and the winner is chosen according to the following diagram:
Your task is to define the following five functions in the provided file named
def isValidGesture(gesture): """Returns True if gesture is one of the strings 'rock', 'paper', or 'scissors', and False otherwise. """ # Flesh out the body of this function def randomGesture(): """Randomly returns one of 'rock', 'paper', or 'scissors', with equal probability. """ # Flesh out the body of this function def beats(gesture1, gesture2): """Returns True if the first gesture beats the second gesture, i.e., if the first and second gesture are rock/scissors or scissors/paper, or paper/rock, respectively. Returns False otherwise. The output is unspecified if one or both gestures is invalid. """ # Flesh out the body of this function def play(yourGesture,opponentGesture): """Plays rock/paper/scissors game with your gesture vs. opponent's gesture. If both gestures are valid, displays one of 'Game is a tie!', 'You win!', or 'Opponent wins!'. Otherwise, indicates the first gesture that is invalid. """ # Flesh out the rest of the body of this function def playComputer(yourGesture): """Plays rock/paper/scissors with your gesture against a computer opponent that randomly chooses a gesture. First displays the choice of the computer, and then displays the result of the game. """ # Flesh out the rest of the body of this function
Interactive Testing in Canopy
One way to test your functions is to first run you program in the Canopy editor window (to load the function definitions) and then enter sample calls of your functions in the interactive console to test that they work correctly. Here are some examples:
In : isValidGesture('paper') Out: True In : isValidGesture('spock') Out: False In : randomGesture() Out: 'scissors' # You might get a different result because of randomness In : randomGesture() Out: 'rock' # You might get a different result because of randomness In : randomGesture() Out: 'scissors' # You might get a different result because of randomness In : beats('paper', 'rock') Out: True In : beats('scissors', 'rock') Out: False In : beats('rock', 'rock') Out: False In : play('rock', 'paper') Opponent wins! In : play('rock', 'scissors') You win! In : play('rock', 'rock') Game is a tie! In : play('rook', 'scissors') Your gesture (rook) is invalid In : play('rock', 'sissors') Opponent's gesture (sissors) is invalid In : play('spock', 'sissors') Your gesture (spock) is invalid In : playComputer('paper') Computer chooses rock You win! # You might get different printout because of randomness In : playComputer('paper') Computer chooses paper Game is a tie! # You might get different printout because of randomness In : playComputer('paper') Computer chooses paper Game is a tie! # You might get different printout because of randomness In : playComputer('paper') Computer chooses scissors Opponent wins! # You might get different printout because of randomness In : playComputer('rock') Computer chooses paper Opponent wins! # You might get different printout because of randomness
Automatic Testing in Canopy
Interactive testing can be tedious. As an alternative, we have provided
a special main conditional block at the bottom of
that includes test cases that will be automatically run every time you
run your program in Canopy. This section begins as follows
if __name__ == "__main__": """All code that tests the above functions should be nested within this special "main" conditional. """ print "isValidGesture('paper') -->", isValidGesture('paper') print "isValidGesture('spock') -->", isValidGesture('spock') print "\nrandomGesture() -->", randomGesture() print "randomGesture() -->", randomGesture() ... many more tests below ...
Feel free to add or comment out tests in this block as desired.
The Python function call
bare integers and
b) returns a randomly chosen integer in the range [
b] (inclusive). For example,
random.randint(1, 10)returns one of the integers between 1 and 10 with equal probability. The file
rockPaperScissors.pybegins with an
import randomdeclaration so that the
randommodule can be use in this program.
An important computer science principle is Don't Repeat Yourself (DRY). In this problem, you should avoid repeating yourself by using some of the functions you define as helper functions in other functions. For example, you should call the
beatsfunction within the
playfunction rather than repeating the logic of which gesture beats which other gestures within the
Once you're satisifed with testing all your functions within Canopy, use Codder to test
rockPaperScissors.py. This is a good way to check for any unexpected errors before you submit your code.
- For fun, check out the variant game rock-paper-scissors-lizard-Spock. Consider implementing this as an ungraded challenge problem. (But don't change your exisiting
rockPaperScissors.pyfile; make a new file with a different name if you decide to pursue this.)
Task 2: Blob Simulator
This task involves a whimsical simulation system with circular objects called blobs that follow rules to move around the four quadrants of a screen. Here's a short video of this simulation in action:
We give you most of the code for this simulation system and ask to fill in a small missing part of the code that implement the rules specifying the behavior of the blobs. These rules involve using conditionals.
You need to understand what the system is supposed to do in order to complete your part of the task. Most of this task description is an explanation of the blob simulation and the code that we've provided for you, so you'll need to do a lot of reading before you can start coding.
This problem uses a
cs1graphics layer called
quadrants that is contained within an 800x600 canvas.
The (0,0) point of the
quadrants layer is in center of the canvas, and there are
horizontal and vertical lines going through this point that divide the
layer into 4 quadrants. As usual in
cs1graphics, x coordinates increase to the right,
and y coordinates increase going down.
quadrants layer hosts a whimsical simulation system in which circular blobs
move around the layer. Each blob is just a colored, borderless
cs1graphics circle that is contained
quadrants layer. The reference point of a blob is it center, so we refer the x or y location
of a blob, we are referring the coordinates of its center point relative to the
On each step of the simulation, the blob is first moved according to the moving rules, and then might be scaled according to the scaling rules:
Rule M1 If the blob's current y coordinate is negative, it should move in the positive x direction by its current radius.
Rule M2 If the blob's current y coordinate is negative and its current radius is at least 100, it should also move in the positive y direction by its current radius.
Rule M3 If the blob's y coordinate is nonnegative, it should move in the negative x direction by its current radius.
- Rule M4 If the blob's y coordinate is nonnegative and its current radius is at most 20, it should also move in the negative y direction by 10 times its current radius.
Rule S1 If the blob's current radius is at most 200 and its center is in the upper right quadrant (i.e., the quadrant with nonnegative x and negative y), double the radius of the blob.
- Rule S2 If the blob's current radius is at least 10 and its center is in the lower left quadrant (i.e., the quadrant with negative x and nonnegative y), halve the radius of the blob.
We illustrate the rules in the context of a simple system with a single purple blob
with initial radius 50 and initial location (-75,25). Below we show a sequence of
state snaphots of this system in which each picture of a blob on the
is accompanied by text showing the state number and the properties of the blob,
The state number also appears in magenta in the upper left corner of
- By M1, moved right by radius (50).
- By M1, moved right by radius (50).
- Note: blob now in upper right quadrant.
- By S1, radius doubled from 50 to 100.
- By M1, moved right by radius (100).
- By M2, moved down by radius (100).
- By S1, radius doubled from 100 to 200.
- By M1, moved right by radius (200).
- By M2, moved down by radius (200).
- Note: blob now in lower right quadrant, so S1 does not apply.
- By M3, moved left by radius (200).
- By M3, moved left by radius (200).
- Note: blob now in lower left quadrant.
- By S2, radius halved from 200 to 100.
- By M3, moved left by radius (100).
- By S2, radius halved from 100 to 50.
- By M3, moved left by radius (50).
- By S2, radius halved from 50 to 25.
- By M3, moved left by radius (25).
- By S2, radius halved from 25 to 12.5.
- By M3, moved left by radius (12.5).
- By M4, moved up by 10 times radius (125).
- By S2, radius halved from 12.5 to 6.25.
- By M3, moved left by radius (6.25).
- By M4, moved up by 10 times radius (62.5).
- Note: blob now in upper left quadrant, so S2 does not apply.
- By M1, moved right by radius (6.25).
- By M1, moved right by radius (6.25).
blobSimulator.py file in the
ps04 folder contains almost all of the code for
simulating the behavior of blobs on the
quadrant layer. Although you don't need
to understand this code in detail, here we give an overview of key aspects of the code.
A blob is simply a borderless, colored circle that "lives" in a layer:
# Do not edit or change makeBlob def makeBlob(color, radius, x, y, containingLayer): """Create a new blob with the specified properties, and add it to the container layer. Return the blob. """ blob = Circle(radius, Point(x, y)) blob.setFillColor(color) # remove borders, which don't look good when scaled blob.setBorderColor('transparent') containingLayer.add(blob) return blob
run function runs the simulation on a given list of blobs for a specified
number of steps:
# Do not edit or change run def run(blobs, steps): """Run simulation on the given blobs for the specified number of steps""" # Print initial state of system printSystemState(blobs) # Run simulation for given number of steps for i in range(steps): nextState(blobs)
run function (and a few other functions) uses a simple loop to perform
an action for every blob in a list of blobs. You are not required to understand
loops for this assignment, but using loops in the simulation code simplifies
The core part of the
run function is calling the
on a list of blobs. This increments the state number in the upper left corner
quadrants layer, and updates the state of each blob according to
the movement and scaling rules explained above:
# Do not edit or change nextState def nextState(blobs): """Run one step of the simulation for the given blobs""" incrementStateNumber() # Increment state number in the upper left corner for blob in blobs: update(blob) printSystemState(blobs)
update function is not provided; your task is to flesh it out.
See the details below.
printSystemState function (provided) displays the current state of the simulation:
# Do not edit or change printSystemState def printSystemState(blobs): """Display the current state of the simulation for the given blobs""" print('-'*55) print('state: ' + stateLabel.getMessage()) for blob in blobs: printBlob(blob)
For example, here is the initial state of a system with five test blobs:
------------------------------------------------------- state: 0 purple blob: radius=50.0; location=(-75.0,-125.0) cyan blob: radius=30.0; location=(10.0,-250.0) red blob: radius=40.0; location=(300.0,150.0) yellow blob: radius=160.0; location=(-25.0,275.0) green blob: radius=125.0; location=(-275.0,-200.0)
printBlob function (provided) displays the current state of a single blob.
It uses several helper functions (all provided):
# Do not edit or change printBlob, blobState, blobX or blobY def printBlob(blob): """Print a line describing the current state of a blob""" print blobState(blob) def blobState(blob): """Returns a string describing the current state of a blob""" return str(blob.getFillColor()) + ' blob:'\ + ' radius=' + str(blob.getRadius())\ + '; location=' + '(' + str(blobX(blob))\ + ',' + str(blobY(blob)) + ')' def blobX(blob): """Returns x coordinate of center of blob""" return blob.getReferencePoint().getX() def blobY(blob): """Returns y coordinate of center of blob""" return blob.getReferencePoint().getY()
There is other code in
blobSimulator.py for creating the
and its enclosing canvas and adding to its upper left corner a text label
that contains the current step number of the simulation.
blobSimulator.py for all the details.
The only thing you must do in this problem is to flesh out the skeleton of
update function in
blobSimulator.py so that it implements all the
movement rules (Rules M1 through M4) and scaling rules (Rules S1 and S2)
def update(blob): """Update the state of a blob according to the movement and scaling rules in the ps04 task description. """ pass # Replace this stub with your code.
To implement the rules, you only need to use conditional statements involving the following blob operations:
Use the helper functions
blobYto get the current x and y coordinates of a blob. For example, if
purpleBlobis the example purple blob in state 0, then
blobX(purbleBlob)is -75 and
.getRadius()method to get the current radius of a blob. For example,
purpleBlob.getRadius()is 50 for the purple blob in its initial state.
.move(deltaX,deltaY)method to move a blob by
deltaXunits in the x direction and
deltaYunits in the y direction. For example if
purpleBlobis at location (100,-80), then
purpleBlob.move(-25, 50)moves it to (75, -30).
- Use the
.scale(factor)method to scale a blob by
You should first apply the movement rules to a blob before applying any
The locations mentioned in the movement rules are those before any of the movement rules have been applied.
- The locations mentioned in the scaling rules are those after all the movement rules have been applied.
The testing code at the end of
blobSimulator.pycreates a list
testBlobscontaining five test blobs. The first of these is a purple blob with the initial state of the example purple blob described above. This blob is named
purpleBlobin the code.
The easiest way to test your
updatefunction is to run Codder on
blobSimulator.py. This will invoke the test case
run(testBlobs, 12), which runs the simulation on the blobs for 12 steps. It will highlight any differences between the printed output of your simulation and the correct output.
The testing code at the end of
blobSimulator.pyhas the call
run(testBlobs, 12), which runs the simulation on the blobs for 12 steps. If your
updatefunction works correctly, the printed output of the simulation should be as follows. Note that the states of the purple blob are exactly as shown in the Example section above.
------------------------------------------------------- state: 0 purple blob: radius=50.0; location=(-75.0,-125.0) cyan blob: radius=30.0; location=(10.0,-250.0) red blob: radius=40.0; location=(300.0,150.0) yellow blob: radius=160.0; location=(-25.0,275.0) green blob: radius=125.0; location=(-275.0,-200.0) ------------------------------------------------------- state: 1 purple blob: radius=50.0; location=(-25.0,-125.0) cyan blob: radius=60.0; location=(40.0,-250.0) red blob: radius=40.0; location=(260.0,150.0) yellow blob: radius=80.0; location=(-185.0,275.0) green blob: radius=125.0; location=(-150.0,-75.0) ------------------------------------------------------- state: 2 purple blob: radius=100.0; location=(25.0,-125.0) cyan blob: radius=120.0; location=(100.0,-250.0) red blob: radius=40.0; location=(220.0,150.0) yellow blob: radius=40.0; location=(-265.0,275.0) green blob: radius=62.5; location=(-25.0,50.0) ------------------------------------------------------- state: 3 purple blob: radius=200.0; location=(125.0,-25.0) cyan blob: radius=240.0; location=(220.0,-130.0) red blob: radius=40.0; location=(180.0,150.0) yellow blob: radius=20.0; location=(-305.0,275.0) green blob: radius=31.25; location=(-87.5,50.0) ------------------------------------------------------- state: 4 purple blob: radius=200.0; location=(325.0,175.0) cyan blob: radius=240.0; location=(460.0,110.0) red blob: radius=40.0; location=(140.0,150.0) yellow blob: radius=10.0; location=(-325.0,75.0) green blob: radius=15.625; location=(-118.75,50.0) ------------------------------------------------------- state: 5 purple blob: radius=200.0; location=(125.0,175.0) cyan blob: radius=240.0; location=(220.0,110.0) red blob: radius=40.0; location=(100.0,150.0) yellow blob: radius=10.0; location=(-335.0,-25.0) green blob: radius=15.625; location=(-134.375,-106.25) ------------------------------------------------------- state: 6 purple blob: radius=100.0; location=(-75.0,175.0) cyan blob: radius=120.0; location=(-20.0,110.0) red blob: radius=40.0; location=(60.0,150.0) yellow blob: radius=10.0; location=(-325.0,-25.0) green blob: radius=15.625; location=(-118.75,-106.25) ------------------------------------------------------- state: 7 purple blob: radius=50.0; location=(-175.0,175.0) cyan blob: radius=60.0; location=(-140.0,110.0) red blob: radius=40.0; location=(20.0,150.0) yellow blob: radius=10.0; location=(-315.0,-25.0) green blob: radius=15.625; location=(-103.125,-106.25) ------------------------------------------------------- state: 8 purple blob: radius=25.0; location=(-225.0,175.0) cyan blob: radius=30.0; location=(-200.0,110.0) red blob: radius=20.0; location=(-20.0,150.0) yellow blob: radius=10.0; location=(-305.0,-25.0) green blob: radius=15.625; location=(-87.5,-106.25) ------------------------------------------------------- state: 9 purple blob: radius=12.5; location=(-250.0,175.0) cyan blob: radius=15.0; location=(-230.0,110.0) red blob: radius=20.0; location=(-40.0,-50.0) yellow blob: radius=10.0; location=(-295.0,-25.0) green blob: radius=15.625; location=(-71.875,-106.25) ------------------------------------------------------- state: 10 purple blob: radius=6.25; location=(-262.5,50.0) cyan blob: radius=15.0; location=(-245.0,-40.0) red blob: radius=20.0; location=(-20.0,-50.0) yellow blob: radius=10.0; location=(-285.0,-25.0) green blob: radius=15.625; location=(-56.25,-106.25) ------------------------------------------------------- state: 11 purple blob: radius=6.25; location=(-268.75,-12.5) cyan blob: radius=15.0; location=(-230.0,-40.0) red blob: radius=40.0; location=(0.0,-50.0) yellow blob: radius=10.0; location=(-275.0,-25.0) green blob: radius=15.625; location=(-40.625,-106.25) ------------------------------------------------------- state: 12 purple blob: radius=6.25; location=(-262.5,-12.5) cyan blob: radius=15.0; location=(-215.0,-40.0) red blob: radius=80.0; location=(40.0,-50.0) yellow blob: radius=10.0; location=(-265.0,-25.0) green blob: radius=15.625; location=(-25.0,-106.25)
- As mentioned above, the visual animation for
run(testBlobs, 12)animation looks like this:
- It's fun to run the simulator for a larger number of steps, such as
Task 3: Quilts
The CS111 Etsy shop wants to expand the items offered on their site.
Quilts would be an item that could generate a lot of revenue.
Below is an example of one of the CS111 Etsy quilt designs, which we will call
Another example is the following, which we will call the
You and several other CS111 students have been hired as interns at the CS111 Etsy shop to help design quilts. Your project is to use pictures to generate the quilt designs shown above. You'll notice that the quilts are the same except for the color scheme.
These quilts are just two sample of the quilt design. In your code, you will write functions that will take color parameters, and therefore can generate lots of different quilts, in the same pattern as above, but with color variation.
picture.py module, which contains picture functions you have
learned about in Lecture 05
and Lab 04, is provided in the ps04 folder. You
may use the functions defined in that module to help create your
quilts. All the functions that you will define for this problem will
be in a file that you will create called
Your goal is to write a
quilt function that takes several color parameters
and returns a picture corresponding to the quilt shown above when
quilt is invoked with appropriate colors. This picture is ultimately
generated by combining primitive pictures created by the following
two functions that you have already seen in class. They can be found in
patch (c): """Returns a rectangular patch of color c with a black border that fills a given picture frame. """ triangles(c1,c2): """Returns a picture that consists of two triangles filling the given picture frame: a black-bordered triangle of color c1 in the lower left corner of the frame; and a black-bordered triangle of color c2 in the upper right corner of the frame. """
For example, below are the pictures generated by some sample invocations of these functions:
Divide, Conquer, and Glue
The key to solving the problem of defining the
quilt function is to note that the picture
it returns can be decomposed into smaller pictures that are used more than once in the larger picture.
For example, by wishful thinking we can image that the upper right quadrant is a picture
returned by a function we'll call
block is clearly decomposable into subquadrants of two kinds,
which we've dubbed
diamond. Here are two roses:
Here are two examples of the pattern we called
Implement each of these, then combine these subproblem solutions to solve the whole quilt. How to solve these? Each of these patterns can be broken down into quadrants and those subproblems solved and combined with operations like rotation to solve the pattern.
This is an excellent illustration of the divide, conquer, and glue problem solving strategy we will use throughout this course:
Divide the problem into subproblems. Here, the whole
quiltproblem can be solved if we can solve the problem of generating the pictures in the different quadrants and sub-quadrants.
Conquer the subproblems by solving them. In this case, you'll want to solve subproblems like
diamondthat will help solve the whole problem.
- Glue the solutions to the subproblems together to form the solution to the whole problem.
Here, we combine four rotated versions of the picture returned by
blockto construct the picture returned by
But how do we solve the problems of defining the
functions? By applying the divide, conquer, and glue strategy again!
Of course, all of these functions will take appropriate color
Continue this way, decomposing each problem into smaller subproblems,
until you reach problems that can be solved using our primitives
triangles). For an example of this sort of
decomposition, see the quilt example from Lecture 05.
Starting the Assignment
Begin by creating a file named
ps04Quilt.py. As usual, your file must start with comments at the top, identifying the author(s), username(s), problem set and task number, filename, and date. Follow this format:
# Your name: # Your username: # Your partner's name (if applicable): # Your partner's username (if applicable): # CS111 PSO4, Task 3 # ps04Quilt.py # Submitted:
Remember to include the line:
from picture import *
at the top of your file, so that all of the functions in the
picture.py file are available to you.
Then use incremental programming to make progress on your quilt. That is, make approximations
to your quilt picture or parts of your quilt picture and use
displayPic to display
these pictures along the way.
You can work in one of two directions:
In the bottom-up strategy, you start with smaller helper functions, like those defined in the Helper Functions section below, and build up pictures of increasing complexity, including
diamond, until you have correctly defined the full quilt picture.
- In the top-down strategy, you start by defining the
quiltfunction in terms of the
blockfunction or the
diamondfunctions. But those are complicated, so you might put off the
diamondsubproblem while you work on the
rosesubproblem. So for testing purposes, you instead provide a so-called stub picture for the
diamondfunction. For example, as a very crude approximation, you might define an initial version of the
diamondfunction that returns the result of calling
triangleson two of its parameters. You can then test
quiltwith this approximation. Then you continue the top-down descent by defining initially-crude-approximations for functions that return the quadrants of the
blockpicture. You continue this top down process until you reach pictures that are correctly implemented by
triangles, at which point you now have the correct
quiltfunction rather than just an approximation.
Colors and Parameters
There are exactly six colors used in the Winter quilt and a different six colors in the Autumn quilt. All of the colors for the Winter quilt are listed in the examples above. The Autumn quilt uses the colors in the following examples:
rose('red','gold') rose('darkred','coral') diamond('darkred','coral','red') diamond('darkorange','bisque','red')
quilt function will take six colors as
arguments and return the appropriate quilt. You get to choose the order
of the six color parameters. (The
quilt function will not independently
be tested by Codder.)
However, you must define zero-argument functions
autumnQuilt that return the result of calling
quilt function on six appropriate color arguments.
def winterQuilt(): '''Returns the first quilt with the blue-green-purple theme''' return quilt( ... six color arguments go here ... ) def autumnQuilt(): '''Returns the second with the red-orange-yellow theme''' return quilt( ... six color arguments go here ... )
The quilt pictures returned by these functions should match the ones depicted at the beginning of this task. Codder will test the results of these two functions.
Ideally, color parameters should have meaningful names, but with functions
block that take lots of (six) color parameters, it's
challenging to design such names.
In our solution, the main quilt function takes six parameters,
which we named
c6. Then in the various subfunctions,
which take fewer colors, we didn't want to use the same numbers,
because it might be confusing.
If we think of
navy for example, we don't want to use
c1 in another function where it
plum. So some functions have arguments named
cz. Of course, Python doesn't care what we call our
parameters, and we can use the same parameter names in several different functions.
But remember that
programs are written for humans to read
and only incidentally for computers to execute. Even reading our own
code, we want to keep names clear in our minds.
As we have seen, a general principle of computer science is Don't Repeat Yourself (DRY), which means you should avoid writing the same pattern of code more than once. If you find yourself writing the same or similar code more than once in your program, you should write functions that capture the patterns of the repeated code and invoke the functions instead.
The divide, conquer, and glue process of defining
exposes the need for numerous auxiliary functions. Above, we have seen
diamond functions, which you must define.
As part of working on this task, you must also define and use the
following helper functions:
def bandana(c1, c2): """Returns a 2x2 picture with solid c1-colored patches in the lower left and upper right quadrants, and triangles(c1, c2) in the upper left and lower right quadrants.""" def lowerLeft(p): """Returns a picture which divides the picture space into four quadrants and places the given picture in the lower left quadrant. Nothing is in the other quadrants.""" def lowerLeftNest(p1, p2): """Returns a picture in which picture p2 is placed in the the lower left quadrant of picture p1.""" def lowerLeftNestSelf4(p): """Returns a picture that has four copies of picture p: one full size one, and three successively smaller versions descending in the lower left quadrant."""
Here is an example invocation of
Note that the
lowerLeftNestSelf4 functions take pictures as arguments, not colors. To illustrate these helper functions, suppose that pictures
picP2 are defined as:
Then here are examples of calling the
lowerLeftNestSelf4 functions with these pictures:
In this problem, you should not use any conditional statements.
In this problem, you should use functions from PictureWorld (like
clockwise90). You should not directly create any
cs1graphicsobjects (such as layers), nor should you use any
cs1graphicsmethods (such as
You must define the following functions in your program:
autumnQuilt. Additionally, you should define one or more other functions that help you abstract over other patterns.
You can use
lowerLeftNestSelf4in conjunction with
trianglesto create one of the patterns that appears in the quilt:
- Stepping back, your high-level goal in this problem is not only to generate the correct quilt picture, but to do so in a way that takes advantage of the power of abstraction to eliminate unnecessary repeated patterns in your code to make it as simple and elegant as possible. You want solution code that has the same level of abstraction and elegance as the code in slide 32 for the Lecture 05 quilt.
As you implement the above required helper functions and your own helper functions, you'll want to test them!
You should put the following testing code at the end of
# ------------------------- Testing ----------------------- if __name__ == "__main__": '''All code that displays pictures or prints output should be nested within this special "main" header at the end of ps04Quilt.py ''' closeAllPics() # Use this to close all previously created pictures. # Uncomment particular lines below to test your code. # Add more test cases for functions that you define! #displayPic(bandana('red', 'blue')) #displayPic(lowerLeft(triangles('red', 'blue'))) #displayPic(lowerLeftNest(patch('red'), triangles('red', 'blue'))) #displayPic(lowerLeftNestSelf4(triangles('navy', 'lightskyblue'))) ## Roses #displayPic(rose('navy', 'lightskyblue')) #displayPic(rose('darkseagreen', 'papayawhip')) #displayPic(rose('red','gold')) #displayPic(rose('darkred','coral')) ## Diamonds #displayPic(diamond('plum', 'orchid', 'darkseagreen')) #displayPic(diamond('navy', 'lightskyblue', 'darkseagreen')) #displayPic(diamond('darkred','coral','red')) #displayPic(diamond('darkorange','bisque','red')) ## Blocks #displayPic(block('navy', 'lightskyblue', 'darkseagreen', # 'papayawhip', 'plum', 'orchid')) ## Quilts #displayPic(winterQuilt()) #displayPic(autumnQuilt()) # Extra invocations to displayPic to fix picture glitch # (a simple picture is sometimes needed to have previous pictures display) displayPic(patch('red')) displayPic(patch('blue'))
Recall that in order to see your pictures, you'll need to to invoke
displayPic with an argument which corresponds to the picture you
want to display. As indicated in the above code, you should put all
displayPic at the very end of
indented within the special header
if __name__ == "__main__":
There is a glitch that sometimes happens with pictures as follows: a complex picture may not display unless one or two simple pictures are displayed afterwards. To play it safe, it is wise to always display two simple pictures after a complex one, like this:
displayPic(complex picture here) # this is the one you want to see displayPic(patch('red')) # 1st simple picture here displayPic(patch('blue')) # 2nd simple picture here
closeAllPics()function call closes all previously created pictures. The above testing code calls this first so you will only see the pictures from clicking the Run button, and not pictures from previous Runs.
Completing the Assignment
You should define all the helper functions specified above. In addition to that, you should define other functions that capture other patterns that appear in the quilt. It is also helpful to define local variables within your functions to give names to pictures that you generate as part of your solution.
Each of your functions should be short: no more than a few statements long (say 7 or 8). If you find yourself defining a longer function, consider how you can break it up into smaller parts (preferably in a way that permits one or more of the smaller functions to be used multiple times).
Remember that your quilt function takes six colors as arguments, so you will be able to create both the winter and autumn quilts with the same function, just supplying different sets of colors.
AS OF THIS WRITING, THERE IS NO CODDER TESTER FOR ps04Quilt.py, BUT THERE IS A CHANCE WE MIGHT PROVIDE ONE BEFORE THE DUE DATE. In the meantime, you'll need to do all of your quilt testing in Canopy.
Task 4: Honor Code File
Your honor code submission for this pset will involve
defining entering values for the variables in the
How to turn in this Problem Set
Softcopy (electronic) submission
- Save your final
rockPaperScissors.pyfile in the
- Each team member should save their final
ps04Quilt.pyfiles in their
ps04folders. The header comment at the top of these files should list the names of both partners (if you worked with a parter).
- Save your filled-out
honorcode.pyfile in the
ps04folder as well.
- Note: It is critical that the name of the folder you submit is
ps04, and your submitted files are named
honorcode.py. In other words, do not rename the folder that you downloaded, do not create new files or folders, and do not delete or re-name any of the existing files in this folder. We have automated scripts to check your electronic submission: an improperly named folder or a folder with impropertly named files will not count as a valid submission.
- You may wish to run Codder one last time
blobSimulator.pybefore you submit your
- Drop your entire
ps04folder in your
dropfolder on the
csserver using Cyberduck by 11:59pm on the DUE DATE = Tuesday, October 02, 2018.
- Failure to submit a code file before the deadline will result in zero credit for that code on PS04.
Hardcopy (paper) submission
There is no hardcopy submission. Problem set submission is entirely electronic.