#lang scheme (require mzlib/math (only-in deinprogramm/image rectangle line overlay image-color? image image-color) (only-in lang/private/imageeq image?) deinprogramm/contract/contract-syntax) (provide set-color turn draw move run sequence turtle image image-color) ; used to convert angles (define pi/180 (/ pi 180)) ; convert angle value ; (: grad->rad (number -> number)) (define grad->rad (lambda (grad) (* pi/180 grad))) (define turtle (contract (predicate (lambda (x) (and (vector? x) (= (vector-length x) 8) (number? (vector-ref x 0)) (number? (vector-ref x 1)) (number? (vector-ref x 2)) (number? (vector-ref x 3)) (number? (vector-ref x 4)) (image? (vector-ref x 5)) (image-color? (vector-ref x 6))))))) ; This function is only for internal use. ; (new-turtle-priv h w x y angle img color state) ; creates a new turtle with hight h, width w. ; The cursor is at position (x,y) and the view direction ; is defined by an angle value relative to the vector (1,0) . ; The two next componets represents the image and the ; color of the pen. The last component represents an abritary ; value, that allows to transport state with the turtle. (: new-turtle-priv (number number number number number image image-color %A -> turtle)) (define new-turtle-priv (lambda (h w x y angle img color state) (vector h w x y angle img color state))) ; (new-turtle h w color) ; creates a new turtle with the pen color color and sets the ; width of the image to w and the hight to h. ; The background of the image is gray and the position of the ; cursor is (0,0) and the view direction is (1,0). (: new-turtle (number number image-color -> turtle)) (define new-turtle (lambda (h w color) (let ((x (floor (/ w 2))) (y (floor (/ h 2)))) (new-turtle-priv h w x y 0 (rectangle w h "solid" "gray") color #f)))) ; (new-turtle-complex h w color bgcolor x y angle) ; creates a new turtle with the pen color color and sets the ; width of the image to w and the hight to h. ; The background of the image is bgcolor and the position of the ; cursor is (x,y) and the view direction is (1,0) * e^(- i angle). (: new-turtle (number number image-color image-color number number number -> turtle)) (define new-turtle-complex (lambda (h w color bgcolor x y angle) (new-turtle-priv h w x y angle (rectangle w h "solid" bgcolor) color #f))) ; For internal use only (: get-h (turtle -> number)) (define get-h (lambda (t) (vector-ref t 0))) (: get-w (turtle -> number)) (define get-w (lambda (t) (vector-ref t 1))) (: get-x (turtle -> number)) (define get-x (lambda (t) (vector-ref t 2))) (: get-y (turtle -> number)) (define get-y (lambda (t) (vector-ref t 3))) (: get-angle (turtle -> number)) (define get-angle (lambda (t) (vector-ref t 4))) (: get-iamge (turtle -> image)) (define get-image (lambda (t) (vector-ref t 5))) (: get-color (turtle -> image-color)) (define get-color (lambda (t) (vector-ref t 6))) (: get-state (turtle -> %A)) (define get-state (lambda (t) (vector-ref t 7))) ; (set-color color) ; returns a function of type turtle -> turtle. ; Use the result to change the color of the pen. (: set-color (image-color -> (turtle -> turtle))) (define set-color (lambda (color) (lambda (t) (let* ((h (get-h t)) (w (get-w t)) (x (get-x t)) (y (get-y t)) (angle (get-angle t)) (image (get-image t))) (new-turtle-priv h w x y angle image color #f))))) ; (turn angle) ; returns a function of type turtle -> turtle. ; Use the result to turn the view of the turtle (counter-clockwise). (: turn (number -> (turtle -> turtle))) (define turn (lambda (grad) (lambda (t) (let* ((h (get-h t)) (w (get-w t)) (x (get-x t)) (y (get-y t)) (angle (get-angle t)) (image (get-image t)) (color (get-color t)) (state (get-state t))) (new-turtle-priv h w x y (- angle grad) image color state))))) ; For internal use only ; (move-cursor turtle length) ; returns a new turtle where the cursor ; is moved length steps along the view vector. (: move-cursor (turtle number -> turtle)) (define move-cursor (lambda (t length) (let* ((h (get-h t)) (w (get-w t)) (x (get-x t)) (y (get-y t)) (angle (get-angle t)) (image (get-image t)) (color (get-color t)) (state (get-state t)) (newx (+ x (* length (cos (grad->rad angle))))) (newy (+ y (* length (sin (grad->rad angle)))))) (new-turtle-priv h w newx newy angle image color state)))) ; (draw length) ; returns a function of type turtle -> turtle. ; The result can be used to move the turtle and draw a line. (: draw (number -> (turtle -> turtle))) (define draw (lambda (length) (lambda (t) (let* ((h (get-h t)) (w (get-w t)) (x (get-x t)) (y (get-y t)) (angle (get-angle t)) (image (get-image t)) (color (get-color t)) (state (get-state t)) ; Compute new coordinats (newx (+ x (* length (cos (grad->rad angle))))) (newy (+ y (* length (sin (grad->rad angle)))))) (new-turtle-priv h w newx newy angle ; Compute new image (overlay image (line w h x y newx newy color) 0 0) color state))))) ; (move length) ; returns a function of type turtle -> turtle. ; The result can be used to move the turtle without drawing a line. (: move (number -> (turtle -> turtle))) (define move (lambda (length) (lambda (t) (move-cursor t length)))) ; runs a turtle function (: run ((turtle -> turtle) number number image-color -> image)) (define run (lambda (t->t h w color) (get-image (t->t (new-turtle h w color))))) ; ; runs a turtle function ; ; (: run* ((turtle -> turtle) -> turtle -> image)) ; (define run* ; (lambda (t->t h w color bgcolor x y angle) ; (get-image (t->t (new-turtle h w color bgcolor x y angle))))) ; This function is only for internal use. (define comp_priv_2 (lambda (f1 f2) (lambda (t) (f2 (f1 t))))) ; This function is only for internal use. (define comp_priv (lambda (l) (cond ((null? l) (error "sequence erwartet mind. ein Argument")) ((list? l) (let ((head (car l)) (tail (cdr l))) (if (null? tail) head (comp_priv_2 head (comp_priv tail)))))))) ; This function allows to do a list of ; turtle -> turtle ; functions into one new function, that do ; one action of the turtle, then later the rest. ; Define the type alias tip = turtle -> turtle. (define tip (contract (turtle -> turtle))) (: do (tip ... -> tip)) (define sequence (lambda l (comp_priv l)))