Please send questions to st10@humboldt.edu .

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

; CS 131 - Week 6, Lecture 1

;------------
;------------
; list abbreviation

; to use this, NOTE that you NEED to:
; CHANGE LANGUAGE to "Beginning Student with List Abbreviations"

; the following is JUST an abbreviation for 
;    (cons thing (cons thing ... (cons thing empty)...))
; 
; (list thing thing ... thing)

; that is,
;
;(list expr expr ... expr)
; is the SAME as
; (cons expr (cons expr ... (cons expr empty)...))

; so, each of these pairs expresses the SAME list:
; (NOTE: in this language level, list results are also shown
;    using (list ...) notation) 

(cons 1 (cons 2 (cons 3 (cons 4 empty))))
(list 1 2 3 4)

(list "ABC")
(cons "ABC" empty)

; there is no abbreviation for the empty list -- it is still
;    simply empty

empty

; and you still get empty if you ask for the rest of a 1-element
;     list, whether you ask for it in list form or in cons form
;     (it is the same list, either way...)

(rest (list 1))
(rest (cons 1 empty))

; so...

(first (list 1))   ; produces 1
(rest (list 1))    ; produces empty

(first (list "a" 1 true)) ; produces "a"
(rest (list "a" 1 true))  ; produces (list 1 true)

; recall:
; (cons thing a-list)
; ...and the result is a new list whose first element
;    is thing, and the rest of the elements are the elements
;    in the list a-list

(cons "a" (list 1 2 3))       ; produces (list "a" 1 2 3)
(cons (list 1 2) (list 3 4))  ; produces (list (list 1 2) 3 4)

;----------
; if you'd like to take lists and simply concatenate or
;    append them -- so their elements become the elements
;    of a new list -- append is a useful operation;

(append (list 1 2) (list 3 4))  ; produces (list 1 2 3 4)

; produces (list 1 "a" "b" "c" 3)

(append (list 1) (list "a" "b" "c") (cons 3 empty))

; produces (list 1 2 3 4 5 6 7)

(append (cons 1 (list 2 3 4))(list 5 6 7))

;-----
; handling mouse events

; big-bang has a function on-mouse that expects
;    the name of a mouse-event-handling function,
;    and then when it detects a mouse event,
;    it will call that function for you;

; so: according to Racket 5.0's documentation (universe),
; a MouseEvent is one of the strings:
;    "button-down", "button-up", "drag", "move",
;    "enter", "leave"

; and, the function that will be called by big-bang
;    when a mouse event occurs is expected to have
;    a signature:
; signature: <name>: world-state number number MouseEvent
;                    -> world-state

;******************************************************************
; BEGINNING of OLD h-flier STUFF from WEEK 5 LABS

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

;-----------
; data definition for a list-of-number
; 
; a list-of-number is:
;   - empty, or
;   - (cons number list-of-number)

;------------
; template for a function uses-num-list that has a list-of-number
;    parameter num-list
;
; (define (uses-num-list ... num-list ...)
;    (cond
;       [(empty? num-list) ...]
;       [else (...(first num-list) ...
;                 (uses-num-list ... (rest num-list) ...) ...)]
;    )
; )

;-----------
; data definition for a list-of-string
; 
; a list-of-string is:
;   - empty, or
;   - (cons string list-of-string)

;------------
; template for a function uses-str-list that has a list-of-string
;    parameter string-list
;
; (define (uses-str-list ... string-list ...)
;    (cond
;       [(empty? string-list) ...]
;       [else (...(first string-list) ...
;                 (uses-string-list ... (rest string-list) ...) ...)]
;    )
; )

;---------------
;---------------
; pulling data definitions and functions from Week 4, Labs
; (edited)

;----------
(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:
;
; (define (makes-h-flier ...)
;    (make-h-flier ... ... ... ...)
; )

(make-h-flier (circle 30 "solid" "red")  3 100 50)
(define FIRST-BIRD (make-h-flier (circle 20 "solid" "yellow") 3 100 50))

;----------
; 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 (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 (circle 20 "solid" "yellow") 3 100 50))

(check-expect (draw-h-flier FIRST-BIRD)
              (place-image (circle 20 "solid" "yellow") 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))

;---------- 
; 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)

(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 (circle 20 "solid" "yellow") 3 100 50))

(check-expect (handle-hf-keys FIRST-BIRD "u")
              (make-h-flier (circle 20 "solid" "yellow")
                            3
                            100
                            45))
(check-expect (handle-hf-keys FIRST-BIRD "d")
              (make-h-flier (circle 20 "solid" "yellow")
                            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))

;----------
; 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 FIRST-BIRD (make-h-flier . 3 100 50))

(check-expect (move-h-flier FIRST-BIRD)
              (make-h-flier (circle 20 "solid" "yellow") 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)

(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))

;-------------------
;-------------------
; the examples for the 8 am WEEK 5 LAB resume HERE (NOW edited)

;----------
; data definition for a list-of-h-flier:
; a list-of-h-flier is:
;    - empty, or
;    - (cons h-flier list-of-h-flier)

;----------
; more-complete template for a function uses-h-fliers expecting a 
; list-of-h-flier parameter h-flier-list:
;    
; (define (uses-h-fliers ... h-flier-list ...)
;    (cond
;       [(empty? h-flier-list) ...]
;       [else (... (h-flier-image (first h-flier-list))
;                  (h-flier-speed (first h-flier-list))
;                  (h-flier-x (first h-flier-list))
;                  (h-flier-y (first h-flier-list)) ...)
;                  (uses-h-fliers ... (rest h-flier-list)...) ...)]
;    )
; )

;----------
; signature: draw-flier-list: list-of-h-flier: -> scene
; purpose: expects a list of h-fliers, and produces a scene
;    depicting all of them

(define (draw-flier-list h-flier-list)
    (cond
       [(empty? h-flier-list) BACKDROP]
       [else (place-image (h-flier-image (first h-flier-list))
                          (h-flier-x (first h-flier-list))
                          (h-flier-y (first h-flier-list))
                          (draw-flier-list (rest h-flier-list)))]
    )
)

(check-expect (draw-flier-list empty)
              BACKDROP)
              
; (define FIRST-BIRD (make-h-flier (circle 20 "solid" "yellow") 3 100 50))
(define SECOND-FLIER (make-h-flier (star 30 "solid" "red") -7 50 80))
(define THIRD-FLIER (make-h-flier (square 40 "solid" "purple") 
                                  10 120 120))
(define INITIAL-FLIERS (cons FIRST-BIRD (cons SECOND-FLIER 
                                              (cons THIRD-FLIER empty))))
(check-expect (draw-flier-list INITIAL-FLIERS)
              (place-image 
                 (h-flier-image FIRST-BIRD)
                 100 50
                 (draw-flier-list (cons SECOND-FLIER 
                                        (cons THIRD-FLIER empty)))))
(draw-flier-list INITIAL-FLIERS)

;----------
; signature: move-flier-list: list-of-h-flier -> list-of-h-flier
; purpose: expects a list of h-fliers,
;    and produces the list of h-fliers as they should be
;    after the next clock tick

(define (move-flier-list h-flier-list)
    (cond
       [(empty? h-flier-list) empty]
       [else (cons (move-h-flier (first h-flier-list))
                   (move-flier-list (rest h-flier-list)))]
    )
)

(check-expect (move-flier-list empty) empty)

;(define INITIAL-FLIERS (cons FIRST-BIRD (cons SECOND-FLIER 
;                                              (cons THIRD-FLIER empty))))

(check-expect (move-flier-list INITIAL-FLIERS)
              (cons (move-h-flier FIRST-BIRD)
                    (move-flier-list (rest INITIAL-FLIERS))))

;(big-bang INITIAL-FLIERS
;          (on-tick move-flier-list)
;          (on-draw draw-flier-list))

;----------
; signature: generate-dot-fliers: whole-number -> list-of-h-flier
; purpose: expects a desired number of dot fliers, and produces
;    a list of that many dot-shaped h-fliers (in random colors)

(define DOT-RADIUS 10)
(define MAX-SPEED 15)

(define (generate-dot-fliers num-fliers)
    (cond
       [(= num-fliers 0) empty]
       [else (cons (make-h-flier 
                     (circle DOT-RADIUS "solid"
                             (make-color (random 256)
                                         (random 256)
                                         (random 256)))
                     (random MAX-SPEED)
                     (random WIDTH)
                     (random HEIGHT))
                   (generate-dot-fliers (- num-fliers 1)))]
    )
)

(check-expect (generate-dot-fliers 0)
              empty)
(check-expect (length (generate-dot-fliers 10))
              10)

;----------
; signature: main: list-of-h-flier -> list-of-h-flier
; purpose: expects a desired initial list of h-fliers, and it calls
;    big-bang with that as its initial world state, and then
;    it produces the final list of h-fliers that big-bang produces
;    when it ends

;(define (main init-hflier-list)
;  (big-bang init-hflier-list
;           (on-tick move-flier-list)
;           (on-draw draw-flier-list))
;)

;(main INITIAL-FLIERS)
;(main (generate-dot-fliers 100))

; END of OLD h-flier STUFF from WEEK 5 LABS
;******************************************************************

;------------
;------------
; NEW STUFF for WEEK 6, LECTURE 1 resumes HERE

; so -- now let's add some mouse-event-handling to our
;    world consisting of a list-of-h-flier;

;-----------
; signature: handle-click: list-of-h-flier number number
;              MouseEvent -> list-of-h-flier
; purpose: expects a list of h-fliers, the x and y
;    coordinates where the mouse action occurred, and
;    a string representing the mouse event,
;    and IF the event is "button-down", 
;    it will add a new h-flier to the world,
;    centered at that x and y coordinate 
;    with random color and speed, and size DOT-RADIUS,
;    otherwise the list of h-fliers is unchanged

(define (handle-click h-flier-list mouse-x mouse-y
                      mouse-event)
  (cond
    [(string=? mouse-event "button-down") 
        (cons (make-h-flier 
                 (circle DOT-RADIUS
                    "solid"
                    (make-color (random 256) (random 256)
                                (random 256)))
                 (random MAX-SPEED)
                 mouse-x mouse-y)
              h-flier-list)]
    [else h-flier-list]
  )
)

(check-expect (handle-click INITIAL-FLIERS 50 50 "drag")
              INITIAL-FLIERS)

(check-expect (length (handle-click INITIAL-FLIERS 50 50 
                            "button-down"))
              4)
              ; that list of length 4 is something like:
              ; (cons (make-h-flier
              ;         (circle DOT-RADIUS "solid" <color>)
              ;         (random MAX-SPEED)
              ;         50 50) INITIAL-FLIERS)
              
;--------
; signature: main: list-of-h-flier -> list-of-h-flier
; purpose: expects a desired initial list of h-fliers, 
;    and it calls
;    big-bang with that as its initial world state, and then
;    it produces the final list of h-fliers that 
;    big-bang produces
;    when it ends

(define (main init-hflier-list)
  (big-bang init-hflier-list
           (on-tick move-flier-list)
           (on-draw draw-flier-list)
           (on-mouse handle-click))
)

(main INITIAL-FLIERS)
(main empty)

;--------
; sometimes expressions have SIDE-EFFECTS --
; define, after all, has the SIDE-EFFECT of making
;    a name have a particular value;

; file input/output can also be considered a side-effect;
; you might write a function that has a side-effect of
;    reading from a file,
; and/or has the side-effect of writing to a file;

; Racket has a teachpack batch-io, with a simple
;    suite of file i/o functions:

; let's make that teachpack available

(require 2htdp/batch-io)

; signature: read-file: string -> string
; purpose: expects the name of a file in the current 
;    directory (you must have saved your Definitions
;    window contents before running this!), and produces
;    the contents of that file depicted as a string

; IF I have created a file named looky.txt in the
;    SAME directory where this .rkt file is saved, then,
;    this expression will produce a string with looky.txt's
;    contents expressed as a string (with a \n for each 
;    newline...)

(read-file "looky.txt")
(string? (read-file "looky.txt")) ; will be true

; (beware, though -- you get an ERROR if this file does NOT exist)

; more on file i/o ob Thursday