Fundamentals of Computer Science I: Media Computing (CS151.01 2008S)

Laboratory: Iterating Over Lists


Summary: In this laboratory, you will explore techniques for iterating over lists using the map and foreach! procedures.

Reference:

(foreach! func lst)
Traditional higher-order list procedure. Evaluate func on each element of the given list. Called primarily for side effects.
(map func lst)
Standard higher-order list procedure. Create a new list, each of whose elements is computed by applying func to the corresponding element of lst.

Preparation

a. Create a new 200x200 image and call it canvas.

b. Load an image and call it portrait.

c. If your library does not include definitions for all the spot functions, add the definitions of spot-new, spot-col, spot-row, spot-color, image-render-spot!, image-scaled-render-spot!, spot-htrans, and spot-vtrans to your definitions pane. If you are missing any of these procedures, you can find them at the end of this lab.

d. Load your library.

e. Create a list of six to ten spots and call it figure. If you're not feeling particularly creative, you can use the following.

(define figure
  (list (spot-new 2 0 color-blue)
        (spot-new 0 1 color-blue)
        (spot-new 1 1 color-blue)
        (spot-new 2 1 color-blue)
        (spot-new 3 1 color-blue)
        (spot-new 4 1 color-blue)
        (spot-new 2 2 color-blue)
        (spot-new 1 3 color-blue)
        (spot-new 3 3 color-blue)
        (spot-new 1 4 color-blue)
        (spot-new 3 4 color-blue)))

f. Add the following definitions to your definitions pane.

;;; Procedure:
;;;   image-render-spots!
;;; Parameters:
;;;   image, an image
;;;   spots, a list of spots
;;; Purpose:
;;    Draw all of the spots on the image.
;;; Produces:
;;;   [Nothing; Called for the side effect]
(define image-render-spots!
  (lambda (image spots)
    (foreach! (lambda (spot) (image-render-spot! image spot))  spots)))

;;; Procedure:
;;;   image-render-big-spots!
;;; Parameters:
;;;   image, an image id
;;;   spots, a list of spots
;;; Purpose:
;;;   Render a list of spots "bigger".
;;; Produces:
;;;   Nothing; called for the side effect.
;;; Preconditions:
;;;   Each scaled spot can be safely rendered.
(define image-render-big-spots!
  (lambda (image spots)
    (foreach! (lambda (spot) (image-scaled-render-spot! image spot 20)) spots)))

;;; Procedure:
;;;   image-scaled-render-spots!
;;; Parameters:
;;;   image, an image
;;;   spots, a list of spots.
;;;   factor, a number
;;; Purpose:
;;    Draw all of the spots in the list on the image, scaled by factor.
;;; Produces:
;;;   [Nothing; Called for the side effect]
;;; Preconditions:
;;;   factor >= 1
;;;   The position of the scaled spot is within the bounds of the image.
;;; Postconditions:
;;;   The image now contains a rendering of each spot.
(define image-scaled-render-spots!
  (lambda (image spots scale)
    (foreach! (lambda (spot) (image-scaled-render-spot! image spot scale))
              spots)))

Exercises

Exercise 1: Drawing the Figure

a. Using image-render-spots!, render figure on canvas.

b. Using image-render-big-spots!, render figure on canvas.

Exercise 2: Drawing Copies

Recall that we can horizontally translate each spot in a list of spots using (map (lambda (spot) (spot-htrans spot offset)) spots) and that you can vertically translate each spot using (map (lambda (spot) (spot-vtrans spot offset)) spots).

a. Confirm that (map (lambda (spot) (spot-htrans spot 7)) figure) translates each spot seven spaces to the right. That is, execute the instruction and read the results.

b. Confirm that (map (lambda (spot) (spot-vtrans spot 11)) figure) translates each spot eleven spaces down. Once again, execute the instruction and read the results.

c. Render each of the translated figures using image-render-spots!.

Exercise 3: Safely Drawing Copies

a. What do you expect (map (lambda (s) (spot-htrans s -2)) figure) to do?

b. Check your answer experimentally.

c. What do you expect the following code to do?

>  (image-render-spots! canvas (map (lambda (s) (spot-htrans s -2)) figure))

d. Check your answer experimentally.

e. As you should have discovered, trying to draw the left-translated figure will result in an error, since some of the pixels are outside the boundary of the image. Fix this problem by rewriting image-render-spot! so that if the spot is to be drawn outside of the bounds of the image, nothing happens. (That is, a spot is not drawn and an error message is not produced.)

f. Verify that your revised procedure now lets us draw the portion of the left-translated figure that is still on screen.

Exercise 4: Multiple Translations

a. Write a procedure, (spots-htrans spots offset), that translates each spot in spots horizontally by offset.

b. Write a procedure, (spots-vtrans spots offset), that translates each spot in spots vertically by offset.

c. Write a procedure, (spots-translate spots hoffset voffset), that translates each spot in spots horizontally by hoffset and vertically by voffset.

Exercise 5: Replicating Figures

a. What do you expect the value of aardvark to be after the following definition?

> (define aardvark (map (lambda (offset) (spots-htrans figure offset)) (list 1 2 4 8)))

b. Check your answer experimentally.

c. As you should have discovered, these instructions create a list of lists of spots.

d. What effect do you expect the following command to have?

> (image-render-spots! canvas aardvark)

e. Check your answer experimentally.

f. What effect do you expect the following command to have?

> (foreach! (lambda (spots) (image-render-spots! canvas spots)) aardvark)

g. Check your answer experimentally.

h. What effect do you expect the following command to have?

> (foreach! (lambda (factor) (image-scaled-render-spots! canvas figure factor)) 
      (list 1 2 3 4 5))

i. Check our answer experimentally.

For Those With Extra Time

Those with extra time may choose to do the extra problems, which focus on programming tasks, or the explorations, which focus on the application of procedures to image creation. Those who do the programming oriented exercises might start with extra 1 or with extra 3.

Extra 1: Getting Spots

a. Write a procedure, (image-get-spot image col row), that gets the spot that corresponds to the given position in the image. That is, if the color at position (col,row) is c, then image-get-spot will return (col row c).

Hint: You will probably need to use image-get-pixel, and spot-new.

b. Write a procedure, (image-get-spots-from-row image row cols) that gets spots from the given row, but only at the selected columns. For example,

> (image-get-spots-from-row 10 (list 1 2 3 4 5))

will get the spots at positions (1,10), (2,10), (3,10), (4,10), and (5,10).

Note that you will need to use map to write this procedure.

Extra 2: Getting Lots of Spots

Pick a group of interesting positions in picture and, by using image-get-spots-from-row, turn them into a list of spots. Name the result stamp. For example,

> (define stamp 
    (append (image-get-spots-from-row 100 (list 10 11 12 13 14 15))
            (image-get-spots-from-row 101 (list 11 12 13 14 15))
            (image-get-spots-from-row 102 (list 12 13 14 15))
            (image-get-spots-from-row 103 (list 13 14 15))
            (image-get-spots-from-row 104 (list 14 15))
            (image-get-spots-from-row 105 (list 15)))

b. Render a copy of the stamp elsewhere in the image.

c. Render another copy of the stamp elsewhere in the image.

Extra 3: Mirroring Lists of Spots

a. Write a procedure, (spots-hmirror spots col), that “mirrors” the figure given by spots around the vertical line through col. For example, if a spot is at (1,2), and we horizontally mirror that spot around column 5, we get a spot at (9,2) with the same color. (How did we get 9 from 1? 1 is 4 less than 5, so it mirrors to 4 greater than 5.) Similarly, a spot at (8,3) would mirror to (2,3). A spot in column 5 would stay where it is.

b. Write a similar procedure, (spots-vmirror spots row), the mirrors the figure given by spots around the horizontal line through row.

Explorations

Explorations are intended for students interested in further exploring the design aspects of these techniques. They also provide students who finish early with extra activities that may challenge them in different ways.

In this lab, you've discovered how to write concise code that lets you render the same list of spots in multiple scales and with multiple offsets.

Create a simple list of spots and, from that list of spots, generate an interesting drawing by both offsetting and scaling the list.

Some Useful Definitions

This lab depends on a variety of procedures that you should have defined in the lab on representing images as lists of spots. However, some of you may have not had time to complete all of those problems and others of you may not be sure of your answers. Here are some possible definitions.

;;; Procedure:
;;;   spot-new
;;; Parameters:
;;;   col, an integer
;;;   row, an integer
;;;   color, a color (name, RGB, etc.)
;;; Purpose:
;;;   Create a new spot.
;;; Produces:
;;;   spot, a spot
;;; Preconditions:
;;;   [No additional]
;;; Postconditions:
;;;   (spot-col spot) = col
;;;   (spot-row spot) = row
;;;   (spot-color spot = color
(define spot-new
  (lambda (col row color)
    (list col row color)))

;;; Procedure:
;;;   spot-col
;;; Parameters:
;;;   spot, a spot
;;; Purpose:
;;;   Extract the col from a spot.
;;; Produces:
;;;   col, an integer
(define spot-col
  (lambda (spot)
    (car spot)))

;;; Procedure:
;;;   spot-row
;;; Parameters:
;;;   spot, a spot
;;; Purpose:
;;;   Extract the row from a spot.
;;; Produces:
;;;   row, an integer
(define spot-row
  (lambda (spot)
    (cadr spot)))

;;; Procedure:
;;;   spot-color
;;; Parameters:
;;;   spot, a spot
;;; Purpose:
;;;   Extract the color from a spot.
;;; Produces:
;;;   color, an integer
(define spot-color
  (lambda (spot)
    (caddr spot)))

;;; Procedure:
;;;   spot-htrans
;;; Parameters:
;;;   spot, a spot
;;;   offset, a number
;;; Purpose:
;;;   Translate the spot horizontally by offset.  If offset is positive,
;;;   the spot is translated right.  If offset is negative, the spot
;;;   is translated left.
;;; Produces:
;;;   new-spot, a spot
;;; Preconditions:
;;;   [No additional]
;;; Postconditions:
;;;   (spot-col new-spot) = (spot-col spot) + offset 
(define spot-htrans
  (lambda (spot offset)
    (spot-new (+ (spot-col spot) offset) (spot-row spot) (spot-color spot))))

;;; Procedure:
;;;   spot-vtrans
;;; Parameters:
;;;   spot, a spot
;;;   offset, a number
;;; Purpose:
;;;   Translate the spot vertically by offset.  If offset is positive,
;;;   the spot is translated down.  If offset is negative, the spot
;;;   is translated up.
;;; Produces:
;;;   new-spot, a spot
;;; Preconditions:
;;;   [No additional]
;;; Postconditions:
;;;   (spot-row new-spot) = (spot-row spot) + offset 
(define spot-vtrans
  (lambda (spot offset)
    (spot-new (spot-col spot) (+ (spot-row spot) offset) (spot-color spot))))

;;; Procedure:
;;;   image-render-spot!
;;; Parameters:
;;;   image, an image
;;;   spot, a spot
;;; Purpose:
;;    Draw the spot on the image.
;;; Produces:
;;;   [Nothing; Called for the side effect]
(define image-render-spot!
  (lambda (image spot)
    (context-set-fgcolor! (spot-color spot))
    (image-select-rectangle! image selection-replace
                             (spot-col spot) (spot-row spot) 1 1)
    (image-fill! image)
    (image-select-nothing! image)))

;;; Procedure:
;;;   image-scaled-render-spot!
;;; Parameters:
;;;   image, an image
;;;   spot, a spot
;;;   factor, a number
;;; Purpose:
;;    Draw the spot on the image, scaled by a factor of factor.
;;; Produces:
;;;   [Nothing; Called for the side effect]
;;; Preconditions:
;;;   factor >= 1
;;;   The position of the scaled spot is within the bounds of the image.
;;; Postconditions:
;;;   The image now contains a rendering of the spot.
(define image-scaled-render-spot!
  (lambda (image spot factor)
    (context-set-fgcolor! (spot-color spot))
    (image-select-ellipse! image selection-replace
                             (* factor (spot-col spot))
                             (* factor (spot-row spot))
                             factor factor)
    (image-fill! image)
    (image-select-nothing! image)))

Creative Commons License

Samuel A. Rebelsky, rebelsky@grinnell.edu

Copyright (c) 2007-8 Janet Davis, Matthew Kluber, and Samuel A. Rebelsky. (Selected materials copyright by John David Stone and Henry Walker and used by permission.)

This material is based upon work partially supported by the National Science Foundation under Grant No. CCLI-0633090. Any opinions, findings, and conclusions or recommendations expressed in this material are those of the author(s) and do not necessarily reflect the views of the National Science Foundation.

This work is licensed under a Creative Commons Attribution-NonCommercial 2.5 License. To view a copy of this license, visit http://creativecommons.org/licenses/by-nc/2.5/ or send a letter to Creative Commons, 543 Howard Street, 5th Floor, San Francisco, California, 94105, USA.