Problem Set 3 - Due Tue, Feb 21 at 23:59*

*The deadline is Tue. because of the Mon. Feb 20 holiday

Reading

  1. Slides and notebooks from Lec 04 Divide/Conquer/Glue with Pictures and Lec 05 Booleans and Conditionals. You do not need (in fact, should not use material from) Lec 6 Sequences and Loops in this problem set.
  2. Problems and solutions from Lab 04 Conditionals, Pictures, DC&G
  3. Think Python, Sections 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.

  1. In Task 1, you will write functions using conditionals to create a rock-paper-scissors game.
  2. In Task 2 (Partner task), you will create quilt patterns using functions. Use this shared Google Doc to find a pair programming partner and record who your pair partner is. Remember, you can talk with other individuals and teams about high-level problem-solving strategies, but you cannot share any code with them.
  3. The CS111 Problem Set Guide gives an overview of psets, including a detailed description of individual and partner tasks.
  4. Follow the style guidelines in the CS 111 Code Style Guide
  5. The PS03 FAQ covers the most common issues students encounter when working on PS03. Consult it before asking in the Google Group.
  6. In Fall 2016, students spent in average 2.3 hours on Task 1 (min = 0.8 hours, max = 6 hours) and 3.7 hours on Task 2 (min = 1 hours, max = 8 hours).

All code for this assignment is available in the ps03 folder in the cs111/download directory within your cs server account. This assignment also uses the Otter Inspector program that you used in PS2 to help you do a final check of Task 1 and your Honor Code form before you submit.


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 rockPaperScissors.py:

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

To test the functions, run the program in the Canopy editor window. No output will be produced, since none of the functions are called. Enter sample calls of your functions in the interactive console to test that they work correctly. Here are some examples:

Sample Output

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

Notes

Task 2: Quilts

This task is a partner problem in which you are required to work with a partner as part of a two-person team.

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 quilt.

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 design shown above.

This quilt is just one 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.

The picture.py module, which contains picture functions you have learned about in Lecture 04 and Lab 04, is provided in the ps03 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 you create called ps03Quilt.py.

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 the picture.py file:

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:

          
patch('red') triangles('red', 'blue')

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:

block('darkseagreen','lightcyan2','royalblue',
   'navy','lightskyblue','darkslateblue')

The whole quilt picture can be decomposed into four copies of the picture returned by block that have different rotations. Once we figure out how to define the block function, we can an combine four rotated copies of the block picture to form the desired picture for quilt. This is an excellent illustration of the divide, conquer, and glue problem solving strategy we will use throughout this course:

  1. Divide the problem into subproblems. Here, the whole quilt problem can be solved if we can solve the problem of generating the picture in its upper right quadrant.

  2. Conquer the subproblems by solving them. In this case, the solution to the subproblem is a function named block that generates the picture in the upper right quadrant of the quilt picture.

  3. 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 block to construct the picture returned by quilt.

But how do we solve the problem of defining the block function? By applying the divide, conquer, and glue strategy again! In this case, you should decompose the picture returned by block itself into four quadrants. You can then define functions quadrant1, quadrant2, etc. that return pictures for these quadrants. Of course, all of these functions will take appropriate color parameters.

Continue this way, decomposing each problem into smaller subproblems, until you reach problems that can be solved using our primitives (e.g., patch and triangles). For an example of this sort of decomposition, see the quilt example from lecture 04.

Starting the Assignment

Begin by creating a file named ps03Quilt.py. 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:

  1. 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 until you have correctly defined the full quilt picture.

  2. In the top-down strategy, you start by defining the quilt function in terms of the block function. But the block function is itself complex, so you can't really test it yet. So for testing purposes, you instead provide a so-called stub picture for the block function. For example, as a very crude approximation, you might define an initial version of the block function that returns the result of calling triangles on two of its parameters. You can then test quilt with this approximation to block. Then you continue the top-down descent by defining initially-crude-approximations for functions that return the quadrants of the block picture. You continue this top down process until you reach pictures that are correctly implemented by patch and triangles, at which point you now have the correct quilt function rather than just an approximation.

Helper Functions

As mentioned in Task 1, 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 quilt naturally exposes the need for numerous auxiliary functions. As part of working on this task, you must define and use the following helper functions:

def patch2x2(c):
    """Returns a picture consisting of four rectangular patches of color c
       with black lines between the patches. (Remember that patch(c) returns
       a picture with a black border.)"""

def triangles2x2(c1, c2):
    """Returns a 2x2 picture similar to triangles(c1, c2) except that each
       large triangle is composed out of three smaller fragments (two
       triangles and one square patch)."""

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 corner(p1, p2):
    """Returns a picture which divides the picture space into four
       quadrants and places p1 in the lower left quadrant and p2 in the
       remaining three quadrants."""

def stripe(p1, p2, p3):
    """Returns a picture which divides the picture space into four
       quadrants and places p1 in the lower left quadrant, p2 in upper left
       and lower right quadrants, and p3 in the upper right quadrant."""

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 are example invocations of patch2x2, triangles2x2, and bandana:

                     
patch2x2('red') triangles2x2('red', 'blue') bandana('red', 'blue')


Note that the corner, stripe, lowerLeft, lowerLeftNest, and lowerLeftNestSelf4 functions take pictures as arguments, not colors. To illustrate these helper functions, suppose that pictures picP1, picP2, and picP3 are defined as:

                     
picP1 picP2 picP3


Then here are examples of calling the corner, stripe, lowerLeft, lowerLeftNest, and lowerLeftNestSelf4 functions with these pictures:

                     
corner(picP1, picP2) stripe(picP1, picP2, picp3)
                     
lowerLeft(picP1) lowerLeftNest(picP1, picP2) lowerLeftNestSelf4(picP2)

Notes:

Testing

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 ps03Quilt.py:

# ------------------------- Testing -----------------------
def blueQuilt():
    """Returns the blue-themed quilt described at the beginning 
       of the quilt problem"""

def autumnQuilt():
    """Returns the autumn quilt described at the end of the quilt problem"""

# All code that displays pictures or prints output should be nested 
# within this special "main" header at the end of ps03Quilt.py
if __name__ == "__main__":

    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(patch2x2('red'))
    #displayPic(triangles2x2('red', 'blue'))
    #displayPic(bandana('red', 'blue'))
    #displayPic(corner(triangles('red', 'blue'), patch('red')))
    #displayPic(stripe(patch('red'), patch('blue'), patch('green')))
    #displayPic(lowerLeft(triangles('red', 'blue')))
    #displayPic(lowerLeftNest(patch('red'), triangles('red', 'blue')))
    #displayPic(lowerLeftNestSelf4(triangles('darkslateblue', 'navy')))
    #displayPic(blueQuilt())
    #displayPic(autumnQuilt())

    # Extra invocation to displayPic to fix picture glitch 
    # (a simple picture is sometimes needed to have previous pictures display)
    displayPic(patch('red'))

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 invocations of displayPic at the very end of ps03Quilt.py indented within the special header if __name__ == "__main__":

Notes:

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).

Your final Task.

Oh no! A new intern just designed this new quilt shown below, using the same pattern as above, but with different colors. She forgot how she actually created this one. She asks you to figure out which color parameters were used in what order to create the pattern below.

To solve this problem, invoke your quilt function to produce the quilt shown below. These are the names of the colors she used: firebrick, sienna, peachpuff, darkred, gold, and orange3.

The autumn version of the quilt

Task 3: Honor Code File

As in PS02, your honor code submission for this pset will involve defining entering values for the variables in the honorcode.py file.

Remember to run otterInspect.py one final time before you submit to check that all your rock/paper/scissors functions work, and that your honor code form is complete.


How to turn in this Problem Set

Soft-copy submission

Hard-copy submission

There is no hard copy submission. Problem set submission is entirely electronic.