;=====
; CS 111 - Week 6 Lecture 2 - 2026-10-01

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

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

;=====
; COMPLETED template for a function that "walks through" a list
;
; *   "walks through"? Might need to do something involving or
;     to *each* element in a list of unknown size
;
; *   AFTER writing your tests for such a function,
;     (being SURE to include at least one test
;     with an empty list AND at least one with
;     a NON-empty list, and MORE if there are additional
;     cases),
;     *   PASTE this into your function body to help
;         in COMPLETING that function body:
;
; (define (a-list-funct ... a-list ...)
;     (cond
;         [(empty? a-list) ...]
;         [else (...
;                  ... (first a-list) ...
;                  (a-list-funct ... (rest a-list) ...) ...)]
;     )
; )

;=====
; NOTE: when a function CALLS itself,
;     like len does, and as this template does,
;     that function is called a RECURSIVE function
;
; IMPORTANT: a recursive function NEEDS:
; *   at least one BASE CASE -- at least one
;     branch that does NOT call itself, to serve as
;     a base, or ending point, for the repeated calls
;     to itself!
;
; *   each RECURSIVE CASE -- each branch that DOES call
;     itself -- needs to do so on a "smaller" version of
;     the given parameter,
;     such that, eventually, one of the base cases WILL be
;     reached

;=====
; a little more file input/file output
;     (file i/o)
; Racket's library for this: batch-io

(require 2htdp/batch-io)

;=====
; REMINDER
;-----
; 2htdp/batch-io has a selection of file input and file output functions
; (as would be needed for a so-called batch program, one with
;    no interactive input/output,
;    that reads its needed input from file(s) and writes its
;    resulting output to file(s)

;=====
; REMINDER
;=====
; signature: write-file: string string -> string
; purpose: expects the name of a file written as a string --
;     either its full/"absolute" name OR its name in the current
;         working directory --
;     AND the string to write to that file,
;     has the SIDE-EFFECT of trying to write that string
;     to that file, creating the file if necessary,
;         (and OVERWRITING its current contents if it exists),
;     and returns the *name* of the file it wrote

;-----
; REMINDER
;-----
; You can use \n to mean the newline character

(write-file "demo.txt"
            "Hello there!\nHow are you?\nI am fine!\n")

"====="
" You should now have a file demo.txt containing 3 lines of text."
"====="

;=====
; REMINDER
;=====
; signature: read-words: string -> list
; purpose: expects the name of a file written as a string --
;    either its full/"absolute" name OR its name in the current
;        working directory --
;    has the SIDE-EFFECT of trying to open and read the contents of
;        that file,
;    and returns the contents as a list of strings, with each
;        white-space-separated "token"/"word" being a string in this list

"====="
"You should see a list of the 'words' in demo.txt"
"====="

(read-words "demo.txt")

;=====
; Oh, you wanted a list of the LINES in a file?

;=====
; signature: read-lines: string -> list
; purpose: expects the name of a file written as a string --
;    either its full/"absolute" name OR its name in the current
;        working directory --
;    has the SIDE-EFFECT of trying to open and read the contents of
;        that file,
;    and returns the contents read as a list of strings,
;        each line in the file being one string in the result

"====="
"You should see a list of the lines in demo.txt"
"====="

(read-lines "demo.txt")

;=====
; Oh, you wanted a list containing lists of the "words"
;    in each line of a file?

;=====
; signature: read-words/line: string -> list
; purpose: expects the name of a file
;     written as a string,
;
;     has the SIDE-EFFECT of trying to open
;     and read the contents of that file, 
;     
;     and returns its contents as a list of
;     lists, one sub-list per line, with
;     the white-space-separated
;     "words"/chunks in that line as
;     strings in that line's list

"====="
"You should see a list of 3 lists, each containing the 'words'"
"    in one of the lines of demo.txt"
"====="

(read-words/line "demo.txt")

;=====
; Or, maybe you'd like a file's contents as one single string?
;    (with \n for newlines in that file?)

;=====
; signature: read-file: string -> string
; purpose: expects the name of a file
;     written as a string,
;
;     has the SIDE-EFFECT of trying to
;     open that file and read its contents,
;  
;     then returns the contents read as
;     a single string

"====="
" You should see ONE string with all of the contents of demo.txt"
"    (with \n for each newline)"
"====="

(read-file "demo.txt")

;=====
; I'd like to have a big-bang world that is
;     a list of images...
;
; And: I'd like those images be displayed randomly
;     in a scene each time big-bang draws its
;     world...

;-----
; some useful named constants

(define SC-WIDTH 300)
(define SC-HEIGHT 200)
(define BACKGRD (empty-scene SC-WIDTH SC-HEIGHT))

;=====
; IF I don't want just ONE never-changing scene,
;    I need EITHER an on-tick clause
;    or some OTHER handler clause that DOES change
;    the world;
; Here, I'd be happy if the world was UNCHANGED
;    each time big-bang's ticker ticks
;    (but still prompt big-bang to AGAIN call
;    its to-draw function to RE-draw the current
;    world value in a scene)

;-----
; I can get this by giving on-tick a function
;    that simply returns the current world
;    UNCHANGED...!!!

;=====
; signature: return-current: Anything -> Anything
; purpose: expects any expression with a value,
;     and returns its value

(check-expect (return-current 15) 15)
(check-expect (return-current #true) #true)

(define (return-current a-val)
   a-val
)

;=====
; to-draw in this case needs a function that'll
;    create a scene from a list of images,
;    placing each randomly into a scene

;=====
; signature: draw-images-randomly: list -> scene
; purpose: expects a list of images, and returns a
;    scene with those images placed at random
;    locations

;-----
; need at least two tests, and for a function expecting
;    a list of uncertain size,
;    one of those tests needs to be for an empty list!

(check-expect (draw-images-randomly empty)
              BACKGRD)

;-----
; for more-convenient testing...

(define SHAPE-TRIO
    (cons (circle 30 "solid" "purple")
          (cons (triangle 35 "outline" "darkgreen")
                (cons (square 50 "solid" "gray")
                      empty))))

SHAPE-TRIO

(check-random (draw-images-randomly SHAPE-TRIO)
      (place-image (first SHAPE-TRIO)
                   (random SC-WIDTH)
                   (random SC-HEIGHT)
                   (place-image
                      (second SHAPE-TRIO)
                      (random SC-WIDTH)
                      (random SC-HEIGHT)
                      (place-image
                          (third SHAPE-TRIO)
                          (random SC-WIDTH)
                          (random SC-HEIGHT)
                          BACKGRD))))
                   
(define (draw-images-randomly image-list)
     (cond
         [(empty? image-list) BACKGRD]
         [else (place-image
                  (first image-list)
                  (random SC-WIDTH)
                  (random SC-HEIGHT)
                  (draw-images-randomly (rest image-list)))]
     )
)

(draw-images-randomly SHAPE-TRIO)

"====="
"non-interactive version -- "
"    CLOSE the big-bang World window to continue!"
"====="

(big-bang SHAPE-TRIO
   (on-tick return-current 0.5)
   (to-draw draw-images-randomly))

;=====
; Another useful kind of thing to do with a list:
;
; a FILTER function - removes data from a set of
;    data (based on what you want)
; (get it? filter out what you don't want,
;          or, if you prefer,
;          filter to keep just what you want...)

;=====
; for example: say you want JUST the strings from
;    a list?

;=====
; signature: grab-strings: list -> list
; purpose: expects any list and returns a list of
;   JUST the strings from the given list. If the list
;   is empty or has no strings, returns the empty list.

;=====
; I'd like at least FOUR tests here...
; *   test on an empty list
; *   test on a list with NO strings
; *   test on a list with a MIX of strings and non-strings
; *   test on a list of ALL strings

(check-expect (grab-strings empty) empty)

(check-expect (grab-strings (list 1 2 3 4)) empty)

(check-expect (grab-strings (list "hi" 15 "wow" #true))
              (list "hi" "wow"))

(check-expect (grab-strings (list "hi" "hey" "bye"))
              (list "hi" "hey" "bye"))

(define (grab-strings a-list)
     (cond
         [(empty? a-list)  empty]

         ; if a-list is not empty, does it START with a string?
         
         [(string? (first a-list))
             (cons (first a-list)
                   (grab-strings (rest a-list)))]

         ; if reach here, a-list is NOT empty AND does not
         ;     START with a string
         
         [else
             (grab-strings (rest a-list))]
     )
)

(grab-strings (list "hi" 15 "wow" #true))

;=====
; STARTED a function for big-bang's on-key clause,
;     to allow us to ADD an image to a given list of images based
;     on a given keystroke
; HOPE to finish this Tuesday, Week 7 Lecture 1!

;;=====
;; signature: add-shape: list string -> list
;; purpose: expects a list of images and a shape key,
;;    either c or t or s, and returns a new list
;;    with a new first shape added to the given list
;;    as follows:
;;    for "c", 20-pixel solid randomly-colored circle
;;    for "t", 25-pixel solid randomly-colored triangle
;;    for "s", 25-pixel solid randomly-colored star
;;    and its nothing if given any other string
;
;; FINISH TUESDAY
;
;(check-random (add-shape SHAPE-TRIO "moo") SHAPE-TRIO)
;(check-random (add-shape empty "c") (list ))
;(check-random (add-shape ) ())
;(check-random (add-shape ) ())
;
;(define (add-shape image-list shape-key)
;    ...
;)
;