;; A Frog is a structure that has two states: live or dead ;; A Frog has 4 behaviors: ;; getPos: --> posn, returns the position of the frog ;; getColor: --> symbol, live Frogs are green, dead frogs are red ;; moveBy: posn --> posn, moves a live frog by the given amt. ;; Dead frogs don't move. The final position is returned. ;; getHit: --> Frog, live frogs become dead. Dead frogs stay dead. The frog is returned. (define-struct Frog (getPos getColor moveBy getHit)) ;; frogFactory: posn -->Frog ;; Factory to create a live frog at a given position. (define (frogFactory a-pos) (local [(define pos a-pos) ;; The position of the frog ;;Abstract state of a Frog. Implements the following state-dependent behaviors: ;; getColor: --> symbol returns the color of the frog ;; moveBy: posn --> posn moves the frog, if possible, by the given amount. The final position is returned. ;; getHit: --> Frog mutates the frog as if it got hit. (define-struct FrogState (getColor moveBy getHit)) (define deadState ;; The dead state of the frog (make-FrogState (lambda () ;; getColor 'red) (lambda (delta) ;; moveBy pos) (lambda () ;; getHit this))) (define liveState ;; The live state of the frog (make-FrogState (lambda () ;; getColor 'green) (lambda (delta) ;; moveBy (begin (set! pos (make-posn (+ (posn-x pos) (posn-x delta)) (+ (posn-y pos) (posn-y delta)))) pos)) (lambda () ;; getHit (begin (set! state deadState) this)))) (define state liveState) ;; the current state of the frog (define this ;; this allows the frog to reference itself (make-Frog (lambda () ;; getPos doesn't need to be delegated pos) (lambda () ;; getColor delegated to the state ((FrogState-getColor state))) (lambda (delta) ;; moveBy delegated to the state ((FrogState-moveBy state) delta)) (lambda () ;; getHit delegated to the state ((FrogState-getHit state)))))] this)) "Live frog:" (define f1 (frogFactory (make-posn 100 200))) ((Frog-getPos f1)) ((Frog-getColor f1)) "moveBy (300, 500):" ((Frog-moveBy f1) (make-posn 300 500)) "moveBy (200, -200):" ((Frog-moveBy f1) (make-posn 200 -200)) "getHit then getColor:" ((Frog-getHit f1)) ((Frog-getColor f1)) "moveBy (100, 100):" ((Frog-moveBy f1) (make-posn 100 100)) "getHit then getColor:" ((Frog-getColor ((Frog-getHit f1)))) "moveBy (100, 100):" ((Frog-moveBy f1) (make-posn 100 100)) "Make another live frog:" (define f2 (frogFactory (make-posn 100 200))) ((Frog-getPos f2)) ((Frog-getColor f2)) "moveBy (50, 20):" ((Frog-moveBy f2) (make-posn 300 500)) "moveBy (100, 0):" ((Frog-moveBy f2) (make-posn 100 0)) "getHit then getColor:" ((Frog-getHit f2)) ((Frog-getColor f2)) "moveBy (10, 10):" ((Frog-moveBy f2) (make-posn 10 10)) "getHit then getColor:" ((Frog-getColor ((Frog-getHit f2)))) "moveBy (10, 10):" ((Frog-moveBy f2) (make-posn 100 100))