Please send questions to st10@humboldt.edu .

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

; CS 131 - Week 5, 10 am Lab

;---------------
;---------------
; pulling data definitions and functions from Week 5, Lecture 2
; (edited)

;------------
; data definition for a list:

; a list is:
;   - empty, OR
;   - (cons anything list)

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

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

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

;----------
; signature: many-circles: number-list -> scene
; purpose:  expects a list of circle radii
;    and produces a scene containing centered circles
;    with those radii

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

(define (many-circles rad-list)
   (cond
      [(empty? rad-list) BACKDROP]
      [else (place-image 
               (circle (first rad-list) "outline" "black")
               (/ WIDTH 2)
               (/ HEIGHT 2)
               (many-circles (rest rad-list)))]
   )
)

(check-expect (many-circles empty)
              BACKDROP)

(check-expect (many-circles (cons 50 (cons 25 (cons 66 empty))))
              (place-image 
                 (circle 50 "outline" "black")
                 (/ WIDTH 2)
                 (/ HEIGHT 2)
                 (place-image 
                    (circle 25 "outline" "black")
                    (/ WIDTH 2)
                    (/ HEIGHT 2)
                    (place-image
                       (circle 66 "outline" "black")
                       (/ WIDTH 2)
                       (/ HEIGHT 2)
                       BACKDROP))))

(many-circles (cons 50 (cons 25 (cons 66 empty))))

;----------
; data definition for a whole-number:
;
; a whole-number is:
;    - 0, or
;    - (+ 1 whole-number)

;----------
; template for a function number-funct that has a 
;    whole-number parameter num-times
;    (you want this when you want to DO something
;    a certain number of times)

; (define (number-funct ... num-times ...)
;    (cond
;       [(= num-times 0) ...]
;       [else (... num-times ...
;                  (number-funct ... (- num-times 1) ...)
;             ...)]
;    )
; )
;  

;a description of the random function you get along
;    with the Beginning Student Level of Racket:

;----------
; signature: random: number -> number
; purpose: expects the ending value in an open
;    interval, and returns a number in the range 
;    [0, that value)

(random 50) ; I'll get values in the interval [0, 50)

;----------
; signature: generate-radii: whole-number -> number-list
; purpose: expects the number of radii desired, and
;    generates a list of that many radii all in the
;    range [MIN-RAD, MAX-RAD)

(define MIN-RAD 5)
(define MAX-RAD (/ (min WIDTH HEIGHT) 2))

(define (generate-radii how-many)
    (cond
       [(= how-many 0) empty]
       [else (cons (+ MIN-RAD (random (- MAX-RAD MIN-RAD)))
                   (generate-radii (- how-many 1)))]
    )
)

(check-expect (generate-radii 0) empty)

; at least this will test if the generated result is a list,
;    and is of length 4...

(check-expect (length (generate-radii 4)) 4)

(generate-radii 10)
(many-circles (generate-radii 10))
(many-circles (generate-radii 100))
(many-circles (generate-radii 25))

;-------------------
;-------------------
; the examples for the 10 am WEEK 5 LAB start HERE

; note: color is an Itemization type in the 2htdp universe and image
;    teachpacks;

;------------
; a color is a:
;    - string containing the name of a color, or
;    - (make-color number number number)
;      where the first number is the red value, between [0, 255],
;            the second is the green value, between [0, 255],
;            the third is the blue value, between [0, 255]
;
; (yes, color-red gets a color struct's red value,
;       color-green gets its green value, and
;       color-blue gets its blue value)

;----------
; signature: colorful-circles: number-list -> scene
; purpose:  expects a list of circle radii
;    and produces a scene containing centered randomly-colored circles
;    with those radii

(define (colorful-circles rad-list)
   (cond
      [(empty? rad-list) BACKDROP]
      [else (place-image 
               (circle (first rad-list) "outline" 
                       (make-color (random 256)
                                   (random 256)
                                   (random 256)))
               (/ WIDTH 2)
               (/ HEIGHT 2)
               (colorful-circles (rest rad-list)))]
   )
)

(check-expect (colorful-circles empty)
              BACKDROP)

; because of the random issue, cannot reasonably do a 
;    non-empty list test for colorful circles... 8-(
;...but I can at least view and check out the results...

(colorful-circles (cons 50 (cons 25 (cons 66 empty))))
(colorful-circles (generate-radii 25))

;-----------
; here's an example of a filter function (one that expects a list
;    a produces a list based on the first that might be smaller than
;    the original list)

; I want a function that expects a desired minimum value and
;     a list of numbers, and produces a new list with only those
;     values from the original list that are greater than that minimum

; I already have a data definition for number-list in this Definitions
;    window...

;-----------
; signature: get-above: number number-list -> number-list
; purpose:  expects a desired minimum value and
;     a list of numbers, and produces a new list with only those
;     values from the original list that are greater than that minimum

(define (get-above minimum a-num-list)
    (cond
       [(empty? a-num-list) empty]
       [(> (first a-num-list) minimum)
             (cons (first a-num-list) 
                   (get-above minimum (rest a-num-list)))]
       [else (get-above minimum (rest a-num-list))]
    )
)

(check-expect (get-above 240 empty) empty)

(check-expect (get-above 10 (cons 3 (cons 17 (cons 2 (cons 21 empty)))))
              (cons 17 (cons 21 empty)))

(check-expect (get-above 7 (cons 1 (cons 2 (cons 3 empty))))
              empty)

(check-expect (get-above 50 (cons 100 (cons 200 empty)))
              (cons 100 (cons 200 empty)))
(get-above 10 (cons 3 (cons 17 (cons 2 (cons 21 empty)))))
(get-above 20 (generate-radii 10))

;---------------
;---------------
; 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 10 am WEEK 5 LAB resume HERE

;-------
; I want a list of h-fliers! and I want big-bang to be able to
;    work on a list of h-fliers (I want its world to be a list
;    of h-fliers

;----------
; above, I have my h-flier data definition;
; I now need the data definition for this specialized list:

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

; template for a function uses-many-fliers that expects a list-of-h-flier
;
; (define (uses-many-fliers ... h-flier-list ...)
;    (cond
;       [(empty? h-flier-list) ...]
;       [else (... (first h-flier-list) ...
;                  (uses-many-fliers ... (rest h-flier-list) ...) ...)]
;    )
; )

;----------
; more-complete template for a function uses-many-fliers that 
;     expects a list-of-h-flier
; (why? because this recognizes that we are likely to want to
;     make use of the details about the first h-flier in the
;     list-of-h-flier
;
; (define (uses-many-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-many-fliers ... (rest h-flier-list) ...) ...)]
;    )
; )

;-----------
; I want a function that expects a list of h-fliers, and depicts
;    them in a scene...

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

(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 80 30))
(define THIRD-FLIER (make-h-flier (square 15 "solid" "blue") 10 30 80))
(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 INITIAL-FLIERS))
                           100 50 
                           (draw-flier-list (rest INITIAL-FLIERS))))
(draw-flier-list INITIAL-FLIERS)

;--------
; now, I want a function that expects a list of h-fliers,
;    and produces the list of h-fliers as they should be
;    after the next clock tick

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

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

; what if -- I want to generate a bunch of little circle h-fliers --
;    I'm going to call them dot-fliers...

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

;----------
; signature: generate-dot-fliers: whole-number -> list-of-h-flier
; purpose: expects the number of h-fliers desired, and
;    produce a list of h-fliers that are set-sized dots of
;    random colors and speeds

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

;--------
; bonus after-lab example -- because putting this big-bang in its
;    own main, to make it easier to start up worlds with different
;    initial lists of h-fliers, would be more convenient...

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