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

Laboratory: Writing Your Own Procedures


Summary: In this laboratory, you will explore some of the issues that pertain to writing your own procedures.

Preparation

a. Review How Scheme Evaluates Expressions (version 2).

b. Create a new 200x100 image and call it canvas.

Exercises

Exercise 1: Sanity Check

a. Copy the following procedures from the reading into the definitions pane: square, turtle-penta-draw!, drawing-new-circle, and compute-grade (second version).

b. Verify that square correctly squares the numbers 5, 10, -3, 1.2, and 0.05.

c. Verify that turtle-penta-draw! draws a pentagon when given an angle of 72 degrees. (You will need to create a turtle, put it somewhere near the middle of the canvas, and then call this procedure.)

d. Verify that turtle-penta-draw! draws a star when given an angle of 144 degrees.

e. What do you expect to happen if you give turtle-penta-draw! an angle of 120 degrees?

f. Check your answer experimentally.

g. Use drawing-new-circle to create a blue circle of radius 50, centered at (80,40).

Exercise 2: Grading, Revisited

a. Check that the second version of compute-grade computes a grade using the strategy specified in the narrative. (That is, that it drops the lowest grade and doubles the highest grade.) You might, for example, use grades of 0, 50, 50, 50, 50, and 80.

b. Write a new version of compute-grade that drops both the lowest and highest grade.

c. Does this new version correspond to the documentation given in the reading? Why or why not?

d. Suppose someone wrote a new version of compute-grade that returns the average of the homework assignments, with an additional one point of extra credit for each assignment over 80. Would this version correspond to the documentation? Why or why not?

Exercise 3: Turtle Squares

Recall that one can teach a turtle to draw a square by having it move forward and turn 90 degrees four times.

(turtle-forward! tommy 100)
(turtle-turn! tommy 90)
(turtle-forward! tommy 100)
(turtle-turn! tommy 90)
(turtle-forward! tommy 100)
(turtle-turn! tommy 90)
(turtle-forward! tommy 100)

a. Write a procedure, (turtle-square! turtle side), that tells the turtle to draw a square of the specified edge length.

b. What happens if you call this procedure twice, using a side length of 40 both times?

c. As you may have just observed, the second time you call turtle-square!, the turtle draws a new square, next to the first. Arguably, it should have drawn the same square again. Why didn't it? Because the turtle was facing in a different direction. What's the solution? We should strive to write turtle procedures that restore the turtle to its starting state. Update turtle-square! so that it returns the turtle to not just position with which it started to draw, but also the orientation.

Exercise 4: Turtle Triangles

Write a procedure, (turtle-triangle! turtle side-length), that draws an equilateral triangle of the specified side length. Make sure that the procedure returns the turtle to the position and orientation it had before the procedure started.

Exercise 5: Generalizing the Drawing of Squares

While the turtle-square! is useful for drawing squares, it's also depends a bit on context. For example, it draws in the current color and brush, and draws the square starting at the turtle's current position. What if we want to more-precisely specify the square to be drawn, including its color, brush, and position? We could simply set that context before we draw each time, or we could make those additional factors parameters to our procedure. Let's try the second approach.

Write a procedure, (turtle-outline-square! turtle color brush left top side), that has the turtle outline a square in the specified color, using the specified brush.

For Those With Extra Time

Extra 1: GIMP Squares

In the drawing examples above, we've only used the turtle model of describing images. However, we've certainly learned other models. Let's try writing a similar procedure for GIMP.

In particular, write a procedure, (image-outline-square! image color brush left top side), that uses the GIMP tools to create a stroked image of the specified width and height, in the specified color and brush.

Extra 2: Square Drawings

As you may recall, the “drawings as values” model is useful for a number of reasons, not least is that it's reliance on pure functions, function without side effects. Let's see if we can use that model to describe an outlined square.

Write a procedure, (drawing-outlined-square color brush left top side), that constructs an outlined square of the specified color, position, and size.

Extra 3: Rectangular Drawings

Can we further generalize the square drawing procedures we described above? Certainly. We might have them create rectangles, rather than squares.

a. Write turtle-outline-rectangle!.

b. Write image-outline-rectangle!.

c. Write drawing-outlined-rectangle.

d. You should have found that the rectangle procedures closely resembled the square procedures. Is it necessary to have so much code duplication? Certainly not! In particular, we could make the body of each square procedure a call to the corresponding rectangle procedure, using the side length for both width and height. Make this change, and test to see whether or not it works.

Explorations

You may recall that in our exploration of drawings, we sometimes built “grids” from a single drawing by grouping a drawing with one or more shifted versions of the drawing. It might we worthwhile to write procedures that do the same thing.

Here are three procedures that, together, make a four-by-four grid from a particular image.

;;; Procedure:
;;;   drawing-hpair
;;; Parameters:
;;;   drawing, a drawing value
;;;   offset, a real number
;;; Purpose:
;;;   Create a new drawing that is two copies of drawing, side-by-side,
;;;   with their left edges separated by offset.
;;; Produces:
;;;   paired-drawing, a drawing value
;;; Preconditions:
;;;   [No additional]
;;; Postconditions:
;;;   paired-drawing, when rendered on an image, contains two copies
;;;   of drawing, one at the same position at drawing and the other
;;;   horizontally offset by offset units.
(define drawing-hpair
  (lambda (drawing offset)
    (drawing-join drawing
                  (drawing-hshift drawing offset))))

;;; Procedure:
;;;   drawing-vpair
;;; Parameters:
;;;   drawing, a drawing value
;;;   offset, a real number
;;; Purpose:
;;;   Create a new drawing that is two copies of drawing, stacked
;;;   top to bottom, with their top edges separated by offset.
;;; Produces:
;;;   paired-drawing, a drawing value
;;; Preconditions:
;;;   [No additional]
;;; Postconditions:
;;;   paired-drawing, when rendered on an image, contains two copies
;;;   of drawing, one at the same position at drawing and the other
;;;   vertically offset by offset units.
(define drawing-vpair
  (lambda (drawing offset)
    (drawing-join drawing
                  (drawing-vshift drawing offset))))

;;; Procedure:
;;;   drawing-row-of-four
;;; Parameters:
;;;   drawing, a drawing value
;;;   offset, a real number
;;; Purpose:
;;;   Create a new drawing that is four copies of drawing, side-by-side,
;;;   with their left edges separated by offset.
;;; Produces:
;;;   row-of-four, a drawing value
;;; Preconditions:
;;;   [No additional]
;;; Postconditions:
;;;   paired-drawing, contains four copies of drawing.  The first is at
;;;   the same postion, the second is offset by offset, the third is
;;;   offset by 2*offset, and the fourth is offset by 3*offset.
(define drawing-row-of-four
  (lambda (drawing offset)
    (drawing-hpair (drawing-hpair drawing offset) (* 2 offset))))

;;; Procedure:
;;;   drawing-simple-grid
;;; Parameters:
;;;   drawing, a drawing value
;;;   hoffset, a real number
;;;   voffset, a real number
;;; Purpose:
;;;   Make a "grid" of four copies of drawing.
;;; Produces:
;;;   grid-drawing, a drawing
;;; Preconditions:
;;;   [No additional]
;;; Postconditions:
;;;   grid-drawing consists of four copies of drawing.
;;;   * The first is at the same position as drawing
;;;   * The second is horizontally offset by hoffset
;;;   * The third is vertically offset by voffset
;;;   * The fourth is horizontally offset by hoffset and vertically
;;;     offset by voffset.
(define drawing-simple-grid
  (lambda (drawing hoffset voffset)
    (drawing-vpair (drawing-hpair drawing hoffset) voffset)))

Use these procedures, along with some the circle drawing procedure from the reading, to create an interesting image. Note, as drawing-row-of-four and drawing-simple-grid suggest, you can get get larger grids by nesting these procedures.

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.