@comment(Hey, EMACS, this is -*- SCRIBE -*- input)
@make(6001)

@set(chapter=1)
@set(page=1)

@PageHeading(even,
             left "@Value(Page)",
             right "6.001")

@PageHeading(odd,
             Left "Problem Set 3",
             right "@value(page)")

@begin(center)
MASSACHUSETTS INSTITUTE OF TECHNOLOGY
Department of Electrical Engineering and Computer Science
6.001 Structure and Interpretation of Computer Programs

Problem Set 3
@end(center)
@blankspace(0.25 in)

@begin(format)
Issued: 27 September 1983@>Due: in Recitation, 5 October 1983

Reading Assignment: Reading: Chapter 2, Sections 2.1, 2.2.1
@end(format)

@begin(figure)
@blankspace(3 inches)
@caption{Tiling patterns (made by Andy diSessa and Doug Hill).  This
assignment asks you to implement a graphics language for drawing
figures such as these.}
@tag(tiling-patterns)
@end(figure)

Write up and turn in the following exercises from the text:
@begin(itemize)
Exercise 2-3: Representing pairs as procedures

Exercise 2-17: Defining @a[reverse]

Exercise 2-18: @a[Square-list]

Exercise 2-19: Debugging @a[square-list]

Exercise 2-20: @a[Mapcar]
@end(itemize)

@section(Lecture Notes:  The Square-Limit Language)

The laboratory assignment for this week begins on page
@pageref(laboratory-assignment) of this handout.  For the assignment,
you are to implement a variation of Peter Henderson's ``Escher
Square-Limit'' language, which will be discussed in lecture on
Thursday, September 29.  This handout begins with a listing of the
procedures that implement Henderson's language.  The explanation given
here is very minimal, since this will be covered in lecture on
Thursday.  @b[You should bring this handout with you to the Thursday
lecture, so that you can refer to the listings.]  You should probably
wait to begin the lab assignment until after you have heard the
lecture.

Thursday's lecture will discuss a simple figure drawing language due
to Peter Henderson, of Oxford University.  One interesting feature of
the implementation is that it represents figures as procedures.

A ``picture'' is defined to be a procedure that takes a rectangle as
input and causes something to be drawn, scaled to fit in the
rectangle.  A rectangle will be represented by three vectors: an
origin, a ``horizontal'' vector, and a ``vertical'' vector.  Any
rectangle defines a linear transformation coordinate map by
@begin(example)
       (1,0) --> horizontal
       (0,1) --> vertical
@end(example)
that is, a general point (x,y)
gets mapped to the vector
@begin(example)
<x>*<horizontal> + <y>*<vertical>
@end(example)
offset by the origin of the rectangle.
We represent a rectangle by a list of three vectors: the location of the
origin of the rectangle, the vector from that origin to the end of the
``horizontal'' axis, and the vector to the end of the ``vertical'' axis.
@begin(example)
(define make-rect list)             ;; origin-vect H-vect V-vect
(define origin first)
(define horiz second)
(define vert third)
@end(example)
Using this map, points with coordinates between 0 and 1 end up inside
the rectangle.  Here is a procedure that takes a rectangle as input
and returns the corresponding coordinate transformation:
@begin(programexample)
(define (coord-map rect)
  (lambda (point)
    (+vect
     (+vect (scale (xcor point)
                   (horiz rect))
            (scale (ycor point)
                   (vert rect)))
     (origin rect))))
@end(programexample)
A picture is defined by a
collection of line segments.
Segments are
represented as pairs of points, and
points (vectors) are represented as pairs of numbers:

@begin(programexample)
(define make-vector cons)
(define xcor car)
(define ycor cdr)

(define make-segment cons)
(define seg-start car)
(define seg-end cdr)
@end(programexample)


Given a rectangle as input, the picture
draws the image of each line segment inside the rectangle.  Here is a
procedure that constructs the picture, given a list of segments:
@begin(programexample)
(define (make-picture seglist)
  (lambda (rect)
    (mapc
     (lambda (segment)
       (drawline ((coord-map rect) (seg-start segment))
                 ((coord-map rect) (seg-end segment))))
     seglist)))

(define empty-picture (make-picture '()))
@end(programexample)
To rotate a picture 90 degrees counterclockwise, we need only draw the
picture with respect to a new rectangle:
@begin(programexample)
 V ---------------            --------------- H'=V
   |             |            |             |
   |         |   |            |   ---o      |
   |  -------/   |    --->    |      |      |
   |             |            |      |      |
   ---------------            ---------------
 O               H           V'=-H          O'=O+H

(define (rotate90 pict)
  (lambda (rect)
    (pict (make-rect
           (+vect (origin rect)          ;O'
                  (horiz rect))          
           (vert rect)                   ;H'
           (scale -1 (horiz rect))))))   ;V'

(define (repeated function n)
  (lambda (thing)
    (if (= n 0) thing
	((repeated function (-1+ n)) (function thing)))))

(define rotate180 (repeated rotate90 2))
(define rotate270 (repeated rotate90 3))
@end(programexample)
Horizontal flip is also drawing with respect to a new rectangle:
@begin(programexample)
 V ---------------            --------------- V'=V
   |             |            |             |
   |         |   |            |  |          |
   |  -------/   |    --->    |  \-------   |
   |             |            |             |
   ---------------            ---------------
 O               H           H'=-H          O'=O+H


(define (flip pict)
  (lambda (rect)
    (pict (make-rect (+vect (origin rect) (horiz rect))
                          (scale -1 (horiz rect))
                          (vert rect)))))
@end(programexample)
The @a[together] operation takes two pictures and combines them into a
single picture, lying superimposed.
@begin(programexample)
(define (together pict1 pict2)
  (lambda (rect)
    (pict1 rect)
    (pict2 rect)))
@end(programexample)
The @a[beside] operation takes two pictures with relative widths and
scales them to fit in a single rectangle.  Input is percentage of
horizontal devoted to the first picture
@begin(programexample)
(define (beside pict1 pict2 a)
  (lambda (rect)
    (pict1 (make-rect
            (origin rect)
            (scale a (horiz rect))
            (vert rect)))
    (pict2 (make-rect
            (+vect (origin rect)
                   (scale a (horiz rect)))
            (scale (- 1 a) (horiz rect))
            (vert rect)))))
@end(programexample)
@a[Above] is defined in terms of @a[beside]
@begin(programexample)
(define (above pict1 pict2 a)
  (rotate270 (beside (rotate90 pict1)
                     (rotate90 pict2)
                     a)))
@end(programexample)

Here are some operations defined in terms of the basic ones above:
@begin(programexample)
(define (4pict pict1 rot1 pict2 rot2 pict3 rot3 pict4 rot4)
  (beside (above ((repeated rotate90 rot1) pict1)
                 ((repeated rotate90 rot2) pict2)
                 .5)
          (above ((repeated rotate90 rot3) pict3)
                 ((repeated rotate90 rot4) pict4)
                 .5)
          .5))

(define (4same pict rot1 rot2 rot3 rot4)
  (4pict pict rot1 pict rot2 pict rot3 pict rot4))

(define (up-push pict n)
  (if (= n 0)
      pict
      (above (up-push pict (-1+ n))
             pict
             .25)))

(define (right-push pict n)
  (if (= n 0)
      pict
      (beside pict (right-push pict (-1+ n)) .75)))

(define (corner-push pict n)
  (if (= n 0)
      pict
      (above
       (beside (up-push pict n)
               (corner-push pict (-1+ n))
               .75)
       (beside
        pict
        (right-push pict (-1+ n))
        .75)
       .25)))

(define (square-limit pict n)
  (4same (corner-push pict n) 1 2 0 3))
@end(programexample)

The rectangle that defines the original screen of the Chipmunk is
defined as:
@begin(programexample)
(define screen (make-rect (make-vector -190 -190) 
			  (make-vector 380 0)
			  (make-vector 0 380)))
@end(programexample)
A useful test pattern is that outlining a rectangle:
@begin(programexample)
(define outline-picture
  (make-picture (list (make-segment (make-vector 0 0)
                                    (make-vector 0 1))
                      (make-segment (make-vector 0 1)
                                    (make-vector 1 1))
                      (make-segment (make-vector 1 1)
                                    (make-vector 1 0))
                      (make-segment (make-vector 1 0)
                                    (make-vector 0 0)))))
@end(programexample)
With the above, one could, for example, cause the outline rectangle to
be drawn on the full (square) screen by:
@begin(programexample)
(outline-picture screen)
@end(progamexample)
The following function, which applies its argument to the screen after
clearing the graphics screen, will save some typing.
@begin(programexample)
(define (draw pict)
  (clear-graphics)
  (pict screen))
@end(progamexample)
The definitions below present a few simple (and not very interesting)
patterns.  To gain a better understanding of the square-limit language,
you may play with them using various combinations of the
operators, and define new primitives.
All the code in this description of the square-limit language may be
loaded by using @b[load problem set] and specifying @a[problem set number]
as @a[squares].  Note that this description (and code and suggestions)
are for your edification only.  There is nothing to hand in related to
the square-limit language.
@begin(programexample)
(define wedge (make-picture
               (list (make-segment (make-vector 0 0)
                                   (make-vector .5 .5))
                     (make-segment (make-vector .5 .5)
                                   (make-vector 1 0)))))


(define line (make-picture
              (list (make-segment (make-vector 0 .5)
                                  (make-vector 1 .5)))))

(define star (make-picture
              (list (make-segment (make-vector 0 .5)
                                  (make-vector .5 0))
                    (make-segment (make-vector .5 0)
                                  (make-vector 1 .5))
                    (make-segment (make-vector 1 .5)
                                  (make-vector .5 1))
                    (make-segment (make-vector .5 1)
                                  (make-vector 0 .5)))))
@end(programexample)

@section(Laboratory Assignment: A Drawing Language Based on Triangles)
@label(laboratory-assignment)

For this assignment, you are to implement a language similar to
Henderson's, except based on triangles rather than squares.  We begin
by describing the implementation, and listing the procedures that have
been installed on the Chipmunk system for you to work with.

The implementation of the language is very similar to the one
described above.

@paragraph(Points and segments)

Points (vectors) are represented as pairs of numbers, and segments are
represented as pairs of points:
@begin(programexample)
(define make-vector cons)
(define xcor car)
(define ycor cdr)

(define make-segment cons)
(define seg-start car)
(define seg-end cdr)
@end(programexample)

We use will the operations of vector addition, subtraction, and
scaling a vector by a number:
@begin(programexample)
(define (+vect v1 v2)
  (make-vector (+ (xcor v1) (xcor v2))
               (+ (ycor v1) (ycor v2))))

(define (-vect v1 v2)
  (+vect v1 (scale -1 v2)))

(define (scale x v)
  (make-vector (* x (xcor v))
               (* x (ycor v))))
@end(programexample)

We will also make use of an operation called @a[shift], which takes as
arguments two vectors @a[o1] and @a[o2] and a vector @a[v] which is
meant to represent a point relative to an ``origin'' @a[o1].
@a[Shift] returns a vector that represents the same point as @a[v],
but with respect to the ``origin'' @a[o2].  See figure @ref(shift).
@begin(programexample)
(define (shift v o1 o2)
  (-vect (+vect v o1) o2))
@end(programexample)
@begin(figure)
@blankspace(3 inches)
@caption(Shifting a vector from one origin to another.)
@tag(shift)
@end(figure)

The following procedure takes 2 points as arguments and draws a line
between them on the Chipmunk screen.

@begin(programexample)
(define (drawline start end)
  (position-pen (xcor start) (ycor start))
  (draw-line-to (xcor end) (ycor end)))
@end(programexample)

@paragraph(Triangles)

@begin(programexample)
(define make-triangle list)

(define origin car)
(define side1 cadr)
(define side2 caddr)
@end(triangle)


A triangle is represented as a triple of vectors -- an origin and two
sides.  See figure @ref(triangle).  The origin will be represented as
a vector whose coordinates give the coordinates of the origin with
respect to some external coordinate system, such as the graphics
screen coordinates.  The two sides are specified as vectors which give
the @i[offsets] of the other two vertices of the triangle from the
origin point.  In other words, they specify the coordinates of the
other two vertices with respect to a coordinate system whose
``origin'' is at the @a[origin] of the triangle.

As shown in figure @ref(triangle), we can express the points of a
triangle in terms of so-called @i[triangular coordinates], which are
pairs @a[x], @a[y] such that @a[x+y]@lessequal()1.  Another way to
say this is that each point of the triangle can be expressed as a
vector
@begin(example)
x Side@-[1](Tri) + y Side@-[2](Tri)
@end(example)
where @a[x+y]@lessequal()1.  Still another way to express this is
that mapping the point in the plane whose coordinates are @a[x],@a[y]
to the point given by
@begin(example)
Origin(Tri) + x Side@-[1](Tri) + y Side@-[2](Tri)
@end(example)
maps one-half of the unit square onto the given triangle.
@begin(programexample)
(define (coord-map triangle)
  (lambda (point)
    (+vect
     (+vect (scale (xcor point)
                   (side1 triangle))
            (scale (ycor point)
                   (side2 triangle)))
     (origin triangle))))
@end(programexample)
@begin(figure)
@blankspace(3 inches)
@caption(A triangle represented as origin and two sides; triangular
coordinates.)
@tag(triangle)
@end(figure)

Finally, we define a standard @a[screen-triangle], which is an
isosceles triangle whose base and height are the edges of the Chipmunk
screen:
@begin(programexample)
(define screen-lower-left (make-vector -190 -190))
(define screen-lower-right (make-vector 190 -190))
(define screen-upper-left (make-vector  -190 190))

(define screen-lower-edge
  (-vect screen-lower-right screen-lower-left))

(define screen-left-edge
  (-vect screen-upper-left screen-lower-left))

(define screen-triangle
  (make-triangle screen-lower-left
                 screen-lower-edge
                 (+vect screen-left-edge
                        (scale 0.5 screen-lower-edge))))
@end(programexample)

@paragraph(Pictures)

As in the square-limit language, a picture is a procedure, this time a
procedure on triangles, which draws inside the given triangle.
@a[Make-picture] constructs a picture from a list of segments:
@begin(programexample)
(define (make-picture seglist)
  (lambda (triangle)
    (mapc
     (lambda (segment)
       (drawline ((coord-map triangle) (seg-start segment))
                 ((coord-map triangle) (seg-end segment))))
     seglist)))
@end(programexample)

We will also define some simple pictures to use as drawing elements:
the empty picture, a picture that just outlines the triangle, one that
connects the center of the triangle to the midpoints of the sides, and
one that draws a ``V'' shape.  Figure @ref(sample-pictures) shows how
these figures are specified in terms of triangular coordinates.
@begin(programexample)
(define empty-picture (make-picture '()))

(define outline-picture
  (let ((v1 (make-vector 0 0))
	(v2 (make-vector 0 1))
	(v3 (make-vector 1 0)))
    (make-picture (list (make-segment v1 v2)
			(make-segment v2 v3)
			(make-segment v3 v1)))))

(define midpoints
  (let ((center (make-vector (/ 1 3) (/ 1 3)))
	(m1 (make-vector (/ 1 2) 0))
	(m2 (make-vector 0 (/ 1 2)))
	(m3 (make-vector (/ 1 2) (/ 1 2))))
    (make-picture (list (make-segment m1 center)
			(make-segment m2 center)
			(make-segment m3 center)))))

(define v-shape
  (let ((m1 (make-vector (/ 2 9) (/ 2 9)))
        (m2 (make-vector (/ 4 9) (/ 4 9)))
        (a1 (make-vector (/ 1 3) 0))
        (a2 (make-vector (/ 2 3) 0))
        (b1 (make-vector 0 (/ 1 3)))
        (b2 (make-vector 0 (/ 2 3))))
    (make-picture (list (make-segment a1 m1)
                        (make-segment m1 b1)
                        (make-segment a2 m2)
                        (make-segment m2 b2)))))

@end(programexample)

@begin(figure)
@blankspace(3 inches)
@caption(Sample pictures, specified using triangular coordinates.)
@tag(sample-pictures)
@end(figure)

@paragraph(Means of combination)

We define a means of combination, called @a[split], which takes
as arguments two pictures and a @a[ratio] between 0 and 1.  When given
a triangle as argument, the @a[split] picture first splits the
triangle by dividing @a[side1] of the triangle as specified by the
@a[ratio].  Then it draws one picture in each subtriangle, as shown in
figure @ref(split).

@begin(figure)
@blankspace(3 inches)
@caption(The @a[split] combination of two pictures.)
@tag(split)
@end(figure)

The procedure for @a[split] must compute the new origin and sides for
each of the two component triangles.
@begin(programexample)
(define (split pict1 pict2 ratio)
  (lambda (triangle)
    (define p (scale ratio (side1 triangle)))
    (define oa (origin triangle))
    (define ob (+vect (origin triangle) p))
    (pict1 (make-triangle oa p (side2 triangle)))
    (pict2 (make-triangle ob
                           (shift (side1 triangle) oa ob)
                            (shift (side2 triangle) oa ob)))))
@end(programexample)
We first compute the vector @a[p], which represents be point on the
side where the triangle is to be split.  (Note that @a[p] will be
given as a vector with respect to the origin of the triangle to be
split.)  The first subtriangle has origin @a[oa] the same as the
original triangle, @a[side1] given by @a[p], and @a[side2] which is
the same as the @a[side2] of the original triangle.  The second
subtriangle has an origin @a[ob] at the point designated by @a[p].
Observe that, in order to express this as a vector in external
coordinates, we must take the vector sum of @a[p] with the origin of
the original triangle.  The @a[side1] and @a[side2] of the second
subtriangle are the vectors running from @a[ob] to the endpoints of
the sides of the original triangle.  We can compute the vectors
running to these points from the new origin @a[ob] by using the
@a[shift] procedure as follows:  With respect to the @i[old] origin,
these points are given by @a[side1] and @a[side2].  So we use
@a[shift] to express these same points as vectors with respect to the
origin @a[ob].

@section(To do in lab)

Begin by installing the code for problem set 3 on your floppy disk,
using the @a[load-problem-set] operation documented in the Chipmunk
manual.  The file to be loaded contains all of the code listed above
in section @ref(laboratory-assignment).  You will not need to edit or
modify any of it.  The ``modifications file'' for problem set 3 that
will be installed on your disk is an empty file, since for this
problem set you will be writing new procedures, rather than modifying
procedures that we supply.

@paragraph(Part 1)

Draw some pictures to test the procedures.  To draw a picture, clear
the graphics screen by calling @a[clear-graphics], and run the picture
(procedure) using @a[screen-triangle] as an argument.  Use @a[split]
to make various combinations of the pre-defined elementary pictures.

@paragraph(Part 2)

Use @a[split] to define an operation called @a[push] which is
analogous to @a[right-push] of the square-limit language.  Test your
procedure by trying it out on some of the simple figures provided.
Turn in a listing of the procedure.

@paragraph(Part 3)

For this part, you are to define a rotation operator on pictures.  The
rotation of a picture draws the picture in the specified triangle, but
``rotated'' so that a different vertex of the triangle is taken as the
origin.  See figure @ref(flip-and-rotate).  Note that the test
pictures @a[outline-picture] and @a[midpoints] won't look any
different when rotated, so you should use @a[v-shape] to test your
procedure.

You should define two rotate operations, which rotate the figure
``in the opposite direction,''  Call them @a[rotate-1] and @a[rotate-2].
Observe that @a[rotate-2] is easily defined in terms of @a[rotate-1].
(Compare the rotation operators in the square-limit language.)
Turn in listings of your procedures.

@begin(figure)
@blankspace(3 inches)
@caption(Rotating and flipping pictures.)
@tag(flip-and-rotate)
@end(figure)

@paragraph(Part 4)

Define an operator @a[flip] which produces a picture that it flipped
from the original about a line drawn from the origin of the triangle
to the opposite side.  See figure @ref(flip-and-rotate).  This is
actually quite simple to do, since the ``flip'' triangle is the same
as the original triangle, with the roles of @a[side1] and @a[side2]
interchanged.

@paragraph(Part 5)

Figure @ref(4split) illustrates a means of combination called
@a[4split], which takes as its arguments four pictures and three
numbers @a[r1], @a[r2], @a[r3] between 0 and 1, and combines them as
shown in the figure.  The orientation of the small triangles does not matter.

For this part, you are to implement @a[4split]
and turn in a listing of your procedure.

This procedure can be rather tricky, especially if you are not used to
expressing points in terms of vectors, so think about it before you
start coding.  To help you, figure @ref(4split) gives the triangular
coordinates of the ``split points.''  You can also make good use of
the @a[shift] procedure, as in the implementation of @a[split]
discussed above.  Also, a good way to test your procedure is to run it
with all four pictures as the @a[outline-picture], and to draw the
result.

@begin(figure)
@blankspace(3 inches)
@caption(Using @a[4split] to combine 4 pictures.)
@tag(4split)
@end(figure)
@paragraph(Part 6)

The following @a[equal-split] procedure uses @a[4split] to replicate a
single picture 4 times, dividing the sides of the original triangle in
half.
@begin(programexample)
(define (equal-split pict)
  (4split pict pict pict pict .5 .5 .5))
@end(programexample)

We could imagine a generalization of @a[equal-split], which uses the
same picture four times, but with the sides split using different
ratios.  One way to do this is to define a procedure similar to
@a[equal-split], but which takes as arguments a picture and also the
three ratios. An alternative method is to use a higher-order procedure,
which, given the three ratios, will generate a procedure that takes a
picture as argument.  In other words, if we call this higher-order
procedure @a[make-splitter], then writing
@begin(programexample)
(define equal-split (make-splitter .5 .5 .5))
@end(programexample)
should be an equivalent way to define @a[equal-split].  For this part,
you are to implement and turn in a listing of the @a[make-splitter]
procedure.  As a hint, notice the @a[make-splitter] will have the
following form:
@begin(programexample)
(define (make-splitter r1 r2 r3)
  (lambda (pict)
    ...))
@end(programexample)

As a test, try drawing
@begin(programexample)
(define web ((make-splitter .2 .5 .8) midpoints))
@end(programexample)

Turn in a listing of @a[make-splitter].

@paragraph(Part 7)

Suppose we use @a[4split] recursively: split a picture which is itself
a split, and so on.  Here is an extended version of the
@a[equal-split] procedure given above, which performs this splitting
to a specified number of levels:
@begin(programexample)
(define (rec-equal-split pict levels)
  (if (= levels 0)
      pict
      (let ((p (rec-equal-split pict (-1+ levels))))
        (4split p p p p .5 .5 .5))))
@end(programexample)

Now suppose we want to generalize this procedure as in part 6, that is
to have a higher-order procedure that will create things like
@a[rec-equal-split], except where the splitting ratios of the sides
can be other than one half.  We want a procedure
@a[make-rec-splitter], such that @a[rec-equal-split] could be defined as
@begin(programexample)
(define rec-equal-split (make-rec-splitter .5 .5 .5)
@end(programexample)

Test your procedure by drawing some figures, and turn in a listing.

@paragraph(Part 8)

The procedures you have implemented give you a wide choice of things
to experiment with. For example, even if you specify that you will
start with a single picture element, and perform a @a[4split] to
three levels using .5 as the splitting ratios, there are still a
tremendous number of variations, since for each @a[4split] you can
choose to rotate and/or flip each of the component pictures.

There is nothing to turn in for this part of the assignment, but we
hope you will spend some time experimenting with these possibilities.
The patterns in figure @ref(tiling-patterns) were produced in just
this way, using picture elements similar to the ones you have here.
What kinds of patterns can you discover?
