Created
February 15, 2009 08:33
-
-
Save melborne/64646 to your computer and use it in GitHub Desktop.
SICP with Ruby
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require "schemed" | |
def deriv(exp, var) | |
case exp | |
when Numeric | |
0 | |
when Symbol, String | |
same_variable?(exp, var) ? 1 : 0 | |
when Sum | |
make_sum deriv(addend(exp), var), deriv(augend(exp), var) | |
when Product | |
m1 = make_product multiplier(exp), deriv(multiplicand(exp), var) | |
m2 = make_product deriv(multiplier(exp), var), multiplicand(exp) | |
make_sum(m1, m2) | |
when Exponentiation | |
e1 = make_product(exponent(exp), make_exponentiation(base(exp), exponent(exp)-1)) | |
e2 = deriv(base(exp), var) | |
make_product(e1, e2) | |
else | |
raise "unknown expression type -- DERIV #{exp.inspect}" | |
end | |
end | |
def same_variable?(exp, var) | |
exp == var ? true : false | |
end | |
class Sum | |
def self.===(x) | |
pair?(x) and car(x).equal? :+ | |
end | |
end | |
class Product | |
def self.===(x) | |
pair?(x) and car(x).equal? :* | |
end | |
end | |
class Exponentiation | |
def self.===(x) | |
pair?(x) and car(x).equal? :** | |
end | |
end | |
def make_sum(a1, a2) | |
if eql_number?(a1, 0) | |
a2 | |
elsif eql_number?(a2, 0) | |
a1 | |
elsif Numeric === a1 and Numeric === a2 | |
a1 + a2 | |
else | |
list :+, a1, a2 | |
end | |
end | |
def eql_number?(exp, num) | |
Numeric === exp and exp == num | |
end | |
def make_product(m1, m2) | |
if eql_number?(m1, 0) or eql_number?(m2, 0) | |
0 | |
elsif m1 == 1 | |
m2 | |
elsif m2 == 1 | |
m1 | |
elsif Numeric === m1 and Numeric === m2 | |
m1 * m2 | |
else | |
list :*, m1, m2 | |
end | |
end | |
def addend(s) | |
cadr s | |
end | |
def augend(s) | |
caddr s | |
end | |
def multiplier(p) | |
cadr p | |
end | |
def multiplicand(p) | |
caddr p | |
end | |
def base(e) | |
cadr e | |
end | |
def exponent(e) | |
caddr e | |
end | |
def make_exponentiation(e1, e2) | |
if e2 == 0 | |
1 | |
elsif e2 == 1 | |
e1 | |
else | |
list :**, e1, e2 | |
end | |
end | |
list_p deriv list(:+, :x, 3), :x | |
list_p deriv list(:*, :x, :y), :x | |
list_p deriv list(:*, list(:*, :x, :y), list(:+, :x, 3)), :x | |
list_p deriv list(:+, list(:*, :a, list(:**, :x, 2)), list(:*, :b, :x)), :x |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(define (p x) (display x)(newline)) | |
(define (deriv exp var) | |
(cond ((number? exp) 0) | |
((variable? exp) | |
(if (same_variable? exp var) 1 0)) | |
((sum? exp) | |
(make_sum (deriv (addend exp) var) | |
(deriv (augend exp) var))) | |
((product? exp) | |
(make_sum | |
(make_product (multiplier exp) | |
(deriv (multiplicand exp) var)) | |
(make_product (deriv (multiplier exp) var) | |
(multiplicand exp)))) | |
((exponentiation? exp) | |
(make_product | |
(make_product (exponent exp) | |
(make_exponentiation (base exp) | |
(- (exponent exp) 1))) | |
(deriv (base exp) var))) | |
(else | |
(error "unknown expression type -- DERIV" exp)))) | |
(define (variable? x) (symbol? x)) | |
(define (same_variable? v1 v2) | |
(and (variable? v1) (variable? v2) (eq? v1 v2))) | |
(define (make_sum a1 a2) | |
(cond ((=number? a1 0) a2) | |
((=number? a2 0) a1) | |
((and (number? a1) (number? a2)) (+ a1 a2)) | |
(else (list `+ a1 a2)))) | |
(define (=number? exp num) | |
(and (number? exp) (= exp num))) | |
(define (make_product m1 m2) | |
(cond ((or (=number? m1 0) (=number? m2 0)) 0) | |
((=number? m1 1) m2) | |
((=number? m2 1) m1) | |
((and (number? m1) (number? m2)) (* m1 m2)) | |
(else (list `* m1 m2)))) | |
(define (sum? x) | |
(and (pair? x) (eq? (car x) `+))) | |
(define (addend s) (cadr s)) | |
(define (augend s) (caddr s)) | |
(define (product? x) | |
(and (pair? x) (eq? (car x) `*))) | |
(define (multiplier p) (cadr p)) | |
(define (multiplicand p) (caddr p)) | |
(define (exponentiation? x) | |
(and (pair? x) (eq? (car x) `**))) | |
(define (base e) (cadr e)) | |
(define (exponent e) (caddr e)) | |
(define (make_exponentiation e1 e2) | |
(cond ((=number? e2 0) 1) | |
((=number? e2 1) e1) | |
(else (list `** e1 e2)))) | |
(p (deriv `(+ x 3) `x)) | |
(p (deriv `(* x y) `x)) | |
(p (deriv `(* (* x y) (+ x 3)) `x)) | |
(p (deriv `(+ (* a (** x 2)) (* b x)) `x)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require "transform" | |
def paint_wave(frame) | |
wave_shape(frame).call(frame) | |
end | |
def paint_wave4(frame) | |
flipped_pairs(wave_shape(frame)).call(frame) | |
end | |
def paint_diamond8(frame) | |
half = flipped_pairs(diamond_shape(frame)) | |
below(half, half).call(frame) | |
end | |
def paint_wave_recur(frame, n=3) | |
square_limit(wave_shape(frame), n).call(frame) | |
end | |
def paint_diamond_recur(frame, n=3) | |
square_limit(diamond_shape(frame), n).call(frame) | |
end | |
def paint_frame(frame) | |
frame_shape(frame).call(frame) | |
end | |
def paint_wave4_with_frame(frame) | |
paint_wave4(frame) | |
paint_frame(frame) | |
end | |
def paint_x(frame) | |
x_shape(frame).call(frame) | |
end | |
def paint_star(frame) | |
star_shape(frame).call(frame) | |
end | |
def paint_star_recur(frame, n=3) | |
square_limit(star_shape(frame), n).call(frame) | |
end | |
if $0 == __FILE__ | |
def draw_line(s1, s2) | |
p s1 + s2 | |
end | |
frame = make_frame(make_vect(0, 0), make_vect(0, 1), make_vect(1, 0)) | |
paint_wave4(frame) | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(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)))))) | |
(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_list))) | |
(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)))) | |
(define (make_frame origin edge1 edge2) | |
(list origin edge1 edge2)) | |
(define (origin_frame frame) | |
(car frame)) | |
(define (edge1_frame frame) | |
(cadr frame)) | |
(define (edge2_frame frame) | |
(cadr (cdr frame))) | |
(define (make_segment x1 y1 x2 y2) | |
(cons (make_vect x1 y1) (make_vect x2 y2))) | |
(define (start_segment segment) | |
(car segment)) | |
(define (end_segment segment) | |
(cdr segment)) | |
(define normal_frame (make_frame (make_vect 0 0) (make_vect 1 0) (make_vect 0 1))) | |
(define (draw_line s1 s2) | |
(display s1) | |
(display s2) | |
(newline)) | |
(define (frame_painter frame) | |
((segments->painter | |
(list (make_segment 0 0 0 1) | |
(make_segment 0 1 1 1) | |
(make_segment 1 1 1 0) | |
(make_segment 1 0 0 0))) | |
frame)) | |
(define (x_painter frame) | |
((segments->painter | |
(list (make_segment 0 0 1 1) | |
(make_segment 0 1 1 0))) | |
frame)) | |
(define (diamond_painter frame) | |
((segments->painter | |
(list (make_segment 0 0.5 0.5 1) | |
(make_segment 0.5 1 1 0.5) | |
(make_segment 1 0.5 0.5 0) | |
(make_segment 0.5 0 0 0.5))) | |
frame)) | |
(define (wave frame) | |
((segments->painter | |
(list (make_segment 0.3 0 0.4 0.5) | |
(make_segment 0.4 0.5 0 0.6) | |
(make_segment 0 0.8 0.2 0.7) | |
(make_segment 0.2 0.7 0.4 0.7) | |
(make_segment 0.4 0.7 0.3 0.8) | |
(make_segment 0.3 0.8 0.4 1) | |
(make_segment 0.6 1 0.7 0.8) | |
(make_segment 0.7 0.8 0.6 0.7) | |
(make_segment 0.6 0.7 0.8 0.7) | |
(make_segment 0.8 0.7 1 0.4) | |
(make_segment 1 0.3 0.6 0.5) | |
(make_segment 0.6 0.5 0.7 0) | |
(make_segment 0.6 0 0.5 0.2) | |
(make_segment 0.5 0.2 0.4 0))) | |
frame)) | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require "painter" | |
require "transform" | |
Shoes.app :width => 400, :height => 420 do | |
@h = { 'Wave' => :paint_wave, | |
'Wave 4' => :paint_wave4, | |
'Wave Recursive' => :paint_wave_recur, | |
'Diamond 8' => :paint_diamond8, | |
'Diamond Recursive' => :paint_diamond_recur, | |
'Star' => :paint_star, | |
'Star Recursive' => :paint_star_recur, | |
'X' => :paint_x, | |
'Frame' => :paint_frame, | |
'Wave 4 in Frame' => :paint_wave4_with_frame } | |
frame = make_frame(make_vect(width/2-150, height/2+120), make_vect(300, 0), make_vect(0, -300)) | |
@slots = [] | |
background firebrick | |
flow do | |
list_box :items => ["Wave", "Wave 4", "Wave Recursive", "Diamond 8", "Diamond Recursive", "Star", "Star Recursive", "X", "Frame", "Wave 4 in Frame"], | |
:width => 200, | |
:choose => "wave" do |list| | |
@slots << stack { send(@h[list.text], frame) } | |
end | |
button "clear" do @slots.each { |s| s.clear} end | |
end | |
end | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def cons(a, b=nil) | |
[a, b] | |
end | |
def car(items) | |
case items | |
when Array | |
items[0] | |
else | |
raise "bad argument type" | |
end | |
end | |
def cdr(items) | |
case items | |
when Array | |
items[1] | |
else | |
raise "bad argument type" | |
end | |
end | |
def cadr(items) | |
case items | |
when Array | |
items[1][0] | |
else | |
raise "bad argument type" | |
end | |
end | |
def caddr(items) | |
case items | |
when Array | |
items[1][1][0] | |
else | |
raise "bad argument type" | |
end | |
end | |
def list(*i) | |
if i.empty? | |
nil | |
else | |
cons i.shift, list(*i) | |
end | |
end | |
def list_ref(items, n) | |
if n == 0 | |
car items | |
else | |
list_ref(cdr(items), n-1) | |
end | |
end | |
def length(items) | |
if items.nil? | |
0 | |
else | |
1 + length(cdr items) | |
end | |
end | |
def append(list1, list2) | |
if list1.nil? | |
list2 | |
else | |
cons car(list1), append(cdr(list1), list2) | |
end | |
end | |
def map(proc, items) | |
if items.nil? | |
nil | |
else | |
cons proc.call(car items), map(proc, cdr(items)) | |
end | |
end | |
def scale_list(items) | |
map(lambda { |x| x**2 }, items) | |
end | |
def pair?(items) | |
case items | |
when Array | |
true | |
else | |
false | |
end | |
end | |
def count_leaves(x) | |
case | |
when x.nil? then 0 | |
when !pair?(x) then 1 | |
else | |
count_leaves(car x) + count_leaves(cdr x) | |
end | |
end | |
def scale_tree(tree, factor) | |
case | |
when tree.nil? then nil | |
when !pair?(tree) then tree * factor | |
else | |
cons scale_tree(car(tree), factor), scale_tree(cdr(tree), factor) | |
end | |
end | |
l = list(1, (list 2, (list 3, 4), 5), (list 6, 7)) | |
scale_tree l, 10 | |
class List < Array | |
def list_ref(n) | |
self[n] | |
end | |
def append(list) | |
self + list | |
end | |
def last_pair | |
self[-1] | |
end | |
def scale_list(n) | |
self.inject([]) { |arr, e| arr << e * n } | |
end | |
def map | |
self.inject([]) { |arr, e| arr << yield(e) } | |
end | |
def count_leaves | |
self.inject(0) do |len, e| | |
case e | |
when List | |
len + e.count_leaves | |
else | |
len + 1 | |
end | |
end | |
end | |
def map_tree | |
self.inject([]) do |arr, e| | |
case e | |
when List | |
arr << e.map_tree{ |x| yield(x) } | |
else | |
arr << yield(e) | |
end | |
end | |
end | |
end | |
def list_p(list) | |
case list | |
when Array | |
puts _p(list).to_s.gsub(/\[/, "(").gsub(/\]/, ")").gsub(/[\:\"\,]/, "") | |
else | |
puts list | |
end | |
end | |
def _p(list) | |
_car = car list | |
_cdr = cdr list | |
case _car | |
when Array | |
if _cdr.nil? | |
[_p(_car)] | |
else | |
[_p(_car)] + _p(_cdr) | |
end | |
else | |
if _cdr.nil? | |
[_car] | |
else | |
(_p(_cdr)).unshift _car | |
end | |
end | |
end | |
def accumulate(op, initial, sequence) | |
if sequence.nil? | |
initial | |
else | |
send(op, car(sequence), (accumulate(op, initial, cdr(sequence)))) | |
end | |
end | |
def prime?(n) | |
2.upto(n-1) do |i| | |
return false if n.modulo(i).zero? | |
end | |
true | |
end | |
def enumerate_interval(low, high) | |
if low > high | |
nil | |
else | |
cons low, enumerate_interval(low+1, high) | |
end | |
end | |
def filter(predicate, sequence) | |
case | |
when sequence.nil? then nil | |
when predicate.call(car sequence) | |
cons car(sequence), filter(predicate, cdr(sequence)) | |
else | |
filter(predicate, cdr(sequence)) | |
end | |
end | |
def flatmap(proc, seq) | |
accumulate(:append, nil, map(proc, seq)) | |
end | |
def permutations(s) | |
mapping = lambda { |x| map(lambda { |p| cons x, p }, permutations(remove x, s)) } | |
if s.nil? | |
list nil | |
else | |
flatmap(mapping, s) | |
end | |
end | |
def remove(item, seq) | |
filter(lambda { |x| x != item }, seq) | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(define (enumerate_interval low high) | |
(if (> low high) `() | |
(cons low (enumerate_interval (+ low 1) high)))) | |
(define (accumulate op initial sequence) | |
(if (null? sequence) | |
initial | |
(op (car sequence) | |
(accumulate op initial (cdr sequence))))) | |
(define (filter predicate sequence) | |
(cond ((null? sequence) `()) | |
((predicate (car sequence)) | |
(cons (car sequence) | |
(filter predicate (cdr sequence)))) | |
(else (filter predicate (cdr sequence))))) | |
(define (smallest_divisor n) | |
(find_divisor n 2)) | |
(define (find_divisor n test_divisor) | |
(cond ((> (square test_divisor) n) n) | |
((divides? test_divisor n) test_divisor) | |
(else (find_divisor n (+ test_divisor 1))))) | |
(define (divides? a b) | |
(= (remainder b a) 0)) | |
(define (prime? n) | |
(= n (smallest_divisor n))) | |
(define (square x) | |
(* x x)) | |
(define (map proc items) | |
(if (null? items) `() | |
(cons (proc (car items)) (map proc (cdr items))))) | |
(define (flatmap proc seq) | |
(accumulate append `() (map proc seq))) | |
(define (p x) (display x) (newline)) | |
(define (permutations s) | |
(if (null? s) | |
(list `()) | |
(flatmap (lambda (x) | |
(map (lambda (p) (cons x p)) | |
(permutations (remove x s)))) | |
s))) | |
(define (remove item seq) | |
(filter (lambda (x) (not (= x item))) | |
seq)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require "schemed" | |
def frame_coord_map(frame) | |
lambda do |v| | |
scaled_edge1 = scale_vect(xcor_vect(v), edge1_frame(frame)) | |
scaled_edge2 = scale_vect(ycor_vect(v), edge2_frame(frame)) | |
add_vect(origin_frame(frame), add_vect(scaled_edge1, scaled_edge2)) | |
end | |
end | |
def make_vect(x, y) | |
cons x, y | |
end | |
def xcor_vect(v) | |
car v | |
end | |
def ycor_vect(v) | |
cdr v | |
end | |
def add_vect(v1, v2) | |
make_vect(xcor_vect(v1)+xcor_vect(v2), | |
ycor_vect(v1)+ycor_vect(v2)) | |
end | |
def sub_vect(v1, v2) | |
make_vect(xcor_vect(v1)-xcor_vect(v2), | |
ycor_vect(v1)-ycor_vect(v2)) | |
end | |
def scale_vect(s, v) | |
make_vect(s*xcor_vect(v), s*ycor_vect(v)) | |
end | |
def make_frame(origin, edge1, edge2) | |
list origin, edge1, edge2 | |
end | |
def origin_frame(frame) | |
car frame | |
end | |
def edge1_frame(frame) | |
cadr frame | |
end | |
def edge2_frame(frame) | |
cadr(cdr frame) | |
end | |
def segments_to_painter(segment_list) | |
lambda do |frame| | |
segment_list.each do |segment| | |
x1, y1 = frame_coord_map(frame).call(start_segment(segment)) | |
x2, y2 = frame_coord_map(frame).call(end_segment(segment)) | |
line x1, y1, x2, y2 | |
end | |
end | |
end | |
def make_segment(x1, y1, x2, y2) | |
cons make_vect(x1, y1), make_vect(x2, y2) | |
end | |
def start_segment(segment) | |
car segment | |
end | |
def end_segment(segment) | |
cdr segment | |
end | |
def draw_line(s1, s2) | |
p s1 + s2 | |
end | |
#shapes | |
def frame_shape(frame) | |
segments_to_painter(List[make_segment(0.0,0.0,0.0,1.0), | |
make_segment(0.0,1.0,1.0,1.0), | |
make_segment(1.0,1.0,1.0,0.0), | |
make_segment(1.0,0.0,0.0,0.0)]) | |
end | |
def x_shape(frame) | |
segments_to_painter(List[make_segment(0.0, 0.0, 1.0, 1.0), | |
make_segment(0.0, 1.0, 1.0, 0.0)]) | |
end | |
def diamond_shape(frame) | |
segments_to_painter(List[make_segment(0.0, 0.5, 0.5, 1.0), | |
make_segment(0.5, 1.0, 1.0, 0.5), | |
make_segment(1.0, 0.5, 0.5, 0.0), | |
make_segment(0.5, 0.0, 0.0, 0.5)]) | |
end | |
def wave_shape(frame) | |
segments_to_painter(List[make_segment(0.3, 0.0, 0.4, 0.5), | |
make_segment(0.4, 0.5, 0.0, 0.6), | |
make_segment(0.0, 0.8, 0.2, 0.7), | |
make_segment(0.2, 0.7, 0.4, 0.7), | |
make_segment(0.4, 0.7, 0.3, 0.8), | |
make_segment(0.3, 0.8, 0.4, 1.0), | |
make_segment(0.6, 1.0, 0.7, 0.8), | |
make_segment(0.7, 0.8, 0.6, 0.7), | |
make_segment(0.6, 0.7, 0.8, 0.7), | |
make_segment(0.8, 0.7, 1.0, 0.4), | |
make_segment(1.0, 0.3, 0.6, 0.5), | |
make_segment(0.6, 0.5, 0.7, 0.0), | |
make_segment(0.6, 0.0, 0.5, 0.2), | |
make_segment(0.5, 0.2, 0.4, 0.0)]) | |
end | |
def star_shape(frame) | |
segments_to_painter(List[make_segment(0.0, 0.25, 0.5, 1.0), | |
make_segment(0.5, 1.0, 1.0, 0.25), | |
make_segment(1.0, 0.25, 0.0, 0.25), | |
make_segment(0.0, 0.75, 1.0, 0.75), | |
make_segment(1.0, 0.75, 0.5, 0.0), | |
make_segment(0.5, 0.0, 0.0, 0.75)]) | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require "shape" | |
def transform_painter(painter, origin, corner1, corner2) | |
lambda do |frame| | |
m = frame_coord_map(frame) | |
new_origin = m.call(origin) | |
painter.call(make_frame(new_origin, | |
sub_vect(m.call(corner1), new_origin), | |
sub_vect(m.call(corner2), new_origin))) | |
end | |
end | |
def flip_vert(painter) | |
transform_painter(painter, make_vect(0.0, 1.0), | |
make_vect(1.0, 1.0), | |
make_vect(0.0, 0.0)) | |
end | |
def flip_horiz(painter) | |
transform_painter(painter, make_vect(1.0, 0.0), | |
make_vect(0.0, 0.0), | |
make_vect(1.0, 1.0)) | |
end | |
def shrink_to_upper_right(painter) | |
transform_painter(painter, make_vect(0.5, 0.5), | |
make_vect(1.0, 0.5), | |
make_vect(0.5, 1.0)) | |
end | |
def ratate90(painter) | |
transform_painter(painter, make_vect(1.0, 0.0), | |
make_vect(1.0, 1.0), | |
make_vect(0.0, 0.0)) | |
end | |
def ratate180(painter) | |
transform_painter(painter, make_vect(1.0, 1.0), | |
make_vect(0.0, 1.0), | |
make_vect(1.0, 0.0)) | |
end | |
def ratate270(painter) | |
transform_painter(painter, make_vect(0.0, 1.0), | |
make_vect(0.0, 0.0), | |
make_vect(1.0, 1.0)) | |
end | |
def suqash_inwards(painter) | |
transform_painter(painter, make_vect(0.0, 0.0), | |
make_vect(0.65, 0.35), | |
make_vect(0.35, 0.65)) | |
end | |
def beside(painter1, painter2) | |
split_point = make_vect(0.5, 0.0) | |
paint_left = transform_painter(painter1, make_vect(0.0, 0.0), | |
split_point, | |
make_vect(0.0, 1.0)) | |
paint_right = transform_painter(painter2, split_point, | |
make_vect(1.0, 0.0), | |
make_vect(0.5, 1.0)) | |
lambda do |frame| | |
paint_left.call(frame) | |
paint_right.call(frame) | |
end | |
end | |
def below(painter1, painter2) | |
split_point = make_vect(0.0, 0.5) | |
paint_bottom = transform_painter(painter1, make_vect(0.0, 0.0), | |
make_vect(1.0, 0.0), | |
split_point) | |
paint_top = transform_painter(painter2, split_point, | |
make_vect(1.0, 0.5), | |
make_vect(0.0, 1.0)) | |
lambda do |frame| | |
paint_bottom.call(frame) | |
paint_top.call(frame) | |
end | |
end | |
def flipped_pairs(painter) | |
painter2 = beside(painter, flip_vert(painter)) | |
below(painter2, painter2) | |
end | |
def right_split(painter, n) | |
if n == 0 | |
painter | |
else | |
smaller = right_split(painter, n-1) | |
beside(painter, below(smaller, smaller)) | |
end | |
end | |
def up_split(painter, n) | |
if n == 0 | |
painter | |
else | |
smaller = up_split(painter, n-1) | |
below painter, beside(smaller, smaller) | |
end | |
end | |
def corner_split(painter, n) | |
if n == 0 | |
painter | |
else | |
up = up_split(painter, n-1) | |
right = right_split(painter, n-1) | |
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) | |
end | |
end | |
def square_limit(painter, n) | |
quarter = corner_split(painter, n) | |
half = beside(flip_horiz(quarter), quarter) | |
below flip_vert(half), half | |
end | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(load "painter.scm") | |
(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 | |
(sub_vect (m corner1) new_origin) | |
(sub_vect (m corner2) new_origin))))))) | |
(define (flip_vert painter) | |
(transform_painter painter | |
(make_vect 0.0 1.0) | |
(make_vect 1.0 1.0) | |
(make_vect 0.0 0.0))) | |
(define (flip_horiz painter) | |
(transform_painter painter | |
(make_vect 1.0 0.0) | |
(make_vect 0.0 0.0) | |
(make_vect 1.0 1.0))) | |
(define (shrink_to_upper_right painter) | |
(transform_painter painter | |
(make_vect 0.5 0.5) | |
(make_vect 1.0 0.5) | |
(make_vect 0.5 1.0))) | |
(define (ratate90 painter) | |
(transform_painter painter | |
(make_vect 1.0 0.0) | |
(make_vect 1.0 1.0) | |
(make_vect 0.0 0.0))) | |
(define (ratate180 painter) | |
(transform_painter painter | |
(make_vect 1.0 1.0) | |
(make_vect 0.0 1.0) | |
(make_vect 1.0 0.0))) | |
(define (ratate270 painter) | |
(transform_painter painter | |
(make_vect 0.0 1.0) | |
(make_vect 0.0 0.0) | |
(make_vect 1.0 1.0))) | |
(define (suqash_inwards painter) | |
(transform_painter painter | |
(make_vect 0.0 0.0) | |
(make_vect 0.65 0.35) | |
(make_vect 0.35 0.65))) | |
(define (beside painter1 painter2) | |
(let ((split_point (make_vect 0.5 0.0))) | |
(let ((paint_left | |
(transform_painter painter1 | |
(make_vect 0.0 0.0) | |
split_point | |
(make_vect 0.0 1.0))) | |
(paint_right | |
(transform_painter painter2 | |
split_point | |
(make_vect 1.0 0.0) | |
(make_vect 0.5 1.0)))) | |
(lambda (frame) | |
(paint_left frame) | |
(paint_right frame))))) | |
(define (below painter1 painter2) | |
(let ((split_point (make_vect 0.0 0.5))) | |
(let ((paint_bottom | |
(transform_painter painter1 | |
(make_vect 0.0 0.0) | |
(make_vect 1.0 0.0) | |
split_point)) | |
(paint_top | |
(transform_painter painter2 | |
split_point | |
(make_vect 1.0 0.5) | |
(make_vect 0.0 1.0)))) | |
(lambda (frame) | |
(paint_bottom frame) | |
(paint_top frame))))) | |
(define (flipped_pairs painter) | |
(let ((painter2 (beside painter (flip_vert painter)))) | |
(below painter2 painter2))) | |
(define (right_split painter n) | |
(if (= n 0) | |
painter | |
(let ((smaller (right_split painter (- n 1)))) | |
(beside painter (below smaller smaller))))) | |
(define (up_split painter n) | |
(if (= n 0) | |
painter | |
(let ((smaller (up_split painter (- n 1)))) | |
(below painter (beside smaller smaller))))) | |
(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 (square_limit painter n) | |
(let ((quarter (corner_split painter n))) | |
(let ((half (beside (flip_horiz quarter) quarter))) | |
(below (flip_vert half) half)))) | |
(define wave4 (flipped_pairs wave)) | |
(define wave_rec (square_limit wave 2)) | |
(wave4 normal_frame) | |
(wave_rec normal_frame) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment