(require (planet "sicp.ss" ("soegaard" "sicp.plt" 1 1)))
(define (flipped-pairs painter)
(let ((painter2 (beside painter (flip-vert painter))))
(below painter2 painter2)))
(define wave4 (flipped-pairs einstein))

(define (right-split painter n)
(if (= n 0)
painter
(let ((smaller (right-split painter (- n 1))))
(beside painter (below smaller smaller)))))

연습문제 2.44
corner-split 프로시저에서 쓰는 up-split 프로시저를 정의하라. 이 프로시저는 right-split과 비슷하지만, below와 beside가 하던 일을 서로 뒤바꾼다는 게 다르다.
(define (corner-split painter n)
(if (= n 0)
painter
(let ((up (up-split painter (- n 1)))
(right (right-split painter (- n 1))))
(let ((top-left (beside up up))
(bottom-right (below right right))
(corner (corner-split painter (- n 1))))
(beside (below painter top-left)
(below bottom-right corner))))))
(define (up-split painter n)
(if (= n 0)
painter
(let ((smaller (up-split painter (- n 1))))
(below painter (beside smaller smaller)))))

(define (square-limit painter n)
(let ((quarter (corner-split painter n)))
(let ((half (beside (flip-horiz quarter) quarter)))
(below (flip-vert half) half))))

(define (flipped-pairs painter)
(let ((combine4 (square-of-four identity flip-vert
identity flip-vert)))
(combine4 painter)))
(define (square-limit painter n)
(let ((combine4 (square-of-four flip-horiz identity
rotate180 flip-vert)))
(combine4 (corner-split painter n))))
연습문제 2.45
right-split과 up-split을 이보다 더 쓰임새가 넓은 split 연산의 인스턴스로 정의할 수 있다. 두 프로시저를 다음과 같이 정의할 수 있도록 split 프로시저를 짜라.
(define right-split (split beside below))
(define up-split (split below beside))
painter와 n을 매개변수로 하는 함수를 만들어 반환하자.
(define (split p1 p2)
(define (combine painter n)
(if (= n 0)
painter
(let ((smaller (combine painter (- n 1))))
(p1 painter (p2 smaller smaller)))))
combine)

그림틀
(define (frame-coord-map frame)
(lambda (v)
(add-vect
(origin-frame frame)
(add-vect (scale-vect (xcor-vect v)
(edge1-frame frame))
(scale-vect (ycor-vect v)
(edge2-frame frame))))))
연습문제 2.46
원점에서 한 점에 이르는 이차원 벡터 v는 x, y 좌표의 쌍으로 나타낸다. 벡터를 짜맞추는 연산 make-vect와 벡터에서 좌표를 골라내는 연산 xcor-vect, ycor-vect를 정의하여, 요약된 벡터를 구현하라. 이 짜맞추개와 고르개를 써서 벡터의 덧셈, 뺄셈, 스칼라 곱셈 연산을 다음과 같이 처리하는 add-vect, sub-vect, scale-vect 프로시저를 구현하라.
(define (make-vect x y)
(cons x y))
(define (xcor-vect v)
(car v))
(define (ycor-vect v)
(cdr v))
(define (add-vect v1 v2)
(make-vect (+ (xcor-vect v1) (xcor-vect v2))
(+ (ycor-vect v1) (ycor-vect v2))))
(define (sub-vect v1 v2)
(make-vect (- (xcor-vect v1) (xcor-vect v2))
(- (ycor-vect v1) (ycor-vect v2))))
(define (scale-vect s v)
(make-vect (* s (xcor-vect v))
(* s (ycor-vect v))))
연습문제 2.47
그림틀 짜맞추개 make-frame은 아래 두 가지 방법으로 구현할 수 있다.
(define (make-frame origin edge1 edge2)
(list origin edge1 edge2))
(define (make-frame origin edge1 edge2)
(cons origin (cons edge1 edge2)))
이 구현을 마무리 짓기 위하여 두 방법에 알맞은 고르개 연산들을 정의해보라.
(origin-frame, edge1-frame, edge2-frame)
1번째 방법
(define (origin-frame frame)
(first frame))
(define (edge1-frame frame)
(second frame))
(define (edge2-frame frame)
(third frame))
2번째 방법
(define (origin-frame frame)
(car frame))
(define (edge1-frame frame)
(car (cdr frame)))
(define (edge2-frame frame)
(cdr (cdr frame)))
페인터
(define (segments->painter segment-list)
(lambda (frame)
(for-each
(lambda (segment)
(draw-line
((frame-coord-map frame) (start-segment segment))
((frame-coord-map frame) (end-segment segment))))
segment-lits)))
frame-coord-map을 이용해서 이 frame에 알맞은 좌표 변환 함수를 얻어내고, start-segment 같은 고르개로 얻어낸 벡터 (이것은 단위 벡터이다.)를 넘겨서 좌표 변환을 한 다음 선을 그려준다. 이 과정을 반복하면 주어진 선분 목록을 그리는 페인터를 만들 수 있다.
연습문제 2.48
한 평면 위의 방향 잡힌 선분은 벡터 쌍으로 나타낼 수 있다. 하나는 원점에서 선분의 시작점에 이르는 벡터이고, 다른 하나는 원점에서 선분의 끝점에 이르는 벡터다. 연습문제 2.46에 나온 벡터 표현을 써서 선분을 표현하라. 선분 짜맞추개는 make-segment고, 그 고르개는 start-segment, end-segment다.
(define (make-segment start-vector end-vector)
(cons start-vector end-vector))
(define (start-segment segment)
(car segment))
(define (end-segment segment)
(cdr segment))
연습문제 2.49
segments->painter를 써서, 다음과 같은 기본 페인터를 정의하라.
a. 그림틀의 테두리를 그려주는 페인터
(require (planet "sicp.ss" ("soegaard" "sicp.plt" 1 1)))
(paint (segments->painter
(list
(make-segment (make-vect 0 0)
(make-vect 0 1))
(make-segment (make-vect 0 0.01)
(make-vect 1 0.01))
(make-segment (make-vect 0.99 0)
(make-vect 0.99 1))
(make-segment (make-vect 0 0.99)
(make-vect 1 0.99)))))
0.99를 1로 바꾸거나 0.01을 0으로 바꾸면 선이 안 나타난다. 아무래도 미묘한 차이로 경계를 벗어나서 클리핑 되는 것 같다.

b. 그림틀에서 마주보는 꼭짓점을 서로 연결하여 'X'를 그리는 페인터
(require (planet "sicp.ss" ("soegaard" "sicp.plt" 1 1)))
(paint (segments->painter
(list
(make-segment (make-vect 0 0)
(make-vect 1 1))
(make-segment (make-vect 1 0)
(make-vect 0 1)))))

c. 그림틀의 모서리 가운데 점 네 개를 연결하여 다이아몬드 꼴을 그리는 페인터
(require (planet "sicp.ss" ("soegaard" "sicp.plt" 1 1)))
(paint (segments->painter
(list
(make-segment (make-vect 0.5 0)
(make-vect 1 0.5))
(make-segment (make-vect 1 0.5)
(make-vect 0.5 1))
(make-segment (make-vect 0.5 1)
(make-vect 0 0.5))
(make-segment (make-vect 0 0.5)
(make-vect 0.5 0)))))

d. wave 페인터
이것은 노가다일 뿐 매우 귀찮으므로 하지 말자 (...)
페인터를 변환해서 엮어 쓰는 방법
연습문제 2.50
페인터를 수평으로 뒤집어 변환하는 flip-horiz 프로시저를 정의하라. 페인터를 시계 반대 방향으로 180도, 270도 돌리는 프로시저도 정의해 보라.
(require (planet "sicp.ss" ("soegaard" "sicp.plt" 1 1)))
(define (transform-painter painter origin corner1 corner2)
(lambda (frame)
(let ((m (frame-coord-map frame)))
(let ((new-origin (m origin)))
(painter
(make-frame new-origin
(vector-sub (m corner1) new-origin)
(vector-sub (m corner2) new-origin)))))))
(define (flip-horiz painter)
(transform-painter painter (make-vect 1 0)
(make-vect 0 0)
(make-vect 1 1)))
(paint (flip-horiz einstein))

(define (rotate180 painter)
(transform-painter painter
(make-vect 1 1)
(make-vect 0 1)
(make-vect 1 0)))
(paint (rotate180 einstein))

(define (rotate270 painter)
(transform-painter painter
(make-vect 1 0)
(make-vect 1 1)
(make-vect 0 0)))
(paint (rotate270 einstein))

연습문제 2.51
페인터 연산 below를 정의하라. below는 페인터 두 개를 인자로 받아서, 첫 번째 페인터는 틀 아래쪽에, 두 번째 페인터는 틀 위쪽에 그림을 그리도록 합쳐진 페인터를 내놓는다. below 프로시저를 두 가지 방법으로 정의해 보라. 하나는 위에서 정의한 beside 프로시저와 비슷하게, 다른 하나는 beside와 돌리는 연산을 써서 정의해 보라.
연습문제 2.52
설계의 견고함을 확인하는 변형 문제인데 지금까지 한 정도면 충분할 것 같은데.. 시간 나면 하자.
(define (flipped-pairs painter)
(let ((painter2 (beside painter (flip-vert painter))))
(below painter2 painter2)))
(define wave4 (flipped-pairs einstein))

(define (right-split painter n)
(if (= n 0)
painter
(let ((smaller (right-split painter (- n 1))))
(beside painter (below smaller smaller)))))

연습문제 2.44
corner-split 프로시저에서 쓰는 up-split 프로시저를 정의하라. 이 프로시저는 right-split과 비슷하지만, below와 beside가 하던 일을 서로 뒤바꾼다는 게 다르다.
(define (corner-split painter n)
(if (= n 0)
painter
(let ((up (up-split painter (- n 1)))
(right (right-split painter (- n 1))))
(let ((top-left (beside up up))
(bottom-right (below right right))
(corner (corner-split painter (- n 1))))
(beside (below painter top-left)
(below bottom-right corner))))))
(define (up-split painter n)
(if (= n 0)
painter
(let ((smaller (up-split painter (- n 1))))
(below painter (beside smaller smaller)))))

(define (square-limit painter n)
(let ((quarter (corner-split painter n)))
(let ((half (beside (flip-horiz quarter) quarter)))
(below (flip-vert half) half))))

(define (flipped-pairs painter)
(let ((combine4 (square-of-four identity flip-vert
identity flip-vert)))
(combine4 painter)))
(define (square-limit painter n)
(let ((combine4 (square-of-four flip-horiz identity
rotate180 flip-vert)))
(combine4 (corner-split painter n))))
연습문제 2.45
right-split과 up-split을 이보다 더 쓰임새가 넓은 split 연산의 인스턴스로 정의할 수 있다. 두 프로시저를 다음과 같이 정의할 수 있도록 split 프로시저를 짜라.
(define right-split (split beside below))
(define up-split (split below beside))
painter와 n을 매개변수로 하는 함수를 만들어 반환하자.
(define (split p1 p2)
(define (combine painter n)
(if (= n 0)
painter
(let ((smaller (combine painter (- n 1))))
(p1 painter (p2 smaller smaller)))))
combine)

그림틀
(define (frame-coord-map frame)
(lambda (v)
(add-vect
(origin-frame frame)
(add-vect (scale-vect (xcor-vect v)
(edge1-frame frame))
(scale-vect (ycor-vect v)
(edge2-frame frame))))))
연습문제 2.46
원점에서 한 점에 이르는 이차원 벡터 v는 x, y 좌표의 쌍으로 나타낸다. 벡터를 짜맞추는 연산 make-vect와 벡터에서 좌표를 골라내는 연산 xcor-vect, ycor-vect를 정의하여, 요약된 벡터를 구현하라. 이 짜맞추개와 고르개를 써서 벡터의 덧셈, 뺄셈, 스칼라 곱셈 연산을 다음과 같이 처리하는 add-vect, sub-vect, scale-vect 프로시저를 구현하라.
(define (make-vect x y)
(cons x y))
(define (xcor-vect v)
(car v))
(define (ycor-vect v)
(cdr v))
(define (add-vect v1 v2)
(make-vect (+ (xcor-vect v1) (xcor-vect v2))
(+ (ycor-vect v1) (ycor-vect v2))))
(define (sub-vect v1 v2)
(make-vect (- (xcor-vect v1) (xcor-vect v2))
(- (ycor-vect v1) (ycor-vect v2))))
(define (scale-vect s v)
(make-vect (* s (xcor-vect v))
(* s (ycor-vect v))))
연습문제 2.47
그림틀 짜맞추개 make-frame은 아래 두 가지 방법으로 구현할 수 있다.
(define (make-frame origin edge1 edge2)
(list origin edge1 edge2))
(define (make-frame origin edge1 edge2)
(cons origin (cons edge1 edge2)))
이 구현을 마무리 짓기 위하여 두 방법에 알맞은 고르개 연산들을 정의해보라.
(origin-frame, edge1-frame, edge2-frame)
1번째 방법
(define (origin-frame frame)
(first frame))
(define (edge1-frame frame)
(second frame))
(define (edge2-frame frame)
(third frame))
2번째 방법
(define (origin-frame frame)
(car frame))
(define (edge1-frame frame)
(car (cdr frame)))
(define (edge2-frame frame)
(cdr (cdr frame)))
페인터
(define (segments->painter segment-list)
(lambda (frame)
(for-each
(lambda (segment)
(draw-line
((frame-coord-map frame) (start-segment segment))
((frame-coord-map frame) (end-segment segment))))
segment-lits)))
frame-coord-map을 이용해서 이 frame에 알맞은 좌표 변환 함수를 얻어내고, start-segment 같은 고르개로 얻어낸 벡터 (이것은 단위 벡터이다.)를 넘겨서 좌표 변환을 한 다음 선을 그려준다. 이 과정을 반복하면 주어진 선분 목록을 그리는 페인터를 만들 수 있다.
연습문제 2.48
한 평면 위의 방향 잡힌 선분은 벡터 쌍으로 나타낼 수 있다. 하나는 원점에서 선분의 시작점에 이르는 벡터이고, 다른 하나는 원점에서 선분의 끝점에 이르는 벡터다. 연습문제 2.46에 나온 벡터 표현을 써서 선분을 표현하라. 선분 짜맞추개는 make-segment고, 그 고르개는 start-segment, end-segment다.
(define (make-segment start-vector end-vector)
(cons start-vector end-vector))
(define (start-segment segment)
(car segment))
(define (end-segment segment)
(cdr segment))
연습문제 2.49
segments->painter를 써서, 다음과 같은 기본 페인터를 정의하라.
a. 그림틀의 테두리를 그려주는 페인터
(require (planet "sicp.ss" ("soegaard" "sicp.plt" 1 1)))
(paint (segments->painter
(list
(make-segment (make-vect 0 0)
(make-vect 0 1))
(make-segment (make-vect 0 0.01)
(make-vect 1 0.01))
(make-segment (make-vect 0.99 0)
(make-vect 0.99 1))
(make-segment (make-vect 0 0.99)
(make-vect 1 0.99)))))
0.99를 1로 바꾸거나 0.01을 0으로 바꾸면 선이 안 나타난다. 아무래도 미묘한 차이로 경계를 벗어나서 클리핑 되는 것 같다.

b. 그림틀에서 마주보는 꼭짓점을 서로 연결하여 'X'를 그리는 페인터
(require (planet "sicp.ss" ("soegaard" "sicp.plt" 1 1)))
(paint (segments->painter
(list
(make-segment (make-vect 0 0)
(make-vect 1 1))
(make-segment (make-vect 1 0)
(make-vect 0 1)))))

c. 그림틀의 모서리 가운데 점 네 개를 연결하여 다이아몬드 꼴을 그리는 페인터
(require (planet "sicp.ss" ("soegaard" "sicp.plt" 1 1)))
(paint (segments->painter
(list
(make-segment (make-vect 0.5 0)
(make-vect 1 0.5))
(make-segment (make-vect 1 0.5)
(make-vect 0.5 1))
(make-segment (make-vect 0.5 1)
(make-vect 0 0.5))
(make-segment (make-vect 0 0.5)
(make-vect 0.5 0)))))

d. wave 페인터
이것은 노가다일 뿐 매우 귀찮으므로 하지 말자 (...)
페인터를 변환해서 엮어 쓰는 방법
연습문제 2.50
페인터를 수평으로 뒤집어 변환하는 flip-horiz 프로시저를 정의하라. 페인터를 시계 반대 방향으로 180도, 270도 돌리는 프로시저도 정의해 보라.
(require (planet "sicp.ss" ("soegaard" "sicp.plt" 1 1)))
(define (transform-painter painter origin corner1 corner2)
(lambda (frame)
(let ((m (frame-coord-map frame)))
(let ((new-origin (m origin)))
(painter
(make-frame new-origin
(vector-sub (m corner1) new-origin)
(vector-sub (m corner2) new-origin)))))))
(define (flip-horiz painter)
(transform-painter painter (make-vect 1 0)
(make-vect 0 0)
(make-vect 1 1)))
(paint (flip-horiz einstein))

(define (rotate180 painter)
(transform-painter painter
(make-vect 1 1)
(make-vect 0 1)
(make-vect 1 0)))
(paint (rotate180 einstein))

(define (rotate270 painter)
(transform-painter painter
(make-vect 1 0)
(make-vect 1 1)
(make-vect 0 0)))
(paint (rotate270 einstein))

연습문제 2.51
페인터 연산 below를 정의하라. below는 페인터 두 개를 인자로 받아서, 첫 번째 페인터는 틀 아래쪽에, 두 번째 페인터는 틀 위쪽에 그림을 그리도록 합쳐진 페인터를 내놓는다. below 프로시저를 두 가지 방법으로 정의해 보라. 하나는 위에서 정의한 beside 프로시저와 비슷하게, 다른 하나는 beside와 돌리는 연산을 써서 정의해 보라.
연습문제 2.52
설계의 견고함을 확인하는 변형 문제인데 지금까지 한 정도면 충분할 것 같은데.. 시간 나면 하자.




덧글
TomCat 2008/01/02 13:32 # 답글
나 CAD 랩 있을 때 생각난다...
xeraph 2008/01/02 13:33 # 답글
돌리고 돌리고~ (..)
페리 2008/01/02 15:12 # 답글
중간에 뭔가 예술이네
페리 2008/01/02 15:12 # 답글
이런걸로 포스터 만들어도 되겠다
xeraph 2008/01/02 16:44 # 답글
ㅇㅇ 멋지지