- start learning about computer graphics
- practice using objects and methods
- practice functions and loops

- Use the Zelle Graphics Documentation as a reference!!!!!
- Same as always: header at the top, comments, good variable names, write and test incrementally
- Don't hard-code values! Define variables, like
`width`

and`height`

, then specify positions, sizes, lengths, etc. in relation to the`width`

and`height`

- We have provided some images below. It's okay if your images look a little different, as long as they still satisfy the program requirements described below
- If you are working remotely, see our help page on remote access as well as the Piazza post about working remotely
- When using
`input()`

to ask the user for input, doing that before setting up the graphics window is often easier (less clicking back and forth between windows) - Don't forget to run
`update21`

and put your programs in your`cs21/labs/06`

directory

In this first program you'll create a grid of circles with blended coloring.

Here are a few steps and suggestions to help you get started. Computers need a coordinate system to draw. The Zelle coordinate system is two-dimensional, having an x-axis and y-axis. The x-axis goes from left to right. The y-axis goes from top to bottom. The point (0,0) is at the top, left corner. The bottom right corner has the coordinate (window width, window height). The coordinate (0,0) has a special name, called the *origin*. To draw a circle, you must give a coordinate which specifies the location of the center as well as a radius. We recommend drawing the Zelle coordinate system on paper and working out the coordinates of the shapes you wish to draw before you start programming.

Read the overview in the Zelle Graphics Documentation. This section includes a sample program which shows how to open a window and draw a circle. Copy this code into

`circle.py`

and verify that it works. This program draws a circle at coordinate (50,50) and radius 10. Verify that the size and position of the circle makes sense. Note that clicking on the window closes it.For this question we will always have a square window of size 400. Modify

`circle.py`

so the window width and height are 400. To figure out how, look up the function definition for`GraphWin(...)`

in the Zelle manual.

`$ `**python3 circle.py **

- Try setting the background to white using the function
`setBackground(...)`

. Look up the function in the Zelle manual for an example to help you.

`$ `**python3 circle.py **

- Ask the user for the number of circles to draw along each row and column. Eventually, we will draw a grid of circles but to start, we will draw a single circle at the top left. Our first step is to compute the radius. We will make the radius an
*integer*so our loops are easier to write. To compute the radius, divide the window size by the number of circles to get the diameter. The radius is then half the diameter. Modify your program to compute an x and y coordinate for a circle with your computed radius. The circle should be flush against the top left corner.

`$ `**python3 circle.py **
Please enter a number of circles for the width and height: **5**

- Next, draw a single row of circles across the top. Modify main() to create circles in a loop. What should the y coordinate of these circles be? How should the x coordinates change? Write your ideas on paper before coding.

`$ `**python3 circle.py **
Please enter a number of circles for the width and height: **5**

- To draw a grid of circles, we will need a nested loop. The outer loop will change the coordinates of the columns (e.g. x as before). The inner loop will correspond to rows (e.g. by changing y). Hint: The y coordinate should change in the same way as x!

`$ `**python3 circle.py **
Please enter a number of circles for the width and height: **5**

- Now that you have a grid of circles, try setting a color for your circles using the function
`setFill(...)`

. Colors in Zelle are represented either with strings or with (red, blue, green) tuples of integers ranging from 0 to 255. For example, the color yellow is represented as either`color_rgb(255,255,0)`

or as the word "yellow". The color blue is`color_rgb(0,0,255)`

or the word "blue". See here to get tuples for different colors. In the example below, we fill the circle with the color "cyan" which is (0,255,255)

`$ `**python3 circle.py **
Please enter a number of circles for the width and height: **5**

Last step! Define a function

**getColor(px,py,winSize)**to generate a color for each circle based on its position using a gradient. Your function should take the circle center (px, py) and the window size as arguments and return the color. Then pass this color to the function`setFill(..)`

. Recall that a color is a tuple of (red, green, blue). We can add and scale colors to create new colors! The only constraints are that- the final rgb color values are all between 0 and 255
the final rgb color values are integers

To create a horizontal gradient, we will blend between two colors based on the x-coordinate of the circle's center. When x is close to zero (the left-side of the screen), the circles will have the first color. When x is close to the window's width (the right-side of the screen), it will have the second color. When x is half the window width, the color will be 50% of the first color and 50% of the second color. Let our first color be *C*_{1} = [*R*_{1}, *G*_{1}, *B*_{1}]^{T}, our second color be *C*_{2} = [*R*_{2}, *G*_{2}, *B*_{2}]^{T}, and the percentage distance along the X-axis be *α*. The general formula for this gradient is

$$
\left[\begin{array}{c}
R \\
G \\
B
\end{array}
\right] =
(1 - \alpha) \left[\begin{array}{c}
R_{1} \\
G_{1} \\
B_{1}
\end{array}
\right] +
\alpha \left[\begin{array}{c}
R_{2} \\
G_{2} \\
B_{2}
\end{array}
\right] =
\left[\begin{array}{c}
(1 - \alpha) R_{1} + \alpha R_{2} \\
(1 - \alpha) G_{1} + \alpha G_{2} \\
(1 - \alpha) B_{1} + \alpha B_{2}
\end{array}
\right]
$$

Let's start by breaking down what this formula means:

- multiply each R,G,B value in the first color by (1 −
*α*) - multiply each R,G,B value in the second color by
*α* - add pairwise the components of each color

Now let's look at some examples. Suppose our window size is 400. What is the color of a circle at location (0,0)? *α* will be 0/400 = 0, or 0% across the window. Now suppose our first color *C*_{1} is yellow [255, 255, 0]^{T} and our second color *C*_{2} is blue [0, 0, 255]^{T}. In this case, the gradient color is 100% of the first color and 0% of the second color, which we can see by plugging in our values

$$
\left[\begin{array}{c}
255 \\
255 \\
0
\end{array}
\right] =
(1 - 0) \left[\begin{array}{c}
255 \\
255 \\
0
\end{array}
\right] +
0 \left[\begin{array}{c}
0 \\
0 \\
255
\end{array}
\right]
$$

Now suppose we have a circle at position (400,0). Now *α* is 400/400 = 1, or 100% across the window. When we plug in our values, we see that we get 0% of the first color and 100% of the second color.

$$
\left[\begin{array}{c}
0 \\
0 \\
255
\end{array}
\right] =
(1 - 1) \left[\begin{array}{c}
255 \\
255 \\
0
\end{array}
\right] +
1 \left[\begin{array}{c}
0 \\
0 \\
255
\end{array}
\right]
$$

Verify for yourself that a circle at position (200,0) will be 50% of *C*_{1} and 50% of *C*_{2}. You may use any colors you like. The following screenshot uses the colors yellow and blue.

`$ `**python3 circle.py **
Please enter a number of circles for the width and height: **5**

`$ `**python3 circle.py **
Please enter a number of circles for the width and height: **50**

Write a program called `aquarium.py`

that generates an animated aquarium, using mouse-clicks from the user. Here is an example:

Here are the requirements and some tips for this program:

Create a fixed sandy ground using a

`Rectangle`

(not based on user clicks).Create and

*update*a`Text`

object that tells the user what to do in each step. The`setText(<string>)`

method can be used to change the text at each step. The input string can also be the empty string.Create a

*function*that makes and draws*one*small fish at a given`Point`

. The fish in the video were created using a polygon. The five points of the polygon are computed relative to the given point (px, py).*Δ**x*and*Δ**y*are distances that you can hard-code. The numbers beside each to point is a suggested order that you can give them to the`Polygon(...)`

constructor.

Your fish does not have to look exactly like these fish. Feel free to personalize them.

In

`main()`

, use a*while loop*to let the user click to create multiple fish. Whenever the user clicks, call your fish function and pass the user's click`Point`

as an argument. When the user clicks on the ground, the while loop should end.In

`main()`

, after creating the small fish, ask the user for a point to create a giant fish. (Note: It's possible to create your large fish in main(). However, try to think about how you can modify your fish function to create either small fish or large fish.) Write a loop to move the giant fish across the screen. To animate, call the function`move(..)`

. You can choose to iterate the animation for a fixed number of frames, or you can exit the loop on mouse click using the function`checkMouse()`

.Finally, when the user next clicks, exit and close the window.

There are many ways to extend this animation.

- Use different colors to create a different scene, or make more elaborate composite objects.
- Create a more elaborate background
- Animate multiple objects in the screen
- Allow the giant fish to wrap to the other side of the screen
- Use random numbers to generate colors for either the fish or background objects
- Use a gradient to generate colors
- Play with different types of Zelle primitives
- Use different formulas to animate the big fish (Idea: Use math.sin() to make your fish swim up and down)
- Zelle supports png, ppm, and gif images. Try integrating images into your solution! (Hint: png supports transparency for making fish!)

Here are some sample videos with ideas

`$ `**python3 circle.py **
Please enter a number of circles for the width and height: **5**

In `circle.py`

, modify your `getColor(..)`

function to do a two-way gradient. In this case, we blend in both the X and Y directions and can use up to four colors! You can think of the two-way gradient like so:

- first we blend along the X direction using the first two colors (same as before) to produce a color
*C*_{x1}; - we blend again along the X direction using the second two colors (same as before) to produce a color
*C*_{x2}; - to get our final color, we blend
*C*_{x1}and*C*_{x2}in the Y direction.

$$
\left[\begin{array}{c}
R_{x1} \\
G_{x1} \\
B_{x1}
\end{array}
\right] =
(1 - \alpha_x) \left[\begin{array}{c}
R_{1} \\
G_{1} \\
B_{1}
\end{array}
\right] +
\alpha_x \left[\begin{array}{c}
R_{2} \\
G_{2} \\
B_{2}
\end{array}
\right]
$$

$$
\left[\begin{array}{c}
R_{x2} \\
G_{x2} \\
B_{x2}
\end{array}
\right] =
(1 - \alpha_x) \left[\begin{array}{c}
R_{3} \\
G_{3} \\
B_{3}
\end{array}
\right] +
\alpha_x \left[\begin{array}{c}
R_{4} \\
G_{4} \\
B_{4}
\end{array}
\right]
$$

$$
\left[\begin{array}{c}
R \\
G \\
B
\end{array}
\right] =
(1 - \alpha_y) \left[\begin{array}{c}
R_{x1} \\
G_{x1} \\
B_{x1}
\end{array}
\right] +
\alpha_y \left[\begin{array}{c}
R_{x2} \\
G_{x2} \\
B_{x2}
\end{array}
\right]
$$

For example, to get the screenshot above, we let

*α*_{x}be the percentage along X (e.g. px/winSize),*α*_{y}be the percentage along Y (e.g. py/winSize),*C*_{1}be the top left color (black, e.g. [0, 0, 0] )*C*_{2}be the top right color (yellow, e.g. [255, 255, 0] )*C*_{3}be the bottom left color (blue, e.g. [0, 0, 255] )*C*_{4}be the bottom right color (white, e.g. [255, 255, 255] )

Create a new program, `mandelbrot.py`

, that colors circles based on the Mandelbrot set. For this challenge, you should modify `circle.py`

so that `getColor(px, py, winSize)`

uses the Mandelbrot formula to compute a color for each circle.

To start, modify `getColor(px, py, winSize)`

to return white if we're outside the set and black otherwise. A point (px,py) is inside the set based on an "escape condition". We start by computing offsets (x0, y0) based on the circle center (px,py). We then initialize a pair (x,y) = (0,0) and repeatedly update the values (x,y) in a loop. If $ x^2 + y^2 $ becomes greater than 4, the point escapes (!) and we assign it a white color. Otherwise, we assume it is part of the Mandelbrot set, and we assign it a black color. The full pseudocode for getColor is below

```
x0 = (px/winSize)*2.25 - 1.5
y0 = (py/winSize)*2 - 1
x = 0.0
y = 0.0
iteration = 0
max_iteration = 1000
while x*x + y*y < 2*2 and iteration < max_iteration
xtemp = x * x - y * y + x0
y = 2*x * y + y0
x = xtemp
iteration = iteration + 1
if iteration < max_iteration
return white
else:
return black
```

The following image shows the result of a size 400 window with 200 circles

You can make a more colorful visualization of the Mandelbrot set by defining a palette. A palette is a list of colors, one for every possible iteration that a point (px,py) can escape. To define a palette, create a list in `main()`

and add 1000 random colors to it using a loop. A random color can be generated using random.randrange(255) to generate red, green, and blue color components. Then modify `getColor()`

to take your palette as a fourth parameter. When iteration is less than 1000, use the color from your palette. Otherwise, return black as before.

Below is an example using a size 400 window with 200 circles.

Each lab has a short questionnaire at the end. Please edit the `QUESTIONS-06.txt`

file in your `cs21/labs/06`

directory and answer the questions in that file.

Don't forget to run `handin21`

to turn in your lab files! You may run `handin21`

*as many times as you want*. Each time it will turn in any *new* work. We recommend running `handin21`

after you complete each program *or* after you complete significant work on any one program.