;;; fichier tortue-toward.rkt ;;; pour le livre PCPS : "Premiers Cours de Programmation avec Scheme" (Ellipses ed, 2010) ;;; Exercice 12.15.18 #lang racket (require graphics/graphics) (provide new-tortue TORTUES repeat) (open-graphics) ; initialisation de la librairie (define size 200) ; la demi-largeur de la fenetre graphique (define view (open-viewport "Turtlegraphics" (* 2 size) (* 2 size))) (define tr-segment (draw-line view)) ; un traceur de segment dans twin (define tr-pixel (draw-pixel view)) ; un traceur de point dans twin (define (turtlepoint->posn x y) ; changement de repere turtle -> graphics (make-posn (+ size x) (- size y))) (define (real-mod360 x) ; x reel modulo 360 (- x (* 360 (floor (/ x 360.0))))) (define pi/180 (/ pi 180)) (define 180/pi (/ 180 pi)) (define TORTUES '()) ; la liste de toutes les tortues (define (new-tortue) (let ((xcor 0) (ycor 0) (cap 0) (crayon? #t)) ; origine, cap Nord, crayon baisse (define (fpos! x y) (when crayon? (tr-segment (turtlepoint->posn xcor ycor) (turtlepoint->posn x y))) (set! xcor x) (set! ycor y)) (define (fcap! a) (set! cap (real-mod360 a))) ; pour que 0 <= cap < 360 (define (this sel . Largs) (case sel ((av) (let ((a (* cap pi/180)) (d (car Largs))) ; avance (fpos! (+ xcor (* d (sin a))) (+ ycor (* d (cos a)))))) ((re) (this 'av (- (car Largs)))) ; recule ((ga) (fcap! (- cap (car Largs)))) ; tourne a gauche ((dr) (this 'ga (- (car Largs)))) ; tourne a droite ((pos) (list xcor ycor)) ; donne ta position ((cap) cap) ; donne ton cap ((point) (tr-pixel (turtlepoint->posn xcor ycor))) ; trace un point ((lc) (set! crayon? #f)) ; leve ton crayon ((bc) (set! crayon? #t)) ; baisse ton crayon ((fpos) (apply fpos! Largs)) ; change ta position ((fcap) (apply fcap! Largs)) ; change ton cap ((init) ((clear-viewport view)) (this 'lc) (apply fpos! (car Largs)) (this 'bc) (fcap! (cadr Largs))) ((toward) ; force la tortue a regarder vers le point L = (x y) <-- (car Largs) (let ((x (caar Largs)) (y (cadar Largs)) (pos (this 'pos))) (let ((xp (car pos)) (yp (cadr pos))) (let ((dx (- xp x)) (dy (- yp y)) (angle '?)) (if (= dx 0) (set! angle (if (> dy 0) -90 90)) (set! angle (* (atan (/ dy dx)) 180/pi))) (set! angle (- angle)) (when (> dx 0) (set! angle (+ angle 180))) ; atan defini entre 0 et 180 (this 'fcap (+ angle 90)))))) (else (error "Message tortue inconnu" sel)))) (set! TORTUES (cons this TORTUES)) this)) (define-syntax repeat (syntax-rules () ((repeat n e1 e2 ...) (do ((i 0 (+ i 1))) ((= i n) (void)) e1 e2 ...)))) (define (distance t1 t2) (apply + (map (compose abs -) (t1 'pos) (t2 'pos)))) ; |x1 - x2| + |y1 - y2| est une distance possible ;;; L'exemple qui suit ne devrait pas faire partie de ce module... ;;; Placez-le dans un fichier "poursuite.rkt" qui devra requerir le module "tortue-toward.rkt" ! (define (poursuite) (let ((lapin (new-tortue)) (chien (new-tortue))) (lapin 'init '(-200 190) 90) ; en haut à gauche (chien 'lc) (chien 'fpos 198 -200) (chien 'bc) (do () ((< (distance lapin chien) 4) 'fini) (lapin 'av 1) (chien 'toward (lapin 'pos)) (chien 'av 2)))) (poursuite)