;=====
; CS 111 - Week 6 Lecture 2 - 2025-10-02

(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 --
;     as len does, as add1-list does,
;     and as the a-list-funct in the template above does --
;     that function is called a RECURSIVE function.
;
; *   It is VITAL that, in a recursive function:
;     *   it includes at least ONE branch that does NOT
;         call itself! (called a BASE case)
;     *   its recursive calls to itself are always on a
;         "SMALLER" version of the original parameter,
;         (such that, eventually, your repeated calls
;         WILL eventually reach one of the base cases!)

;====
; writing to a file?
; 2htdp/batch-io module includes ONE write function:

(require 2htdp/batch-io)

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

;=====
; FUN FACT: you can indicate a newline within a string
;    using the \n character
; (the default display of these in DrRacket's Interactions
;    window is as \n, BUT they WILL appear as newlines when
;    written to a file!)

"(don't worry, when written to a file the \n characters below"
"    are treated as newlines)"

"1\n2\n3"

"after running this, view the contents of the file sample.txt"

(write-file "sample.txt" "hello\n32")

;=====
; what if I want a big-bang expression whose
;    world is a list of IMAGES?
;
; and here, I want to make use of a function
; that takes a list of images and adds them
; randomly to a scene

;-----
; first: some useful named constants

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

;=====
; for this big-bang's on-tick clause -- well, we
;    don't want the world to change, in this case!
; so how about a function that just returns the
;    current world unchanged?

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

(check-expect (return-current 3) 3)
(check-expect (return-current empty) empty)

(define (return-current any-value)
    any-value
)

;=====
; signature: draw-images-randomly: list -> scene
; purpose: expects a list of images, and returns a scene
;    of those images centered 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-random (draw-images-randomly empty)
              BACKDROP)

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

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

(check-random
    (draw-images-randomly SHAPE-TRIO)
    (place-image (first SHAPE-TRIO)
                 (random SC-WIDTH)
                 (random SC-HEIGHT)
                 (draw-images-randomly (rest SHAPE-TRIO))))
                 
(define (draw-images-randomly image-list)
     (cond
         [(empty? image-list) BACKDROP]
         
         [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))

;=====
; what if: certain keystrokes could add shapes to this world?

;-----
; say: a "c" to add a circle, say with a 20-pixel radius?
;      a "t" to add a triangle, say with 25-pixel sides?
;      a "s" to add a star, say with 25 pixels between its points?
; say, randomly-colored?

;=====
; signature: add-shape: list string -> list
; purpose: expects a list of images and a shape key,
;    one of "c" or "t" or "s", and returns a new list
;    with a new first randomly-colored
;    shape added to the given list as follows:
;    *   for "c", it adds a 20-pixel-radius circle
;    *   for "t", it adds a 25-pixel-sided triangle
;    *   for "s", it adds a 25-pixels-between-its-points star
;    *   for any other key, it returns the given list unchanged

;-----
; since the newly-added shapes' sizes are constant...

(define CIRC-SIZE 20)
(define TRI-SIZE 25)
(define STAR-SIZE 25)

;=====
; have lists AND enumeration data here, but which are
;    "driving" this function's action?
; really, it is the enumeration data -- the shape key string;
; SO: need at least 4 tests here,
;    one for each of the 3 values in the enumeration,
;    and, because the function specifies what is desired for
;    a "bad" shape key value, need a test for that, also.

(check-random (add-shape empty "c")
              (cons (circle CIRC-SIZE "solid"
                            (make-color (random 256)
                                        (random 256)
                                        (random 256)))
                    empty))

(check-random (add-shape SHAPE-TRIO "t")
              (cons (triangle TRI-SIZE "solid"
                               (make-color (random 256)
                                           (random 256)
                                           (random 256)))
                    SHAPE-TRIO))

(check-random (add-shape (list (rectangle 25 30 "outline" "red")) "s")
              (cons (star STAR-SIZE "solid"
                          (make-color (random 256)
                                      (random 256)
                                      (random 256)))
                    (list (rectangle 25 30 "outline" "red"))))

;-----
; IMPROVED after class:
; because your tests SHOULD each have DIFFERENT argument values...

(define MULTI-RINGS (list (circle 10 "outline" "red")
                          (circle 10 "outline" "green")
                          (circle 10 "outline" "blue")
                          (circle 10 "outline" "black")))

(check-expect (add-shape MULTI-RINGS "g")
              MULTI-RINGS)

(define (add-shape img-list shape-key)
    (cond
        [(string=? shape-key "c")
            (cons (circle CIRC-SIZE "solid"
                            (make-color (random 256)
                                        (random 256)
                                        (random 256)))
                  img-list)]
        
        [(string=? shape-key "t")
            (cons (triangle TRI-SIZE "solid"
                               (make-color (random 256)
                                           (random 256)
                                           (random 256)))
                  img-list)]
        
        [(string=? shape-key "s")
            (cons (star STAR-SIZE "solid"
                          (make-color (random 256)
                                      (random 256)
                                      (random 256)))
                  img-list)]
        
        [else img-list]
    )
)

(add-shape (list (rectangle 25 30 "outline" "red")) "s")
(add-shape MULTI-RINGS "t")

"====="
"type c and/or t and/or s and see "
"   what happens!"
"====="

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