Please send questions to st10@humboldt.edu .

; Bonus, after-class example: a scene of a "sun" rising
;    and setting, as another example of a conditional
;    function, another boolean function, and another
;    collection of definitions and functions that work
;    together to a single purpose

; NOTE: this is more complex than the animation
;    asked for in HW 4 is required to be (although
;    since you get to customize if desired, you might take
;    yours to a comparable level... 8-) )

;--------------------------------------------------------
; goal: to animate a scene where a "sun" rises and sets...

; more specifically: a sun moves diagonally upward for
;    a while, then diagonally downward for a while, and
;    repeats;
;    ...can't do that with just modulo, but you CAN
;    with the help of a cond expression;

; (could the sun "rise" in a curved arc? Sure, with the right
;    math... maybe a lovely quadratic equation for setting x and y
;    given the modulo of the time counter... that's a
;    variation for another time...)

; we know we need to create a scene -- one with a sun
;    whose position is determined by the current time-counter
;    value -- but sometimes the sun should be "rising" and
;    sometimes the sun should be "setting".

; and, with a time-counter that gets ever-bigger, we can
;    use modulo to coerce that value into a guaranteed-to-be-in
;    -scene range, if we are careful;

;-------------------------------------------------------
; FIRST, then: some definitions:

(define WIDTH 400)
(define HEIGHT 300)
(define SUN (circle 45 "solid" "yellow"))
(define BACKDROP
	(place-image (nw:rectangle WIDTH HEIGHT "solid" "blue")
	             0   0   (empty-scene WIDTH HEIGHT)))

BACKDROP

; might be fun to figure out how we could get the sky to
;    brighten when the sun is going up, and darken when going
;    down, but that's another possibility for another day... 8-)
; (it would require creating the nw:rectangle in the
;    create-scene function, too, by the way, instead of
;    having it be part of the backdrop)

; contract: create-sun-scene: number -> scene
; purpose: expects a time-counter value, and if 
;    (modulo time-counter WIDTH) is in the morning
;    range, should produce a scene with a sun centered
;    at... 

; Hmm. Need to consider this!
; at time-counter of 0 -- where should sun be?
; how about in the middle of the left-hand side?
; ...what coordinates? x is 0; y is (/ HEIGHT 2)

; How long should it go up? That is, what is the "morning"
;    range? How about -- [0, (/ WIDTH 2)]?
; "afternoon" range? Note that it is ((/ WIDTH 2), WIDTH)
;    ...and WIDTH is NOT part of that interval, since
;    (modulo time-counter WIDTH) can never equal WIDTH
;    (it always produces 0 to (- WIDTH 1) )

; So -- at time-counter of (/ WIDTH 2), I'd LIKE to be at the 
;    top middle of the scene -- perhaps x of (/ WIDTH 2),
;    y of 0

; it DOES take a little math to figure this out --
;    I want to start at (0, (/ HEIGHT 2)) and end at
;    ((/ WIDTH 2), 0) in (/ WIDTH 2) steps;
; ...while in morning range, as (modulo time-counter WIDTH)
;    goes from 0 to (/ WIDTH 2), I want x coordinate to change
;    from 0 ro (/ WIDTH 2). OK, then, that's set.
; ...how should y change? from (/ HEIGHT 2) to 0! in (/ WIDTH 2)
;    steps;
;    slope of a line is the change in y over the change in x;
;    (/ (/ HEIGHT 2) (/ WIDTH 2) )
;    ...that's how much it changes per unit change in x?

; OK then!

; auxiliary function one: I'd like a function that simply
;    tells me if the time-counter is in "morning" range;
;    ...it is in morning range if (modulo time-counter WIDTH)
;       is in the interval [0, (/ WIDTH 2)]

;--------------------------------------------------------
; contract: morning-range?: number -> boolean
; purpose: expects a time-counter value, and produces
;    whether (modulo time-counter WIDTH) is in
;    the interval [0, (/ WIDTH 2)]

; normally, an interval like this would require at least
;    FIVE specific examples/test cases: <0, =0, in the interval,
;    =(/ WIDTH 2), and >(/ WIDTH 2).
; BUT! A time-counter can NEVER be negative -- so you can skip
;    that one.. (it's OK to have it in a check-expect, but
;    it would not be called by animate...)

(check-expect (morning-range? 0) true)
(check-expect (morning-range? (- (/ WIDTH 2) 5)) true)
(check-expect (morning-range? (/ WIDTH 2)) true)
(check-expect (morning-range? (+ (/ WIDTH 2) 5)) false)

; hmm -- and better have a few for "bigger" example
;    time-counter values, to double-check my modulo
;    expressions;

(check-expect (morning-range? (* 3 WIDTH)) true)
(check-expect (morning-range? (+ 1 (* 3 WIDTH))) true)
(check-expect (morning-range? (+ (* 3 WIDTH) (/ WIDTH 2)))
              true)
(check-expect (morning-range? (+ (* 3 WIDTH) (/ WIDTH 2) 5))
              false)

(define (morning-range? time-counter)
  (and (>= (modulo time-counter WIDTH) 0)
       (<= (modulo time-counter WIDTH) (/ WIDTH 2)))
)

; I think I'd like an auxiliary function that helps me
;    with the y coordinate of the desired sun, too.
; ...how about two? One for the "rising" sun, and one
;    for the "setting" sun?

;------------------------------------------------------
; contract: get-rising-y: number -> number
; purpose: expects a time-counter value, assumed to
;    be in the "morning" range, and determines the
;    y value for the sun for that time-counter
;    value

; y better be this at time-counter of 0 (I want the sun to
;    start on the left, mid-way up)

(check-expect (get-rising-y 0) (/ HEIGHT 2))

; y better be this at time-counter of (/ WIDTH 2) (I want the
;    sun, at its height, to be at height 0)

(check-expect (get-rising-y (/ WIDTH 2)) 0)

; OK then! to get from (/ HEIGHT 2) to 0 as time-counter
;    increases -- y had better decrease by 
;    (/ (/ HEIGHT 2) (/ WIDTH 2) ) by time-counter "step" --
;    OR -- subtract (/ (/ HEIGHT 2) (/ WIDTH 2) ) * time-counter
;    from initial y of (/ HEIGHT 2) for each step...
;    (really, the modulo of time-counter and width...)

(check-expect (get-rising-y 10)
              (- (/ HEIGHT 2)
                 (* (/ (/ HEIGHT 2) (/ WIDTH 2)) 10)))

; and make sure still works as time-counter gets beyond
;    WIDTH... this should have the SAME y, as the above
;    check-expect, true?

(check-expect (get-rising-y (+ 10 (* WIDTH 3)))
              (- (/ HEIGHT 2)
                 (* (/ (/ HEIGHT 2) (/ WIDTH 2)) 10)))

(define (get-rising-y time-counter)
   (- (/ HEIGHT 2)
      (* (/ (/ HEIGHT 2) (/ WIDTH 2)) 
         (modulo time-counter WIDTH)))
)

; hmm; won't get-setting-y be similar, except it ADDS to 0
;    instead of subtracting from (/ HEIGHT 2)?

;--------------------------------------------------------
; contract: get-setting-y: number -> number
; purpose: expects a time-counter value, assumed to
;    be in the "afternoon" range, and determines the
;    y value for the sun for that time-counter
;    value

; y better be this at time-counter of (/ WIDTH 2) (I want the 
;    sun to be at its highest point at this "midday" value)

(check-expect (get-setting-y (/ WIDTH 2)) 0)

; careful -- can x ever reach WIDTH? not with 
;    (modulo time-counter WIDTH) involved -- it goes to 0, then!
; ...there's no night-time in this particular scenario... 8-)

; ...and, really, get-setting-y should NOT be called with
;    a time-counter of WIDTH -- that's not in the "afternoon"
;    range...

; OK then! to get from 0 to (/ HEIGHT 2) as time-counter
;    increases in the "afternoon" -- y had better increase by 
;    (/ (/ HEIGHT 2) (/ WIDTH 2) ) by time-counter "step" --
;    OR -- add (/ (/ HEIGHT 2) (/ WIDTH 2) ) * 
;              (- time-counter (/ WIDTH 2))
;    from initial y of 0 for each step past the middle;
;    (and of course, adding to 0 -- that's just that product)
;    (and, really, the modulo of time-counter and width...)

(check-expect (get-setting-y (+ (/ WIDTH 2) 10))
              (* (/ (/ HEIGHT 2) (/ WIDTH 2)) 10))

; and make sure still works as time-counter gets beyond
;    WIDTH... this should have the SAME y, as the above
;    check-expect, true?

(check-expect (get-setting-y (+ 10 (* WIDTH 3) (/ WIDTH 2)))
              (* (/ (/ HEIGHT 2) (/ WIDTH 2)) 10))

(define (get-setting-y time-counter)
      (* (/ (/ HEIGHT 2) (/ WIDTH 2)) 
         (- (modulo time-counter WIDTH) (/ WIDTH 2)))
)

; back to scene creation function, finally!

;------------------------------------------------------------
; contract: create-sun-scene: number -> scene
; purpose: expects a time-counter value, and if 
;    (modulo time-counter WIDTH) is in the morning
;    range, creates a scene with the sun centered
;    at the appropriate "rising" point for that
;    time between (0, (/ HEIGHT 2)) and
;    ((/ WIDTH 2), 0). Otherwise, it creates
;    a scene at the appropriate "setting" point for
;    that time between ((/ WIDTH 2), 0) and
;    (WIDTH, (/ HEIGHT 2))

(check-expect (create-sun-scene 0)
              (place-image SUN
                           0   (/ HEIGHT 2)
                           BACKDROP))

(check-expect (create-sun-scene 10)
              (place-image SUN
                           10 (get-rising-y 10)
                           BACKDROP))

(check-expect (create-sun-scene (/ WIDTH 2))
              (place-image SUN
                           (/ WIDTH 2) 0
                           BACKDROP))

(check-expect (create-sun-scene (+ (/ WIDTH 2) 5))
              (place-image SUN
                           (+ (/ WIDTH 2) 5)
                           (get-setting-y (+ (/ WIDTH 2) 5))
                           BACKDROP))

; at time-counter of WIDTH -- it should be back on the
;    left...

(check-expect (create-sun-scene WIDTH)
              (place-image SUN
                           0 (/ HEIGHT 2)
                           BACKDROP))

; and make sure time-counter still OK as it goes out
;    of range...

(check-expect (create-sun-scene (+ (* WIDTH 3) 5))
              (place-image SUN
                           5 (get-rising-y 5)
                           BACKDROP))

(check-expect (create-sun-scene (+ (* WIDTH 3) (/ WIDTH 2) 5))
              (place-image SUN
                           (+ (/ WIDTH 2) 5) 
                           (get-setting-y (+ (/ WIDTH 2) 5))
                           BACKDROP))
              
; result of template step

;(define (create-sun-scene time-counter)
;  (cond
;    [... ...]
;    [else ...]
;  )
;)

(define (create-sun-scene time-counter)
  (cond
    [(morning-range? time-counter)
        (place-image SUN 
                     (modulo time-counter WIDTH)
                     (get-rising-y time-counter)
                     BACKDROP)]
    [else 
        (place-image SUN
                     (modulo time-counter WIDTH)
                     (get-setting-y time-counter)
                     BACKDROP)]
  )
)

; does this actually work...? YES!

(animate create-sun-scene)