;=====
; CS 111 - Week 4 Lecture 1 - 2025-09-16
;=====

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

;=====
; slightly-edited FROM WEEK 2 LECTURE 2
;=====
;-----
; signature: cyan-star: number -> image
; purpose: expects the distance between a 5-pointed
;     star's points, and returns a solid cyan star image
;     of that size

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

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

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

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

;=====
;FROM WEEK 3 LECTURE 2 - then REFACTORED a bit!
;=====
(define WIDTH 400)
(define HEIGHT 200)

; I decide that these named constants might make this
;     more readable:

(define CENTER-X (/ WIDTH 2))
(define CENTER-Y (/ HEIGHT 2))

(define BACKDROP (empty-scene WIDTH HEIGHT))

;=====
; signature: cyan-star-scene: number -> scene
; purpose: expects a desired star size (distance in pixels
;     between its points) and returns a scene of size
;     WIDTH by HEIGHT with a cyan star of that size centered
;     within it

(check-expect (cyan-star-scene 50)
              (place-image (cyan-star 50)
                           CENTER-X
                           CENTER-Y
                           BACKDROP))

(check-expect (cyan-star-scene 150)
              (place-image (cyan-star 150)
                           CENTER-X
                           CENTER-Y
                           BACKDROP))

(define (cyan-star-scene star-size)
    (place-image (cyan-star star-size)
                 CENTER-X
                 CENTER-Y
                 BACKDROP)
)

(cyan-star-scene 50)
(cyan-star-scene 150)

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

;=====
; cond expression
;=====
; syntax:
;=====
;    (cond
;        [boolean-expr1 result-expr1]
;        [boolean-expr2 result-expr2]
;        [boolean-expr3 result-expr3]
;        ...
;        [else result-expr-else]
;    )
;
;    *   the [bool-expr result-expr] parts can be called 
;        branches or clauses
;    *   the second expr in each clause can be of any type
;        (but it must have a value)
;
;=====
; semantics (meaning):
;=====
; *   evaluate each clause's boolean expression in order
;     until it finds one with the value #true --
;     that clause's 2nd expression becomes the value of the cond
;     expression
;
;     *   once a clause starting with a #true boolean expression
;         is found, the rest of the clauses are IGNORED, skipped!
;         *   at most one branch will be "taken", at most one
;             clause will have its 2nd expression evaluated
;
;     *   so the ORDER of the clauses matters!
;
;     *   if you include an [else ...] clause and it is reached,
;         else is always considered #true and the else clause's
;         2nd expression will be the value of the cond expression
;
;=====
; CS 111 Class Style:
;=====
; *   start each [boolean-expr result-expr] clause in
;     a cond expression on its own line
;
; *   INDENT the start of each [boolean-expr result-expr]
;     clause in a cond expression under its (cond
;
; *   (for a long clause, indent its continuation line(s)
;     so it is clear which clause it is continuing)
;
; *   as always, ASK me if you have any questions about CS 111
;     class style!

;=====
; kind of inspired by the song "Yes, We Have No Bananas",
;     I decide I want a function that expects a quantity
;     of bananas, and returns a slightly-grammatical
;     report of that quantity

;=====
; signature: banana-report: number -> string
; purpose: expects an integer quantity of bananas
;     and returns a string reporting that quantity of
;     bananas (saying no bananas if 0 or fewer, one banana
;     if 1, and the given quantity as a number with bananas
;     if more than 1)

;=====
; do you see that you should have a test for each
;     branch, and sometimes more, as we'll see later?

(check-expect (banana-report -7)
              "yes, we have no bananas!")

(check-expect (banana-report 0)
              "yes, we have no bananas!")

(check-expect (banana-report 1)
              "yes, we have one banana!")

(check-expect (banana-report 2)
              "yes, we have 2 bananas!")

(check-expect (banana-report 400)
              "yes, we have 400 bananas!")

(define (banana-report num-bananas)
    (cond
        [(<= num-bananas 0) "yes, we have no bananas!"]
        [(= num-bananas 1)  "yes, we have one banana!"]
        [else (string-append "yes, we have "
                             (number->string num-bananas)
                             " bananas!")]
    )
)

(banana-report -7)
(banana-report 1)
(banana-report 400)

;====
; I decide I'd like to write a function to use with
;     cyan-star-scene and big-bang to use with big-bang's
;     stop-when clause,
;     to help big-bang end gracefully whenever the world
;     size gets "unreasonable"

; say: a star size of 0 or less,
;     and maybe if the star size exceeds the HEIGHT, that's
;     too big; 

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

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

;=====
; signature: bad-star-size?: number -> boolean
; purpose: expects a star size, and returns #true if it
;     is OUTSIDE the the desired star size range of
;     [1, HEIGHT) and it 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, we need at least FIVE tests here (3 intervals, and 2 boundaries
;     in-between):

(check-expect (bad-star-size? -5) #true)
(check-expect (bad-star-size? 1) #false)
(check-expect (bad-star-size? (- HEIGHT 1)) #false)
(check-expect (bad-star-size? HEIGHT) #true)
(check-expect (bad-star-size? (+ HEIGHT 167)) #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)
;    (cond
;;        ; version 1 - 3-branch version
;;
;;        [(< star-size 1) #true]
;;        [(>= star-size HEIGHT) #true]
;;        [else #false]
;
;         ; refactored version 2 -
;         ;     combining the #true cases into one branch using or
;
;         [(or (< star-size 1)
;              (>= star-size HEIGHT)) #true]
;         [else #false]
;      
;    )

    ; refactored version 3 - realizing a single boolean expression
    ;     can work here for this boolean function
  
    (or (< star-size 1)
        (>= star-size HEIGHT))
)

(bad-star-size? (+ HEIGHT 167))

"====="
"thanks to stop-when clause, these big-bang calls end"
"    gracefully! (but you should close the World window...)"

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

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