;=====
; CS 111 - Week 5 Lecture 1 - 2024-09-24
;=====

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

;===== ADAPTED from Week 4 Lecture 2 =====
;    (shortened some comments) 

;=====
; some useful named constants related to my penguin scenes

(define PENG-SC-WIDTH 300)
(define PENG-SC-HT 450)

(define PENG-SC-BACKGRD (empty-scene PENG-SC-WIDTH
                                     PENG-SC-HT))

(define PENG-CTR-X (/ PENG-SC-WIDTH 2))

;=====
; bitmap/url expects a string with a URL and returns the
;    image at that URL

(define FLOATING-PENGUIN
        (bitmap/url 
"https://nrs-projects.humboldt.edu/~st10/f24cs111/floating-penguin.png"))

(define LANDED-PENGUIN
        (bitmap/url
"https://nrs-projects.humboldt.edu/~st10/f24cs111/landed-penguin.png"))

FLOATING-PENGUIN
LANDED-PENGUIN

; want the landed penguin's y-coordinate to be
;    slightly LESS than the scene's height
;    so it is standing "on" the ground and not
;    underground
; (how much less? half-of-the-penguin's-height less!)

(define LANDING-HEIGHT (- PENG-SC-HT
                          (/ (image-height LANDED-PENGUIN)
                             2)
                       ))

;=====
; signature: draw-penguin-scene: number -> scene
; purpose: expects a world-number, and if it is less than
;    LANDING-HEIGHT, it returns a scene of a floating penguin
;    whose y-coordinate is the current world-number,
;    otherwise, it returns a scene with the now-landed
;    penguin on the "ground"

; the interval-style data here has 2 intervals/categories,
;     so need 3 tests, one for each interval and
;     one for the boundary between them

(check-expect (draw-penguin-scene 10)
              (place-image FLOATING-PENGUIN
                           PENG-CTR-X
                           10
                           PENG-SC-BACKGRD))

(check-expect (draw-penguin-scene 10000)
              (place-image LANDED-PENGUIN
                           PENG-CTR-X
                           LANDING-HEIGHT
                           PENG-SC-BACKGRD))

(check-expect (draw-penguin-scene LANDING-HEIGHT)
              (place-image LANDED-PENGUIN
                           PENG-CTR-X
                           LANDING-HEIGHT
                           PENG-SC-BACKGRD))

(define (draw-penguin-scene world-num)
   (cond
      [(< world-num LANDING-HEIGHT)
           (place-image FLOATING-PENGUIN
                        PENG-CTR-X
                        world-num
                        PENG-SC-BACKGRD)]
      
      [else (place-image LANDED-PENGUIN
                         PENG-CTR-X
                         LANDING-HEIGHT
                         PENG-SC-BACKGRD)]
   )
)

(draw-penguin-scene 10)
(draw-penguin-scene 10000)

;===== END of part copied from Week 4 Lecture 2 =====

"our penguin-world as of the end of class, "
"    Week 4 - Lecture 2: "
"    (close big-bang sub-window to "
"        stop this big-bang expression)"

(big-bang 0
  (to-draw draw-penguin-scene)
  (on-tick add1))

;=====
;big-bang clause: on-key
;=====
;*   so that a keyboard event -- the act of typing
;    a key on the keyboard while big-bang is running --
;    can be handled to affect the world
;
;*   on-key expects the name of a function that
;    expects TWO arguments:
;    *   the current world value
;    *   a string representing the key that was typed
;
;    and that function should return whatever the new
;    world-value should be (as a result of that key
;    being typed)
;
;    *   (note: big-bang calls this function for you
;        when a key is typed, and it is ALREADY part
;        of big-bang to be able to determine a string
;        to correspond to a typed key)

;=====
; let's add the ability to change the
;     penguin's altitude when the user types the
;     up-arrow or down-arrow keys!

;=====
; how much should it "jump" each time a user types
;     the up-arrow or down-arrow keys?

(define JUMP-AMOUNT 20)

;=====
; FUN FACT:
; big-bang will associate "up" with
;        someone typing the up-arrow key,
;    and it will associate "down" with
;        someone typing the down-arrow key

;=====
; signature: change-elevation: number string -> number
; purpose: expects the current world-number and a keystroke
;     string of "up" or "down", and returns the following:
;     *   if the keystroke string is "up", it returns
;         the current world-number reduced by JUMP-AMOUNT
;     *   if the keystroke string is "down", it returns
;         the current world-number increased by JUMP-AMOUNT
;     *   otherwise, it returns the current world-number
;         unchanged

(check-expect (change-elevation 7 "up")
              (- 7 JUMP-AMOUNT))

(check-expect (change-elevation 22 "down")
              (+ 22 JUMP-AMOUNT))

(check-expect (change-elevation 50 "f")
              50)

(define (change-elevation world-num user-entry)
   (cond
       [(string=? user-entry "up")   (- world-num JUMP-AMOUNT)]
       [(string=? user-entry "down") (+ world-num JUMP-AMOUNT)]
       [else world-num]
   )
)

"====================="
"type up-arrow or down-arrow keys to see what happens"
"====================="

(big-bang 0
  (to-draw draw-penguin-scene)
  (on-tick add1)
  (on-key change-elevation))

;=====
; Itemizations - another style of data
;     for which cond expressions are useful!!!!

;-----
; an interval distinguishes subclasses of numbers;
;
; an enumeration spells out, item for item, the useful
;    elements of an existing class of data;
;
; an itemization *generalizes* intervals and enumerations,
;    and allows for distinctive combinations of existing
;    data types and individual pieces of data!
;    *   we are going to use a data definition comment
;        to specify a desired itemization type when we want one

;====
; aside: data definition
;
; this (at this part of the semester in BSL Racket)
;    will be defined using a COMMENT,
; giving a name for this new informal type starting
;    with an uppercase letter and using CamelCase,
; and describing the possible values of this informal type

;=====
; DATA DEFINITION
; a NumOrF is one of:
;   - #false
;   - a number

;=====
; DATA DEFINITION
; a Color is one of:
;   - a string whose name is a color
;   - (make-color red-value green-value blue-value)

;=====
; CS 111 class style:
; once you have given a data definition comment for
;    an informal type, you can and should use that
;    in signature comments for functions that expect
;    or return such a type that follow that comment

;=====
; for a function expecting itemization data,
;    you frequently can use a cond with a branch
;    for each of the items in the itemization
; and you DO need at least one test for each
;    branch in the itemization!
;    *   sometimes you might need MORE, if some of the
;        branches involve interval data...!

;====
; AS AN EXAMPLE of itemization data:
;
; what if I want a function double-it that can
;    double, conceptually, something that might
;    be a number or an image or a string?

;-----
; this could be considered itemization-style data!

;=====
; DATA DEFINITION
; an AddableType is one of:
;    - number
;    - image
;    - string

;-----
; SO -- if I am writing a function after this
;    data definition comment that
;    expects this kind of data and/or returns this kind of
;    data, I now CAN use AddableType in that function's signature:

;=====
; signature: double-it: AddableType -> AddableType
; purpose: expects an addable thing, and:
;    *   IF it is a number, returns the sum of
;        that number and itself
;    *   IF it is an image, returns the result of
;        copying that image beside itself
;    *   IF it is a string, it returns the result
;        of appending that string to a space and itself

(check-expect (double-it 50)
              100)

(check-expect (double-it FLOATING-PENGUIN)
              (beside FLOATING-PENGUIN FLOATING-PENGUIN))

(check-expect (double-it "poot")
              "poot poot")

(define (double-it an-addable-thing)
   (cond
     [(number? an-addable-thing)
          (+ an-addable-thing an-addable-thing)]
     [(image? an-addable-thing)
          (beside an-addable-thing an-addable-thing)]
     [(string? an-addable-thing)
          (string-append an-addable-thing " " an-addable-thing)]
   )
)

(double-it 50)
(double-it FLOATING-PENGUIN)
(double-it "poot")

;===== !!!!! =====
; SIDE NOTE:
; when dealing with itemization-style data, sometimes you
;     need to see if an argument is equal to a particular value,
;     BUT the argument might be one of a multi-type itemization type;
;
; THAT's where the function equal? can be VERY handy!
;
;-----
; equal? expects two arguments of ANY type and
;    returns if they are equal or not

;-----
; for example: this is #false, but will NOT cause an error message:

(equal? 1 "1")

;-----
; (SO:      =         expects two or more arguments of type number,
;           string=?  expects two arguments of type string,
;           image=?   expects two arguments of type image,
;           boolean=? expects two arguments of type boolean,
;
;       but equal?    expects two arguments of ANY type,
;           which can be USEFUL in a cond's boolean expression
;           involving an argument of an itemization type...

;-----
; Why have the others, then?
; Because sometimes you would prefer a function give an error message
;    if called with a definitely-wrong type, such as a function
;    that only expects a single particular type.