Please send questions to st10@humboldt.edu .

; NOTE -- remember, all bird images below show up as . in this text version!

; CS 131 - Week 4, Lab, 8 am

(require 2htdp/universe)
(require 2htdp/image)

;----------
; defining your own struct type: the basic syntax and semantics
;
; (define-struct <struct-name> (<charac1> <charac2> ... <charac2>)
; creates a new struct type named <struct-name>,
; and a number of new functions:
;   a constructor function, make-<struct-name>
;   accessor/selector functions
;      <struct-name>-<charac1>
;      <struct-name>-<charac2>
;      ...
;      <struct-name>-<characn>
;   a predicate function (to see if something is an instance
;      of that type)
;      <struct-name>?

; for example,

;(define-struct h-flier (image speed x y))

; I have a new struct type named h-flier that can be
;     used in other functions (and in function signatures)
; I have make-h-flier to create instances of h-flier
; ...and h-flier-image gets me an h-flier's image,
;        h-flier-speed gets me an h-flier's speed,
;        h-flier-x gets me an h-flier's x,
;        h-flier-y gets me an h-flier's y,
; ...and h-flier? can tell me if an expression is of type h-flier

; BUT!! a user can't tell the expected types of each struct
;    characteristic, nor what it is intended to mean,
;    JUST from the define-struct expression;

; we need some COMMENTS to FINISH the data definition
;    for a struct type!

; Here's the CLASS STANDARD for such a data definition for a struct:

;----------
(define-struct h-flier (image speed x y))

; an h-flier is a:
;    (make-h-flier image number number number)
; an h-flier has:
;    an image depicting it, 
;    a speed in pixels per tick,
;        if positive, it is pixels per tick going right,
;        if negative, it is pixels per tick going left
;    its current x-coordinate where its image is centered,
;    and its current y-coordinate where its image is centered

; the template for a function uses-h-flier that expects
;    an h-flier could be:
;
; (define (uses-h-flier an-h-flier)
;    (... (h-flier-image an-h-flier)
;         (h-flier-speed an-h-flier)
;         (h-flier-x an-h-flier)
;         (h-flier-y an-h-flier) ...)
; )

; the template for a function makes-h-flier that produces
;    an h-flier could be:
;    (notice that we put a ... for each expression the
;    contructor function expects...)
;
; (define (makes-h-flier ...)
;    (make-h-flier ... ... ... ...)
; )

(make-h-flier . 3 100 50)
(define FIRST-BIRD (make-h-flier . 3 100 50))

(h-flier-speed FIRST-BIRD)
(h-flier-image FIRST-BIRD)
(h-flier-x FIRST-BIRD)
(h-flier-y FIRST-BIRD)

(h-flier? FIRST-BIRD)
(h-flier? .)

;----------
; WHAT IF... big-bang's world type was an h-flier
;    instead of a number?

; SO: big-bang's on-draw function would expect
;   the name of a function that expects an h-flier and
;   produces a scene
;
; ...its on-tick function would expect the name
;   of a function that expects an h-flier, and produces
;   the h-flier that should result 1 tick later
;
; ...its on-key function would expect the name
;   of a function that expects an h-flier and a string
;   representing a keystroke, and would produce
;   the h-flier that should result from that keystroke
;  

;----------
; I'm going to start with the function to give to
;    big-bang's on-draw...

; signature: draw-h-flier: h-flier -> scene
; purpose: expects an h-flier, and produces a scene
;    showing that h-flier's image centered at
;    its x and y coordinates

(define WIDTH 300)
(define HEIGHT 200)
(define BACKDROP (empty-scene WIDTH HEIGHT))

; NOTE: REMEMBER, you write the check-expects BEFORE
;    writing the function body!
; AND: in this case, after writing the check-expects,
;    you can use the template for a function that expects an
;    h-flier, and paste its body in here, and then edit it
;    as suggested by your check-expects, being sure
;    that THIS function's parameter(s) are being used
;    appropriately in the result...!
; (we DID this in-class -- you are just seeing the final
;    result here...)

(define (draw-h-flier an-h-flier)
    (place-image (h-flier-image an-h-flier)
                 (h-flier-x an-h-flier)
                 (h-flier-y an-h-flier) 
                 BACKDROP)
)

; reminder:
; (define FIRST-BIRD (make-h-flier . 3 100 50))

(check-expect (draw-h-flier FIRST-BIRD)
              (place-image . 100 50 BACKDROP))

(check-expect (draw-h-flier
                 (make-h-flier (star 30 "solid" "purple")
                               -9 150 (/ HEIGHT 2)))
              (place-image
                 (star 30 "solid" "purple")
                 150 (/ HEIGHT 2)
                 BACKDROP))
(draw-h-flier FIRST-BIRD)
(draw-h-flier (make-h-flier (star 30 "solid" "purple")
                            -9 150 (/ HEIGHT 2)))

;(big-bang FIRST-BIRD (on-draw draw-h-flier))
;(big-bang  (make-h-flier (star 30 "solid" "purple")
;                               -9 150 (/ HEIGHT 2))
;           (on-draw draw-h-flier))

;----------
; big-bang's on-key function expects a function that
;    expects a world and a keystroke, and produces
;    the resulting world

;---------- 
; DATA DEFINITION:
; an AltButton is a string, "u" or "d"

; this named constant defines the delta, or amount of
;    altitude change, that should occur when "u" or "d"
;    is pressed

(define ALT-DELTA 5)

;----------
; signature: handle-hf-keys: h-flier AltButton -> h-flier
; purpose: expects an h-flier and an AltButton keystroke,
;    and produces a new h-flier whose y-coordinate (altitude) is:
;    *   ALT-DELTA smaller if "u" is pressed,
;    *   ALT-DELTA bigger if if "d" is pressed
;    *   unchanged if any other key is pressed
;    (because in a scene, y is lower in the scene as y gets bigger)

; again: remember, you are seeing the final result here --
;    in class, we followed the design recipe,
;    first developing the check-expects,
;    then using several templates to help develop the
;        function body...
;        (which? here, the template when a function has
;        several cases, and (for several of the cond expression
;        branch's actions) the template for a function
;        that produces an h-flier and (!) the template for
;        a function that produces an h-flier...

(define (handle-hf-keys an-h-flier a-key)
  (cond
    ; make the new h-flier's altitude higher when "u" is pushed
    ;    (requiring a smaller y...)
    
    [(string=? a-key "u") 
        (make-h-flier 
          (h-flier-image an-h-flier)
          (h-flier-speed an-h-flier)
          (h-flier-x an-h-flier)
          (- (h-flier-y an-h-flier) ALT-DELTA))]
    
    ; make the new h-flier's altitude lower when "d" is pushed
    ;     (requiring a larger y...)
    
    [(string=? a-key "d") 
        (make-h-flier 
          (h-flier-image an-h-flier)
          (h-flier-speed an-h-flier)
          (h-flier-x an-h-flier)
          (+ (h-flier-y an-h-flier) ALT-DELTA))]
    
    ; for any other keystroke, produce an unchanged h-flier
    
    [else an-h-flier]
  )
)

; (define FIRST-BIRD (make-h-flier . 3 100 50))

(check-expect (handle-hf-keys FIRST-BIRD "u")
              (make-h-flier .
                            3
                            100
                            45))
(check-expect (handle-hf-keys FIRST-BIRD "d")
              (make-h-flier .
                            3
                            100
                            55))
(check-expect (handle-hf-keys FIRST-BIRD "x")
              FIRST-BIRD)

;(big-bang FIRST-BIRD (on-draw draw-h-flier)
;                     (on-key handle-hf-keys))

;----------
; now: the function whose name can be given to big-bang's
;    on-tick expression

; signature: move-h-flier: h-flier -> h-flier
; purpose: expects an h-flier, and produces the
;   h-flier after the next clock tick, with
;   the new h-flier's x changed by the amount of
;   the speed

;(define (move-h-flier an-h-flier)
;  ...
;)

;---------------------------
; NEW STUFF STARTS HERE!!
;----------------------------

; what are the cases, here?

; an h-flier in the scene going to the right

;(define FIRST-BIRD (make-h-flier . 3 100 50))

(check-expect (move-h-flier FIRST-BIRD)
              (make-h-flier . 3 103 50))

; an h-flier in the scene going to the left

(define LEFT-SQR (make-h-flier (square 40 "solid" "green")
                               -7 80 90))
(check-expect (move-h-flier LEFT-SQR)
              (make-h-flier (square 40 "solid" "green")
                            -7
                            73 90))

; an h-flier outside the scene to the right going right

(define OUT-RIGHT (make-h-flier (circle 30 "solid" "red")
                                10 (+ 1 WIDTH) 50))

; in this case, after the next clock tick, we'd like
;     the speed reversed and its x to be the WIDTH

(check-expect (move-h-flier OUT-RIGHT)
              (make-h-flier (circle 30 "solid" "red")
                            -10 WIDTH 50))

; an h-flier outside the scene to the left going left

(define OUT-LEFT (make-h-flier (star 25 "outline" "pink")
                               -8 -10 60))
; in this case, after the next clock tick, we'd like
;    the speed reversed, and its x to be 0

(check-expect (move-h-flier OUT-LEFT)
              (make-h-flier (star 25 "outline" "pink")
                            8 0 60))
;-----
; AUXILIARY FUNCTION!!
; signature: in-scene?: h-flier -> boolean
; purpose: expects an h-flier, and produces whether its
;    x is in [0, WIDTH]

(define (in-scene? an-h-flier)
  (and     
     (>= (h-flier-x an-h-flier) 0)
     (<= (h-flier-x an-h-flier) WIDTH))
)

(check-expect (in-scene? FIRST-BIRD) true)
(check-expect (in-scene? OUT-LEFT) false)
(check-expect (in-scene? OUT-RIGHT) false)
(check-expect (in-scene? (make-h-flier (circle 10 "solid" "black")
                                      10 0 60))
              true)
(check-expect (in-scene? (make-h-flier (circle 10 "solid" "black")
                                      -10 WIDTH 75))
              true)


; note: 4 cases! So use the cond template with 4 [... ...]

(define (move-h-flier an-h-flier)
  (cond
    ; if the h-flier is in the scene
    
    [(in-scene? an-h-flier)
           (make-h-flier  (h-flier-image an-h-flier)
                          (h-flier-speed an-h-flier)
                          (+ (h-flier-x an-h-flier)
                             (h-flier-speed an-h-flier))
                          (h-flier-y an-h-flier))]
    
    ; if the h-flier is OUTSIDE the scene to the right going right
    
    [(and (> (h-flier-x an-h-flier) WIDTH) 
          (> (h-flier-speed an-h-flier) 0))
       (make-h-flier (h-flier-image an-h-flier)
                     (* -1 (h-flier-speed an-h-flier))
                     WIDTH
                     (h-flier-y an-h-flier))]
    
    ; if the h-flier is OUTSIDE the scene to the left going left

    [(and (< (h-flier-x an-h-flier) 0) 
          (< (h-flier-speed an-h-flier) 0))
       (make-h-flier (h-flier-image an-h-flier)
                     (* -1 (h-flier-speed an-h-flier))
                     0
                     (h-flier-y an-h-flier))]
  )
)

(big-bang FIRST-BIRD (on-draw draw-h-flier)
                     (on-key handle-hf-keys)
                     (on-tick move-h-flier))