;=====
; CS 111 - Week 4 Lecture 2 - 2026-09-17
;=====

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

;=====
; REMINDER
;=====
; cond expression
;
; syntax:
;    (cond
;        [boolean-expr1 result-expr1]
;        [boolean-expr2 result-expr2]
;        [boolean-expr3 result-expr3]
;        ...
;        [else result-expr-else]
;    )
;
; semantics:
; *   evaluate each clause's boolean expression in order
;     until it finds one with the value #true --
;     that clause's 2nd/result expression becomes the value
;     of the cond expression

;=====
; COPIED from Week 3 Lecture 2 posted examples
; (INCLUDING the signature, purpose, and tests!

;-----
; signature: cyan-star: number -> image
; purpose: expects the desired distance between
;    the points of a star and returns an image
;    of a cyan star of that size

(check-expect (cyan-star 10)
              (star 10 "solid" "cyan"))

(check-expect (cyan-star 4)
              (star 4 "solid" "cyan"))

(define (cyan-star star-size)  
   (star star-size "solid" "cyan")
)

;===== (END of part copied over from Week 3 Lecture 2)

;-----
; COPIED from Week 4 Lecture 1 posted examples
; (and edited to just include parts needed here)
;-----

(define WIDTH 400)
(define HEIGHT 200)

(define CENTER-X (* 0.5 WIDTH))

(define BACKDROP (empty-scene WIDTH HEIGHT))

;=====
; signature: cyan-star-scene: number -> scene
; purpose: expects a cyan star size and returns a scene
;    of a cyan star of that size, centered. The scene will
;    always be WIDTH x HEIGHT pixels.

(check-expect (cyan-star-scene 20)
              (place-image (cyan-star 20)
                           CENTER-X
                           (* 0.5 HEIGHT)
                           (empty-scene WIDTH HEIGHT)))

(check-expect (cyan-star-scene 50)
              (place-image (cyan-star 50)
                           CENTER-X
                           (* 0.5 HEIGHT)
                           (empty-scene WIDTH HEIGHT)))

(define (cyan-star-scene star-size)
    (place-image (cyan-star star-size)
                 CENTER-X
                 (* 0.5 HEIGHT)
                 (empty-scene WIDTH HEIGHT)))

;===== (END of part copied over and edited from Week 4 Lecture 1

;=====
; remember: big-bang's stop-when clause
;     expects the name of a function that
;     expects the current world value's type and returns
;     a boolean
; and when big-bang's ticker ticks, it calls the function
;     from a stop-when clause with the current world value,
;     and if that function returns #true, big-bang ends
;
;     (get it? asking big-bang to stop when its function is #true...)
;

"====="
"Thanks to stop-when clause with built-in Racket function "
"    zero?, this ends gracefully when world value reaches 0"
"====="

(big-bang 100
    (on-tick sub1)
    (to-draw cyan-star-scene)
    (stop-when zero?))

;=====
; I'd like to be able to stop a big-bang expression involving
;    cyan stars for too big OR too small values

(define MAX-STAR-SIZE 200)

;=====
; recall the MATH notation for intervals:
;     ( or ) means up to but NOT including that value
;     [ or ] means INCLUDING that value
;
; so, for example:  [3, 8) means all values between
;     3 and 8, *including* 3 but *not* including 8

;=====
; SO: say I consider a "good" star size to be [1, MAX-STAR-SIZE]
;
; I could write a function that returns true if my
;    proposed star size is "bad"

;=====
; signature: bad-star-size?: number -> boolean
; purpose: expects a star size, and returns #true if it
;    is "bad" -- if it is outside the interval [1, MAX-STAR-SIZE] -
;    and returns #false otherwise

;-----
; CS 111 Class Style: when your function is dealing with
;     numeric intervals, need a test for each interval,
;     PLUS a test for each BOUNDARY value between intervals

;-----
; SO, since this interval divides a number line into 3 regions, or
;     intervals, I should have at least 1 test per region,
;     PLUS an additional test for each boundary between regions --
;
; so, we need at least FIVE tests here (3 intervals, and 2 boundaries
;     in-between):

(check-expect (bad-star-size? -1) #true)
(check-expect (bad-star-size? 1) #false)
(check-expect (bad-star-size? 7) #false)
(check-expect (bad-star-size? MAX-STAR-SIZE) #false)
(check-expect (bad-star-size? (+ 10 MAX-STAR-SIZE)) #true)

;-----
; (just for your reference, I am including the
;     versions we refactored from during class --
;     that is not required!)

(define (bad-star-size? star-size)
;    ; version 1 - 3-branch version
  
;    (cond
;        [(< star-size 1) #true]
;        [(> star-size MAX-STAR-SIZE) #true]
;        [else #false]
;    )

;    ; refactored version 2 - 
;    ;     combining the #true cases into one branch using or

;    (cond
;        [(or (< star-size 1)
;             (> star-size MAX-STAR-SIZE))
;             #true]
;        [else #false]
;    )

    ; refactored version 3 - realizing a single boolean expression
    ;     can work here for this boolean function

    (or (< star-size 1)
        (> star-size MAX-STAR-SIZE))
)

(bad-star-size? (+ MAX-STAR-SIZE 167))

"====="
"thanks to stop-when clause using our new function"
"    bad-star-size?, both of these big-bang calls end"
"    gracefully!"
"====="

(big-bang 100
    (on-tick sub1)
    (to-draw cyan-star-scene)
    (stop-when bad-star-size?))

(big-bang 50
    (on-tick add1)
    (to-draw cyan-star-scene)
    (stop-when bad-star-size?))

;======
; it's penguin time!

;=====
; some useful named constants

;----
; these images were originally from
;     http://wallofgame.com/free-online-games/arcade/231/Parachute_Penguin_Shootout.html):

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

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

FLOATING-PENGUIN
LANDED-PENGUIN

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

(define PENG-SC-BACKGD (empty-scene PENG-SC-WIDTH PENG-SC-HEIGHT))

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

;=====
; oh -- want the penguin to "land" when its feet roughly
;    reach the "ground" --
; BUT place-image tends to center the image at the (x, y) coordinates
;     specified (although there are also ways to change
;     what is considered its "center" -- see put-pinhole
;     in the 2htdp/image documentation)

; so -- a bigger y is further down in a scene coordinate system;
;    I want to switch to a landed penguin before PENG-SC-HEIGHT;
;    ...so, for a y value smaller than PENG-SC-HEIGHT --
;    ...how much smaller? Half of the landed penguin's height smaller;
;
;    SO could subtract half the landed penguin's height
;         from PENG-SC-HEIGHT to get a better landing height;

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

;=====
; signature: draw-penguin-scene: number -> scene
; purpose: expects a penguin's y coordinate,
;    and if it is less than the LANDING-HEIGHT,
;    it returns a scene of a floating penguin centered
;    at that y coordinate;
;    otheriwse, it returns a scene of a now-landed penguin
;    on the "ground"

;-----
; for this function, I want at least 3 tests:
;    one that results in a floating penguin scene,
;    one that results in a landed penguin scene,
;    and one for the boundary between these two world-num ranges
; (more tests are fine!)

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

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

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

(define (draw-penguin-scene y-coord)
    (cond
        [(< y-coord LANDING-HEIGHT)
            (place-image FLOATING-PENGUIN
                         PENG-CTR-X
                         y-coord
                         PENG-SC-BACKGD)]
        
        [else
            (place-image LANDED-PENGUIN
                         PENG-CTR-X
                         LANDING-HEIGHT
                         PENG-SC-BACKGD)]
    )
)

"====="
"CLOSE World window when you are ready to go on --"
"    this big-bang expression continues to run until then!"
"====="

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

;=====
; draw-penguin-scene involved interval-style data;
; here's an example involving enumeration-style data

;=====
; enumeration-style data - a type of data that is a
;     relatively small number of discrete, specific cases --
;     *   a traffic light's colors of red, or yellow, or green
;     *   4 arrow keys of up, down, left, right
;     *   etc.

;=====
; a silly example using enumeration data
;-----
; based on Sandra Boynton's "Moo, Baa, La La La"

;=====
; signature: next-sound: string -> string
; purpose: expects an animal sound as a string,
;    and returns the next sequential animal sound
;    based on the beginning of Sandra Boynton's
;    "Moo, Baa, La La La" as follows:
;    *   for "moo", it returns "baa"
;    *   for "baa", it returns "la la la"
;    *   for "la la la", it returns "oink"
;    *   for "oink", it returns "moo"
;    *   for any other sound, it returns "???"

;-----
; I need at least 5 tests here --
;    one for each of the 4 possible sounds,
;    and because I specified what to do for a "bad" sound,
;        I also need to test for that

(check-expect (next-sound "moo") "baa")
(check-expect (next-sound "baa") "la la la")
(check-expect (next-sound "la la la") "oink")
(check-expect (next-sound "oink") "moo")
(check-expect (next-sound "bark") "???")


(define (next-sound farm-sound)
    (cond
        [(string=? "moo" farm-sound) "baa"]
        [(string=? "baa" farm-sound) "la la la"]
        [(string=? "la la la" farm-sound) "oink"]
        [(string=? "oink" farm-sound) "moo"]
        [else "???"]
    )
)

(next-sound "moo")
(next-sound "fred")