Functional Problem Solving (CSC 151 2014F) : Labs
Primary: [Front Door] [Schedule] - [Academic Honesty] [Disabilities] [Email] - [FAQ] [Teaching & Learning] [Grading] [Rubric] - [Calendar]
Current: [Assignment] [EBoard] [Lab] [Outline] [Reading]
Sections: [Assignments] [EBoards] [Examples] [Handouts] [Labs] [Outlines] [Readings]
Reference: [Setup] [VM] [Errors] - [Functions A-Z] [Functions By Topic] - [Racket] [Scheme Report (R5RS)] [R6RS] [TSPL4]
Related Courses: [Davis (2013F)] [Rebelsky (2014S)] [Weinman (2014F)]
Misc: [Submit Questions] - [SamR] [Glimmer Labs] [CS@Grinnell] [Grinnell] - [Issue Tracker (Course)]
Summary: In this laboratory, you will explore the three new approaches to making images that were covered in the corresponding reading.
Make a copy of project-ideas-lab.rkt
, which contains much of the code from the reading.
a. What effect do you expect the following instructions to have?
>
(define t1 (cons "grey" (cons "red" "black")))
>
(define image1 (ctree->image t1 200 200))
>
(image-show image1)
b. Check your answer experimentally.
c. What effect do you expect the following instructions to have?
>
(define t2 (cons (cons "red" t1) t1))
>
(define image2 (ctree->image t2 200 200))
>
(image-show image2)
d. Check your answer experimentally.
e. What effect do you expect the followings instruction to have?
>
(define image3 (image-new 200 200))
>
(image-render-color-tree! image3 t1 0 0 100 100)
>
(image-render-color-tree! image3 t1 100 100 50 25)
>
(image-render-color-tree! image3 t1 100 150 25 25)
>
(image-show image3)
f. Check your answer experimentally.
g. Create one or two color trees of your own and render them.
a. The base case for image-render-color-tree!
is
to render the area as a rectangle. What do you expect to happen if
we change the call to image-select-rectangle!
to
image-select-ellipse!
?
b. Check your answer experimentally. Then restore the call to
image-select-rectangle!
.
c. As written, the width used in recursive calls during horizontal
splits is (/ width 2)
. What do you expect to have happen
if we change that to (/ width 2.5)
? (Assume we change
it for both recursive calls.)
d. Check your answer experimentally. Then restore the original formula.
e. As written, the top edge used in recursive calls for vertical splits
is (+ top (/ height 2))
. What do you expect to have
happened if we use (+ top (/ height 1.5))
?
f. Check your answer experimentally. Then restore the original formula.
Look at the code for series-1
.
a. What do you expect (series-1 5 100 100)
to produce?
b. Check your answer experimentally.
c. What do you expect (series-1 42 100 100)
to produce?
d. Check your answer experimentally.
e. Do you expect (series-1 43 100 100)
to be similar to or
very different from the image you got using 42? How do you expect it
to differ?
f. Check your answer experimentally.
g. How do you expect (series-1 43 500 500)
to differ?
h. Check your answer experimentally.
i. How do you expect (series-1 43 800 100)
to relate to
the previous two images?
j. Check your answer experimentally.
a. Use fractal-rectangle!
to draw a 200x200 blue
rectangle on canvas
, using a recursion level of 0.
b. Use fractal-rectangle!
to draw a 200x200
red rectangle using a recursion level of 1. (Don't be surprised if it
looks pretty boring.)
c. Use fractal-rectangle!
to draw a 200x200
green rectangle using a recursion level of 2. (Again, don't be surprised
if it's boring.)
d. After those three exercises, you are probably ready to do something
a bit more interesting. Here's a modified version of
fractal-rectangle!
in which we've changed the
recursive calls for the top-middle, left-middle, right-middle, and
bottom-middle subrectangles so that they use the complement of the color.
(define fractal-rectangle-c! (lambda (image color left top right bottom level) (cond ; Base case: We're at a level in which we just draw the rectangle. ((= level 0) (context-set-fgcolor! color) (image-select-rectangle! image REPLACE left top (- right left) (- bottom top)) (image-fill-selection! image) (image-select-nothing! image) (context-update-displays!)) ; Recursive case: Break the rectangle into a few parts and recur ; on each. (else (let ([midcol1 (round (+ left (/ (- right left) 3)))] [midcol2 (round (- right (/ (- right left) 3)))] [midrow1 (round (+ top (/ (- bottom top) 3)))] [midrow2 (round (- bottom (/ (- bottom top) 3)))]) ; First row of squares (fractal-rectangle-c! image color left top midcol1 midrow1 (- level 1)) (fractal-rectangle-c! image (rgb-complement color) midcol1 top midcol2 midrow1 (- level 1)) (fractal-rectangle-c! image color midcol2 top right midrow1 (- level 1)) ; Second row of squares (fractal-rectangle-c! image (rgb-complement color) left midrow1 midcol1 midrow2 (- level 1)) (fractal-rectangle-c! image color midcol1 midrow1 midcol2 midrow2 (- level 1)) (fractal-rectangle-c! image (rgb-complement color) midcol2 midrow1 right midrow2 (- level 1)) ; Third row of squares (fractal-rectangle-c! image color left midrow2 midcol1 bottom (- level 1)) (fractal-rectangle-c! image (rgb-complement color) midcol1 midrow2 midcol2 bottom (- level 1)) (fractal-rectangle-c! image color midcol2 midrow2 right bottom (- level 1)) )))))
Put this new version at the end of your definitions pane.
Use this procedure to draw a 200x200 rectangle fractal with black as the initial color and a recursion level of 1. Once you've done that, try it with a recursion level of 2.
e. Predict what will happen if you draw a 200x200 rectangle with yellow as the initial color and a recursion level of 3. Then check your prediction experimentally.
f. Here is a procedure that averages two RGB colors.
;;; Procedure: ;;; rgb-average ;;; Parameters: ;;; rgb1, an RGB color ;;; rgb2, an RGB color ;;; Purpose: ;;; Compute the "average" of two RGB colors. ;;; Produces: ;;; rgb-avg, an RGB color ;;; Preconditions: ;;; [No additional] ;;; Postconditions: ;;; (rgb-red rgb-avg) is the average of (rgb-red rgb1) and (rgb-red rgb2) ;;; (rgb-green rgb-avg) is the average of (rgb-green rgb1) and (rgb-green rgb2) ;;; (rgb-blue rgb-avg) is the average of (rgb-blue rgb1) and (rgb-blue rgb2) (define rgb-average (lambda (rgb1 rgb2) (rgb-new (quotient (+ (rgb-red rgb1) (rgb-red rgb2)) 2) (quotient (+ (rgb-green rgb1) (rgb-green rgb2)) 2) (quotient (+ (rgb-blue rgb1) (rgb-blue rgb2)) 2))))
And here is a rewritten fractal-rectangle!
that
averages the colors in the top-middle, left-middle, right-middle,
and bottom-middle subrectangles with black and the colors in the other
five subrectangles with white.
(define fractal-rectangle-a! (let ([RGB-WHITE (irgb 255 255 255)] [RGB-BLACK (irgb 0 0 0)]) (lambda (image color left top right bottom level) (cond ; Base case: We're at a level in which we just draw the rectangle-a. [(= level 0) (context-set-fgcolor! color) (image-select-rectangle! image REPLACE left top (- right left) (- bottom top)) (image-fill-selection! image) (image-select-nothing! image) (context-update-displays!)] ; Recursive case: Break the rectangle-a into a few parts and recur ; on each. [else (let ([midcol1 (round (+ left (/ (- right left) 3)))] [midcol2 (round (- right (/ (- right left) 3)))] [midrow1 (round (+ top (/ (- bottom top) 3)))] [midrow2 (round (- bottom (/ (- bottom top) 3)))]) ; First row of squares (fractal-rectangle-a! image (rgb-average color RGB-WHITE) left top midcol1 midrow1 (- level 1)) (fractal-rectangle-a! image (rgb-average color RGB-BLACK) midcol1 top midcol2 midrow1 (- level 1)) (fractal-rectangle-a! image (rgb-average color RGB-WHITE) midcol2 top right midrow1 (- level 1)) ; Second row of squares (fractal-rectangle-a! image (rgb-average color RGB-BLACK) left midrow1 midcol1 midrow2 (- level 1)) (fractal-rectangle-a! image (rgb-average color RGB-WHITE) midcol1 midrow1 midcol2 midrow2 (- level 1)) (fractal-rectangle-a! image (rgb-average color RGB-BLACK) midcol2 midrow1 right midrow2 (- level 1)) ; Third row of squares (fractal-rectangle-a! image (rgb-average color RGB-WHITE) left midrow2 midcol1 bottom (- level 1)) (fractal-rectangle-a! image (rgb-average color RGB-BLACK) midcol1 midrow2 midcol2 bottom (- level 1)) (fractal-rectangle-a! image (rgb-average color RGB-WHITE) midcol2 midrow2 right bottom (- level 1)) )]))))
g. What do you expect to have happen if we draw a 200x200 level-2 fractal rectangle whose initial color is blue? Check your answer experimentally.
h. What do you expect to have happen if we draw a 200x200 level-3 fractal rectangle whose initial color is green? Check your answer experimentally.
i. Let's change the computation of the intermediate boundaries so that
midcol1
is 1/4 of the way across,
midcol2
is 1/2 of the way across,
midrow1
is 1/4 of the way down, and
midrow2
is 1/2 of the way down.
Add the following to the end of your definitions pane.
(define fractal-rectangle-u! (let ([RGB-WHITE (irgb 255 255 255)] [RGB-BLACK (irgb 0 0 0)]) (lambda (image color left top right bottom level) (cond ; Base case: We're at a level in which we just draw the rectangle-u. ((= level 0) (context-set-fgcolor! color) (image-select-rectangle! image REPLACE left top (- right left) (- bottom top)) (image-fill-selection! image) (image-select-nothing! image) (context-update-displays!)) ; Recursive case: Break the rectangle-u into a few parts and recur ; on each. (else (let* ([midcol1 (round (+ left (/ (- right left) 4)))] [midcol2 (round (+ midcol1 (/ (- right left) 4)))] [midrow1 (round (+ top (/ (- bottom top) 4)))] [midrow2 (round (+ midrow1 (/ (- bottom top) 4)))]) ; First row of squares (fractal-rectangle-u! image (rgb-average color RGB-WHITE) left top midcol1 midrow1 (- level 1)) (fractal-rectangle-u! image (rgb-average color RGB-BLACK) midcol1 top midcol2 midrow1 (- level 1)) (fractal-rectangle-u! image (rgb-average color RGB-WHITE) midcol2 top right midrow1 (- level 1)) ; Second row of squares (fractal-rectangle-u! image (rgb-average color RGB-BLACK) left midrow1 midcol1 midrow2 (- level 1)) (fractal-rectangle-u! image (rgb-average color RGB-WHITE) midcol1 midrow1 midcol2 midrow2 (- level 1)) (fractal-rectangle-u! image (rgb-average color RGB-BLACK) midcol2 midrow1 right midrow2 (- level 1)) ; Third row of squares (fractal-rectangle-u! image (rgb-average color RGB-WHITE) left midrow2 midcol1 bottom (- level 1)) (fractal-rectangle-u! image (rgb-average color RGB-BLACK) midcol1 midrow2 midcol2 bottom (- level 1)) (fractal-rectangle-u! image (rgb-average color RGB-WHITE) midcol2 midrow2 right bottom (- level 1)) ))))))
j. What do you expect to have happen if we draw a 200x200 level-2 fractal rectangle whose initial color is red? Check your answer experimentally. What about a level-3 fractal?
k. Change the computation of the intermediate boundaries so that
midcol1
is 1/4 of the way across,
midcol2
is 3/4 of the way across,
midrow1
is 1/4 of the way down, and
midrow2
is 3/4 of the way down.
l. Draw one final level-3 fractal.
Sometimes it is difficult to envision how you make 1000 variations of an image. But, as is often the case, the problem is a bit easier if you break it down into parts. Suppose we want all of our images to be based on the “spin a polygon” technique. In building different images, we can vary
(We probably can't vary the side length, since that should depend on the size of the image.)
Now, how do we turn one number (the n
we're
using to describe the image) into four different numbers (or six, if
we change the red, green, and blue components separately)? We can
use modulo
(define series-2 (lambda (n width height) (let* ((canvas (image-new width height)) (width (exact->inexact width)) (height (exact->inexact height)) (t (turtle-new canvas)) (side-length (/ (+ width height) 12)) (sides (+ 3 (modulo n 4))) (angle (* 5 (modulo n 5))) (copies (+ 5 (* 2 (modulo n 7)))) (red (* 256/11 (modulo n 11))) (green (* 256/13 (modulo n 13))) (blue (- 256 red))) (turtle-set-color! t (rgb-new red green blue)) (turtle-teleport! t (/ width 3) (/ height 3)) (turtle-spin-polygon! t side-length sides angle copies) (image-show canvas) canvas)))
a. Try this procedure with a variety of values for
n
, width
,
and height
b. In your own words, explain how the procedure works to vary the drawing.
c. Can we be sure that this procedure creates 1000 different drawings
for the values of n
from 0 to 999? Why or why
not?