; CS 111 - Week 4 Lecture 2 - 2016-09-15
; Sharon Tuttle
; last modified: 2016-09-15

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

; cond expression syntax:
;
; (cond
;     [boolean_expr1 expression1]
;     [boolean_expr2 expression2]
;     ...
;     [else expression-else
; )
;
; semantics: DrRacket tries each
;   boolean expression UNTIL it finds
;   one that's #true -- when it does,
;   that clause's 2nd expression IS the
;   value/result for this cond expression
;   (if none? then the else's expression
;    becomes the cond expression's value)

; (I *think* BSL Racket will let you omit
;    the else clause, BUT will give an
;    error if it is NEEDED and not there...)

;========
; another branching example:

; in Math, you might recall:
;    abs-value(x) = x if x >=0
;                  -x if x < 0


; signature: abs-value: number -> number
; purpose: expects a number, returns the
;    absolute value of that number:
;    abs-value(x) = x if x >=0
;                  -x if x < 0

;(define (abs-value num)
;    ...
;)

; TWO categories of interval-style data,
;    with ONE boundary -- so at least THREE
;    tests are needed;

(check-expect (abs-value 11)
              11)
(check-expect (abs-value -3)
              3)
(check-expect (abs-value 0)
              0)

; I have TWO categories of data --
;    I will likely have at least TWO clauses,
;    two BRANCHES if you will, in my cond

;(define (abs-value num)
;    (cond
;        [... ...]
;        [... ...]
;    )
;)

(define (abs-value num)
    (cond
        [(>= num 0) num]
        [else (- 0 num)]
    )
)

;========
; back to the penguin example!

(define FLOATING-PENGUIN floating penguin image)
(define LANDED-PENGUIN landed penguin image)

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

; if I want an animation with these penguins,
;    using big-bang,
;    I need a function that expects a world value
;    and returns the "right" penguin-scene for
;    that world value;

; signature: draw-penguin: number -> scene
; purpose: expects a world-number,
;    and if the world number is less than 
;    (HEIGHT - 50), then this returns a scene of
;    a floating penguin centered at a y coordinate
;    of that world value;
;    otherwise, this returns a scene of a landed
;    penguin 50 pixels above the "ground"
;   (at the bottom of the
;    scene)

;(define (draw-penguin world-num)
;    ...
;)

; need at least 3 tests -- one for
;    floating, one for landed, one for
;    boundary...

(check-expect (draw-penguin 10)
              (place-image FLOATING-PENGUIN
                           (/ WIDTH 2)
                           10
                           BACKDROP))

(check-expect (draw-penguin (+ HEIGHT 1000))
              (place-image LANDED-PENGUIN
                           (/ WIDTH 2)
                           (- HEIGHT 50)
                           BACKDROP))

(check-expect (draw-penguin (- HEIGHT 50))
              (place-image LANDED-PENGUIN
                           (/ WIDTH 2)
                           (- HEIGHT 50)
                           BACKDROP))

;(define (draw-penguin world-num)
;    (cond
;        [... ...]
;        [... ...]
;    )
;)

(define (draw-penguin world-num)
    (cond
        [(< world-num (- HEIGHT 50))
             (place-image FLOATING-PENGUIN
                          (/ WIDTH 2)
                          world-num
                          BACKDROP)]
        [else
             (place-image LANDED-PENGUIN
                          (/ WIDTH 2)
                          (- HEIGHT 50)
                          BACKDROP)]
    )
)

;========
; an INTERVAL is a kind of data where
;   branching is useful
;   *  you have a description of a set of numbers
;      described by its boundaries
;   *  you OFTEN have a clause/branch for each
;      interval;
;   *  you at least need to have a TEST for each
;      interval, and for each boundary between
;      intervals (and CAN add additional tests as
;      desired!)

;=========
;  another useful category of data where branching
;  is useful:
;  *   enumerations
;      *   when your data is relatively small
;          number of discrete, specific cases
;      *   a traffic light can be yellow, green, red
;      *   arrow keys on a computer are often
;          up, down, left, right
;      *   some multiple-choice tests have questions
;          whose answers are 1, 2, 3, or 4

; really, these are an informal "little" special
;    kind of data --
; we are going to make a DATA DEFINITION COMMENT
;    to make this clear
; (We'll write the names of these "new" data types
;    in CamelCase, to make clear they are "new",
;    but still data types)

; DATA DEFINITION:
; an AnimalSound is one of:
;     "moo", "baa", "la la la", "oink"
; (inspired by Sandra Boynton's "Moo, Baa, La La La")

; signature: next-sound: AnimalSound -> AnimalSound
; purpose: expects an animal sound, (as defined above),
;     and returns the "next" animal sound I should hear
;     based on the the beginning of
;     Sandra Boynton's "Moo, Baa, La La La":
;     *   "moo"? -> "baa"
;     *   "baa"? -> "la la la"
;     *   "la la la"? -> "oink"
;     *   "oink"? -> "moo"
; (if they give a NON animal sound, return "???")

;(define (next-sound an-animal-sound)
;  ...
;)

; when writing tests for functions involving
;    enumerations,
; you usually need a test for EACH possible value of
;    the enumeration, and often one more for
;    if the user gives a "bad" value;

(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 "arf")
              "???")



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

; for enumerations,
;    you often have a branch/clause for each possible
;    value, plus one for "bad" values;

;(define (next-sound an-animal-sound)
;    (cond
;        [... ...]
;        [... ...]
;        [... ...]
;        [... ...]
;        [... ...]                                   
;    )
;)

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

(next-sound "moo")

; what if big-bang had a string world instead of a number?

; I might want:

; signature: draw-string-world: string -> scene
; purpose: expects a world-string, and returns
;    a scene with that world-string in its center,
;    in blue 40-point letters

;(define (draw-string-world world-string)
;   ...
;)

(check-expect (draw-string-world "Hi!")
              (place-image
                  (text "Hi!" 40 "blue")
                  (/ WIDTH 2)
                  (/ HEIGHT 2)
                  BACKDROP))
(check-expect (draw-string-world "Lo!")
              (place-image
                  (text "Lo!" 40 "blue")
                  (/ WIDTH 2)
                  (/ HEIGHT 2)
                  BACKDROP))

(define (draw-string-world world-string)
   (place-image
       (text world-string 40 "blue")
       (/ WIDTH 2)
       (/ HEIGHT 2)
       BACKDROP)
)

; let's use draw-string-world and next-sound in
;     a big-bang expression...
; (note: on-tick clause has an optional 2nd argument,
;     how often (in seconds) to tick the ticker;
;     by default it tries to tick it every 1/28 second,
;     here I am asking it to tick every 1 second...)

(big-bang "moo"
          (to-draw draw-string-world)
          (on-tick next-sound 1))