# Problem Set 3 - Due Tue, Sept 24 at 23:59

1. Slides and notebooks from Lec Functions. You do not need (in fact, should not use) material from Lec 06: Booleans, Logical Expressions, and Predicates or Lec 07: Conditionals.
2. Problems and solutions from Lab 03 Functions
3. Think Python, Chapter 3: Functions

This problem set will give you practice with abstraction, problem-solving by recognizing patterns, and functions.

• In tasks 1 and 2 you will create your own functions and practice breaking down a problem into simpler parts.

• Task 0 is an individual problem in which you will solve some puzzles involving the problem set 2 solution code, to help prepare for the problem set 2 quiz.

• In Task 1 (individual task), you will use functions to display a diamond pattern made out of text lines generated from a small set of strings.
• In Task 2 (partner-optional task), you will create butterfly patterns using functions. In this problem, having a partner is optional, but strongly recommended. 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.

Other notes:

• Based on data from Spring 2019, we expect that this assignment will take most students 4–6 hours (2–3 hours per task), plus about an hour of reading time. When you've been working on the pset for about 4 hours, you should evaluate whether you are making efficient progress, and make use of some of the class resources available to you, like help-room hours or office hours. If you've been working on it for 6 or 7 hours and still have a ways to go, you should definitely get some help with it.

• All code for this assignment is available in the `ps03` folder in the `cs111/download` directory within your `cs` server account.

This is an individual problem which you must complete on your own, although you can ask for help from the CS111 staff.

As in problem set 2 Task 0 we have two puzzles for you to solve to review the problem set 2 solutions. This time both puzzles use code from the `bunnyMoneyMosaic.py` solution. Go to:

CS 111 Puzzles

and select each of the options under `Problem Set 2`. These puzzles will only be made available after ps02 is due.

As before, please download and submit your solutions. The files should download as `ps02-bunny_bill-solution.json` and `ps02-bunny_mosaic-solution.json`. Also as before, please email `pmawhort@wellesley.edu` if you run into trouble.

This is an individual problem which you must complete on your own, though you may ask for help from the CS111 staff.

In the provided `diamonds.py`, define a zero-parameter function named `diamondPattern`. When `diamondPattern` is invoked on zero arguments in the interactive Python pane, it should display the pattern of asterisks shown below:

```In [17]: diamondPattern()
*         *         *         *
* *       * *       * *       * *
* * *     * * *     * * *     * * *
* *       * *       * *       * *
*         *         *         *
*         *         *         *
* *       * *       * *       * *
* * *     * * *     * * *     * * *
* *       * *       * *       * *
*         *         *         *
*         *         *         *
* *       * *       * *       * *
* * *     * * *     * * *     * * *
* *       * *       * *       * *
*         *         *         *
*         *         *         *
* *       * *       * *       * *
* * *     * * *     * * *     * * *
* *       * *       * *       * *
*         *         *         *
*         *         *         *
* *       * *       * *       * *
* * *     * * *     * * *     * * *
* *       * *       * *       * *
*         *         *         *
*         *         *         *
* *       * *       * *       * *
* * *     * * *     * * *     * * *
* *       * *       * *       * *
*         *         *         *
*         *         *         *
* *       * *       * *       * *
* * *     * * *     * * *     * * *
* *       * *       * *       * *
*         *         *         *
*         *         *         *
* *       * *       * *       * *
* * *     * * *     * * *     * * *
* *       * *       * *       * *
*         *         *         *
```

In Canopy, open `diamonds.py`. Notice that it contains the following variable definitions.

``````# pre-defined strings
zeroStar  = '     '
oneStar   = '  *  '
twoStar   = ' * * '
threeStar = '* * *'
empty     = ''``````

### Notes

• By using only these strings and no others, `diamondPattern` must print out the pattern shown above. There are possible solutions where one of these strings may not be necessary.

• This task would be easy (but tedious) if you could invoke `print` 40 times, one for each of the 40 lines in the pattern. But we require that `print` may appear at most 5 times in your program. This is possible if you define helper functions to abstract over common patterns. Your goal is to make your program as simple and elegant as possible.

• In this problem, you are not allowed to use features of Python that we have not studied yet, even if you know them. In particular, you are not allowed to use conditionals (i.e., `if` statements) or loops (i.e., `for` loops or `while` loops).

• You may concatenate these strings to form larger strings, but you are not allowed to create any new strings delimited by quotation marks.

• You may not use the newline character `\n`.

• The goal of this problem is two-fold: to recognize patterns, and to write functions that can generate these patterns and combine them together to produce the entire drawing. We strongly recommend that you spend some time thinking about how to break the drawing into different patterns that can be captured by simple functions. If you are having difficulty recognizing patterns, we have a diagram to help you with this process. Access the diagram only after pondering on the pattern on your own.

• This problem has many possible solutions. There is a particularly elegant solution that uses one single `print` statement. While we don't require you to do this, you might want to challenge yourselves.

• There is a trivial solution which involves simply defining a function that does the same thing as print, and using that function everywhere, like this:

``````def myprint(x):
print(x)``````

This is not allowed, and points will be taken off if you do this. Your uses of `print` must combine function parameters with other values in some way, rather than directly using exactly the same parameters as your function takes.

• In the description so far we have been referring to the function by its name only, but when you invoke it in the interactive console, you'll need to include the parentheses.

At the very end, once you're satisfied with your `diamondPattern` function, you should check your program with Codder. Codder will not only verify that the diamond pattern is correct, but it will also check that you have satisfied various restrictions specified above for your code.

In this problem, having a partner is optional, but is strongly recommended. If you want to have a partner, use this shared Google Doc.

In this task, your ultimate goal is to create a canvas populated with butterflies that looks like this:

### Subtask a: `makeWing`

In this subtask, you must define a function named `makeWing` that takes two parameters --- first a wing color and then a spot color --- and returns a `Layer` containing two circles and an ellipse like the one shown in the following call:

`makeWing('pink', 'yellow')`

The wing is always an ellipse (in this case, pink) and the spot is always a circle (in this case, yellow). The dimensions and positioning of the parts of the returned wing layer are always the same, and are specified in the following picture:

`makeWing('pink', 'yellow')`

Note that the layer includes a small cyan dot at the left edge of the ellipse that explicitly marks the (0,0) reference point of the returned layer. This cyan dot is part of the returned layer. It is always cyan, and always has radius 3.

You should add your `makeWing` function to the part of `butterflies.py` where it says:

``````#******************************************************************************
# Put your makeWing function definition here
#******************************************************************************     ``````

Notes:

• The reference point of the returned layer must be (0,0). You must not use `adjustReference` to change the reference point of this layer.

• The testing function `testWing` has been defined for you for testing your `makeWing` function. It creates two wings (one of them rotated by 90 degress), and displays on a canvas with a grid. The call `testWing()` should create and display the following canvas:

There is a commented out call to `testWing()` near the end of `butterflies.py` within code that looks like this:

``````if __name__ == "__main__":
'''All your testing code should go below.
Uncomment and comment particular lines as appropriate.'''
# testWing()   ``````

You should uncomment the call to `testWing()` to test your `makeWing` function for this subtask, leaving it indented within the conditional `if __name__ == "__main__":`. Indeed, you should put all of your testing code indented within this `if` block. Why? Because although this testing code will be executed when you press Canopy's green run button, it will not be executed when Codder runs your file.

• Codder will test the functions in each of the parts of this task. But you should make sure that your function passes the test functions in Canopy before submitting your program to Codder.

### Subtask b: `makeWingPair`

In this subtask, you must define a function named `makeWingPair` that takes two parameters --- first a wing color and then a spot color --- and returns a `Layer` with two wings and a circle like the one show in the following call:

`makeWingPair('pink', 'yellow')`

A wing pair is always a pair of wings with the same colors containing a full-sized wing rotated counterclockwise by 60 degrees and a 75%-sized wing rotated clockwise by 30 degrees. As indicated in the following picture, the cyan dots of the two wings should coincide at the point (25,0) in the returned layer.

`makeWingPair('pink', 'yellow')`

Note that the layer returned by `makeWingPair` includes a small yellow dot that explicitly marks the (0,0) point of the returned layer. This yellow dot is part of the returned layer. It is always yellow, and always has radius 3.

You should add your `makeWingPair` function to the appropriate part of `butterflies.py`, as indicated by a comment.

Notes:

• The reference point of the returned layer must be (0,0). You must not use `adjustReference` to change the reference point of this layer.

• The wings in `makeWingPair` must be created either by calling `makeWing` from subtask a, or by cloning the layer returned by another call to `makeWing`.

What this means is that you should not copy/paste code from the body of your `makeWing` function definition in subtask a into your definition of `makeWingPair`. Instead, you should simply call your `makeWing` function from subtask a in subtask b. To make two wings, you can either (1) call `makeWing` twice or (2) call `makeWing` once, and clone the resulting wing to get a second one. Furthermore, you should not make any changes to the definition of the `makeWing` function from subtask a when defining `makeWingPair`.

• The testing function `testWingPair` has been defined for you for testing your `makeWingPair` function. It creates two wing pairs (one of them rotated by 90 degress), and displays them on a canvas with a grid. The call `testWingPair()` should create and display the following canvas:

### Subtask c: `makeButterfly`

In this subtask, you must define a function named `makeButterfly` that takes six parameters and returns a `Layer` like the one shown in the following call:

`makeButterfly('purple', 'orange', 400, 500, 1.0, 0.0)`

The six parameters, in order, are:

1. The color of the butterfly body and spot on the wing (these are always the same color)
2. The color of the wing
3. The x coordinate of the butterfly layer's reference point, which coincides with the yellow reference dot in the butterfly's body.
4. The y coordinate of the butterfly layer's reference point.
5. The factor by which a full-sized butterfly is scaled about its yellow dot reference point
6. The angle by with the butterfly is rotated about its yellow dot reference point

A full-sized butterfly consists of two full-sized wing pairs whose yellow dot reference points coincide at within the rectangular body (see size details below). This yellow dot is also the (x,y) reference point of the returned layer.

`makeButterfly('purple', 'orange')`

You should add your `makeButterfly` function to the appropriate part of `butterflies.py`, as indicated by a comment.

Notes:

• The wing pairs in `makeButterfly` must be created either by calling `makeWingPair` from subtask b, or by cloning the layer returned by another call to `makeWingPair`.

What this means is that you should not copy/paste code from the body of your `makeWingPair` function definition in subtask b into your definition of `makeButterfly`. Instead, you should simply call your `makeWingPair` function from subtask a in subtask b. To make two wings pairs, you can either (1) call `makeWingPair` twice or (2) call `makeWingPair` once, and clone the resulting wing pair to get a second one. Furthermore, you should not make any changes to the definitions of the `makeWing` function from subtask a or the `makeWingPair` function from substask b when defining `makeButterfly`.

• The testing function `testButterfly` has been defined for you for testing your `makeButterfly` function. It creates two butterflies (one of them rotated by -30 degress), and displays them on a canvas with a grid. The call `testButterfly()` should create and display the following canvas:

• As illustrated by the reference points in the above picture, the reference point of a butterfly layer is located at the position of the yellow dot and is not in the center of the rectangle. There are many ways to achieve this result, but pay attention to the distinction between the reference point of the rectangle and the reference point of the layer that contains it. It is not necessary to use the `adjustReference` method seen in the transformation section of Lab 02 to achieve this result.

### Subtask d: `butterflySky`

Your final subtask is to define a zero-parameter function `butterflySky` that creates the canvas with 5 butterflies shown at the beginning of this task. Here is the same picture with a grid and reference points turned on:

You should be able to tell most canvas and butterfly parameters from the above picture. Here are a few details that may not be apparent:

• All the butterfly coordinates are multiples of 25.
• The background color of the canvas is `lightblue`.
• The only butterfly colors used are blue, green, magenta, orange, pink, purple, red, and yellow.
• The green-yellow butterfly is scaled by 75%
• The pink-red butterfly is scaled by two-thirds (you should express this as a fraction and not as 0.666..)
• You should be able to determine the rotations of the yellow-green and blue-magenta butterflies from their right wing pairs, which are aligned to the vertical and horizontal axes respectively.
• You should be able to determine the scaling of the blue-magenta and magenta-green butterflies from the following information: the size of the big wings of the blue-magenta butterfly is a multiple of 50 and the size of the body of the magenta-green butterfly is also a multiple of 50.

Notes:

• Your `butterflySky` function should flesh out this exact skeleton:

``````def butterflySky():
sky = Canvas(... add parameters here ...)
# drawGrid(sky, 50) # Uncomment this line to draw grid,
# but comment out again before submission
# drawReferencePoints(sky) # Uncomment this line to draw reference points
# but comment out again before submission
return sky # *must* return the sky canvas for Codder to work properly``````

## Task 3: Honor Code File

Your honor code submission for this pset will involve entering values for the variables in the `honorcode.py` file.

If you wrote any function invocations or `print` statements in your Python files to test your code, please remove them, comment them out before you submit, or wrap them in the `if __name__=='__main__'` block at the end of the `.py` file. Points will be deducted for isolated function invocations or superfluous `print` statements.

It's a good idea to run Codder one last time on `diamonds.py` and `butterflies.py` before you submit your `ps03` folder.

## How to turn in this Problem Set

• For Task 0, save your downloaded `ps02-bunny_bill-solution.json` and `ps02-bunny_mosaic-solution.json` files in your `ps03` folder.
• Save your final `diamonds.py` file in the `ps03` folder.
• Each team member should save their `butterflies.py` file in their `ps03` folder. This file should contain a comment with names of both partners at the top. Both team members must submit exactly the same file.
• Save your filled-out `honorcode.py` file in the `ps03` folder as well.
• Note: It is critical that the name of the folder you submit is `ps03`, and your submitted files are named `ps02-bunny_bill-solution.json`, `ps02-bunny_mosaic-solution.json`, `diamonds.py`, `butterflies.py`, and `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 improperly named files will not count as a valid submission.

• Drop your entire `ps03` folder in your `drop` folder on the `cs` server using Cyberduck by 11:59pm on the DUE DATE = Tuesday, September 24, 2019.
• Failure to submit a code file before the deadline will result in zero credit for that code on PS03.