Please send questions to st10@humboldt.edu .

; CS 131 - Week 3 Lab - 10 am

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

; today: adding the ability for keystrokes to affect our universes
; ...because handling keystrokes often involves using cond expressions

; so: the world doesn't have to be just a steadily-increasing counter;
;    it COULD represent the current state of some "thing",
;    (the current temperature, the happiness of a virtual pet,
;    the current score of some game, etc.)
;
; (next week, we'll work toward worlds that are MORE than just 1 number...)

; in the universe,
; a key-handler function expects the current state of the world
;    and something something representing a key press,
; and it produces the state of the world that should result from
;    that key press;
; strings are used to represent key presses in this universe;
;    a string of a single letter represents typing that key,
;    (and see documentation for other options, such as how up-arrow
;    keys are represented, etc.)

; you will give the name of this key-handler function to the
;    function on-key when you call big-bang so that that function
;    will be called on the current state of the world when you
;    type a key;

; simple example:
; signature: affect-world: number string -> number
; purpose: expects the current state of the world and a keystroke, 
;    and if the keystroke is "u", it increases the world by 80,
;    and if the keystroke is "d", it decreases the world by 40,
;    and if it is any other key, the world is unchanged

(define U-STEP 80)
(define D-STEP 40)

; note: = can only be used to compare numbers;
; string=? can compare two strings for equality;

(define (affect-world world-state a-key-stroke)
  (cond
    [(string=? a-key-stroke "u") (+ world-state U-STEP)]
    [(string=? a-key-stroke "d") (- world-state D-STEP)]
    [else world-state]
  )
)

(check-expect (affect-world 70 "u") (+ 70 U-STEP))
(check-expect (affect-world 100 "d")(- 100 D-STEP))
(check-expect (affect-world 200 "x") 200)
(affect-world 70 "u")
(affect-world 100 "d")
(affect-world 200 "x")

; I also need a way to "draw" the world...

; my choice here is to expect the world, and produce
;    a scene that is that number turned into a text-image
;    of font size 30 and color green centered in a scene

; signature: draw-world-state: number -> scene
; purpose: expects a world state, and produces a scene that
;    shows that world state centered in fonr size 30 and color green

(define WIDTH 75)
(define HEIGHT 75)
(define BACKDROP (empty-scene WIDTH HEIGHT))
(define WORLD-FONT-SIZE 30)

(define (draw-world-state world-state)
  (place-image
                  (text (number->string world-state) WORLD-FONT-SIZE "green")
                  (/ WIDTH 2)
                  (/ HEIGHT 2)
                  BACKDROP)
)

(check-expect (draw-world-state 100)
              (place-image
                  (text (number->string 100) WORLD-FONT-SIZE "green")
                  (/ WIDTH 2)
                  (/ HEIGHT 2)
                  BACKDROP))
(check-expect (draw-world-state 150)
              (place-image
                  (text (number->string 150) WORLD-FONT-SIZE "green")
                  (/ WIDTH 2)
                  (/ HEIGHT 2)
                  BACKDROP))
(draw-world-state 100)

;---------------
; signature: get-1-bigger: number -> number
; purpose: expects a number, and produces the number
;     that is 1 bigger

(define (get-1-bigger a-number)
  (+ a-number 1)
)

(check-expect (get-1-bigger 15) 16)
(get-1-bigger 45)

;(big-bang 100 
;          (on-tick get-1-bigger 1)
;          (on-draw draw-world-state)
;          (on-key affect-world))

; what if I would like big-bang to stop if/when the world reaches
;    a certain state?
; I can have a stop-when expression in big-bang whose value is the
;    name of a function, that expects the world and produces a boolean,
;    and big-bang will stop if, when called, this function produces true

; (I decide that) I want big-bang to stop if/when the world state becomes
;   negative;
; So, I need a function that produces true when the world-state is negative

; signature: is-negative: number -> boolean
; purpose: expects a number, and produces whether it is negative

(define (is-negative a-number)
  (< a-number 0)
)

; need at least 3 tests: one for each of the cases true and false,
;    and one for the boundary case (here, that is 0)

(check-expect (is-negative -3) true)
(check-expect (is-negative 6) false)
(check-expect (is-negative 0) false)

;(big-bang 100 
;          (on-tick get-1-bigger 1)
;          (on-draw draw-world-state)
;          (on-key affect-world)
;          (stop-when is-negative))

; we decide we might like to call big-bang more than once,
;    with different initial worlds;
; ...we can write a function to make this more convenient;

; because this starts up our world, when we specify an initial world,
;    we'll call this function main
;    (yes, sort of like main in C++ and Java)

; signature: main: number -> number
; purpose: expects a desired initial world state, and it calls
;    big-bang with that initial state (and my other options for
;    this little world), and then it produces the final world
;    state that big-bang produces when it ends.
; (oh yes, and as a side effect, it also start displaying the world!)

(define (main init-world-state)
  (big-bang init-world-state 
          (on-tick get-1-bigger 1)
          (on-draw draw-world-state)
          (on-key affect-world)
          (stop-when is-negative))
)

(check-expect (main -3) -3)

; for a top-level function like main, that starts up a larger program,
;    sometimes you can't write a complete set of check-expects...

(main 50)
(main 10)
(main -7)