;=====
; CS 111 - Recording for Week 7 Lecture 2 - 2024-10-10

(require 2htdp/image)
(require 2htdp/universe)
(require 2htdp/batch-io)

;=====
; DATA DEFINITION
; an Anything is an expression of any type

;=====
; DATA DEFINITION
; a list is one of:
;    - empty
;    - (cons Anything list)  ; cons for CONStruct a list


;==== TEMPLATE for a function that needs
;     to "walk through" all of the elements of a
;     variable-length list
;
; (define (my-list-funct ... my-list ...)
;     (cond
;         [(empty? my-list) ...]
;         [else
;             (... (... (first my-list) ...)
;                  (my-list-funct ... (rest my-list) ...) ...)]
;     )
; )

;===== COPYING from 111lect06-2-string-list-smush.rkt
;          recorded example =====

;=====
; signature: string-list-smush: list -> string
; purpose: expects any list of strings, and returns a single string
;    containing the strings from the given list each followed by a
;    newline character, \n

; since this should be able to handle a list of strings of any length,
;    I *NEEEEEED* to include tests for the empty-list case as well as
;    a non-empty-list case!

(check-expect (string-list-smush empty) "")

(check-expect (string-list-smush
                  (list "How" "are" "you?" "I" "am" "fine."))
              "How\nare\nyou?\nI\nam\nfine.\n")

(define (string-list-smush string-list)
     (cond
         [(empty? string-list) ""]
         [else
             (string-append
                  (first string-list)
                  "\n"
                  (string-list-smush (rest string-list)))]
     )
)

;=====
; from the Week 2 Lab Exercise:

;=====
; signature: say-hi: string -> string
; purpose: expects a person's name
;     and returns a personalized greeting to that person

(check-expect (say-hi "Jo")
              "Howdy, Jo!")

(check-expect (say-hi "Terry")
              "Howdy, Terry!")

(define (say-hi name)
   (string-append "Howdy, " name "!")
)

;=== end of part from Week 2 Lab Exercise

;=====
; I would like to greet everyone in a list of names!

;=====
; signature: make-greet-list: list -> list
; purpose: expects a list of strings that are names,
;    and returns a list of strings where each is
;    a personalized greeting to that name

(check-expect (make-greet-list empty) empty)

(check-expect
    (make-greet-list (list "Larry" "Bob" "Steve" "Grace"
                           "Tom" "Jerry"))
    (cons "Howdy, Larry!"
          (cons "Howdy, Bob!"
                (cons "Howdy, Steve!"
                      (cons "Howdy, Grace!"
                            (cons "Howdy, Tom!"
                                  (cons "Howdy, Jerry!" empty)))))))
                    
(define (make-greet-list name-list)
    (cond
       [(empty? name-list) empty]
       
       [else (cons (say-hi (first name-list))
                   (make-greet-list (rest name-list)))]
    )
)

;==== END of parts copied from 111lect06-2.rkt ====
;==== END of part copied from 111lect06-2-string-list-smush.rkt ====

;=====
; what if: what if I wanted a big-bang animation
;    where the initial world is a list of strings?

;=====
; I would need a function, to serve as big-bang's to-draw clause's argument,
;    that expects a list of strings and returns a scene somehow depicting those
;    strings

;-----
; hmmm... are many options!
; what if the scene has those strings depicted at random locations in that scene?

;-----
; I'd like some named constants to help me with this;

(define SC-WIDTH 1200)
(define SC-HEIGHT 600)
(define BACKDROP (empty-scene SC-WIDTH SC-HEIGHT))
(define STRING-SIZE 50)

;=====
; signature: draw-strings-randomly: list -> scene
; purpose: expects a list of strings, and returns
;    a scene with image-versions of those strings
;    in random colors placed at random locations

;----
; at least two tests! this should be able to handle an
;    empty list of strings, so be sure to include that as one
;    of your tests!

(check-expect (draw-strings-randomly empty)
              BACKDROP)

(define SOUND-TRIO (list "moo" "baa" "la la la"))

(check-random (draw-strings-randomly SOUND-TRIO)
              (place-image
                   (text "moo" STRING-SIZE (make-color (random 256)
                                                       (random 256)
                                                       (random 256)))
                   (random SC-WIDTH)
                   (random SC-HEIGHT)
                   (draw-strings-randomly (rest SOUND-TRIO))))

(define (draw-strings-randomly string-list)
     (cond
         [(empty? string-list) BACKDROP]
         [else
             (place-image
                  (text (first string-list) STRING-SIZE (make-color (random 256)
                                                                    (random 256)
                                                                    (random 256)))
                  (random SC-WIDTH)
                  (random SC-HEIGHT)
                  (draw-strings-randomly (rest string-list)))]
     )
)

(draw-strings-randomly SOUND-TRIO)

;====
; to make a reasonably-dynamic big-bang expression,
;    I also need a function for on-tick --
;    BUT because draw-strings-randomly, well, draws the strings randomly,
;    I *can* get away with a little function that expects a thing and returns
;    it unchanged...!

;====
; signature: return-current: Anything -> Anything
; purpose: expects any value, and simply returns it unchanged!

(check-expect (return-current 3) 3)
(check-expect (return-current SOUND-TRIO) SOUND-TRIO)

(define (return-current a-value)
    a-value
)

"calling big-bang with SOUND-TRIO"
"    (close world window when you are done)"

(big-bang SOUND-TRIO
    (to-draw draw-strings-randomly)
    (on-tick return-current 1))

"calling big-bang with the names in 111-names.txt"
"    (close world window when you are done)"

(big-bang (read-lines "111-names.txt")
    (to-draw draw-strings-randomly)
    (on-tick return-current 1))

"calling big-bang with the greetings in greetings.txt"
"    (close world window when you are done)"

(big-bang (read-lines "greetings.txt")
    (to-draw draw-strings-randomly)
    (on-tick return-current 1))

"calling big-bang with the word-chunks in greetings.txt"
"    (close world window when you are done)"

(big-bang (read-words "greetings.txt")
    (to-draw draw-strings-randomly)
    (on-tick return-current 1))

;=====
; what if I wanted keystrokes to affect my list of strings
;    (in a big-bang expression whose world is a list of strings?)
;
; note that adding to the beginning of a list is EASY with the cons
;    operation!

;=====
; signature: add-string: list string -> list
; purpose: expects a list of strings and a keystroke string,
;     and returns a new list with a new first string added that
;     is the keystroke string

(check-expect (add-string empty "c")
              (cons "c" empty))

(check-expect (add-string SOUND-TRIO "o")
              (cons "o" SOUND-TRIO))
              

(define (add-string string-list a-key)
    (cons a-key string-list)
)

"adding an on-key clause - type anything and see what happens!"
"    (close world window when you are done)"

(big-bang SOUND-TRIO
    (to-draw draw-strings-randomly)
    (on-tick return-current 1)
    (on-key add-string))

;=====
; what if I would like the option of REMOVING a value from a list?
; ...if the value removed is the FIRST value, the rest function make that easy!
;
; I can only have one on-key clause per big-bang, BUT I can write a function
;    with a cond that can behave based on what string was typed;
; SO: what if typing the down-arrow should REMOVE the first item in the given list,
;    and anything else gets added?

;=====
; signature: change-string-list: list string -> list
; purpose: expects a list of strings and a keystroke string, and
;     IF the keystroke string is "down", it returns the list of
;         everything EXCEPT the first thing in the given list,
;     OTHERWISE, it returns a new list whose first element is the
;         keystroke string followed by the elements in the given list

; two categories of keystrokes: "down" and everything else
; two categories of lists of strings: empty and everything else

; SO: 4 tests, to play it safe!

(check-expect (change-string-list empty "c")
              (cons "c" empty))

(check-expect (change-string-list SOUND-TRIO "f")
              (cons "f" SOUND-TRIO))

; note: I can't remove from an empty list!

(check-expect (change-string-list empty "down")
              empty)

(check-expect (change-string-list SOUND-TRIO "down")
              (rest SOUND-TRIO))

(define (change-string-list string-list a-key)
    (cond
        [(string=? a-key "down")
            (cond
                [(empty? string-list) empty]
                [else                 (rest string-list)]
            )]
        [else
            (cons a-key string-list)]
    )
)

" NOW using change-string-list for big-bang's on-key clause!"
"    THAT IS, now you can remove from the string world - "
"    type anything including the down-arrow key and see what happens!"
"    (close world window when you are done)"

(big-bang SOUND-TRIO
    (to-draw draw-strings-randomly)
    (on-tick return-current 1)
    (on-key change-string-list))

"and THIS version stops if the string world becomes empty:"
"    (close world window when you are done)"

(big-bang SOUND-TRIO
    (to-draw draw-strings-randomly)
    (on-tick return-current 1)
    (on-key change-string-list)
    (stop-when empty?))