Please send questions to st10@humboldt.edu .

; CS 131 - Week 3 Lab - 8 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 just be a steadily-increasing counter;
;    ...it COULD represent the current state of some "thing"
;    (the current temperature, or the happiness of a virtual pet,
;    or the current score of some game, or ...)
;
; (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 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 then 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 15,
;    and of the keystroke is "d", is decreases the world by 15,
;    and if it is any other key, the world is unchanged

; (note: string=? can compare 2 strings for equality;
;        = can only compare numbers...)

(define U-STEP 15)
(define D-STEP 15)

(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 25 "u") (+ 25 U-STEP))
(check-expect (affect-world 75 "d") (- 75 D-STEP))
(check-expect (affect-world 100 "x") 100)
(affect-world 25 "u")
(affect-world 75 "d")
(affect-world 100 "x")

; I also need a way to "draw" the world...
; my choice here is to take the world, and produce a scene that
;    is that number turned into a text-image of font size 36
;    and color red 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 font size 36 and color red

(define WIDTH 100)
(define HEIGHT 100)
(define BACKDROP (empty-scene WIDTH HEIGHT))

(define (draw-world-state world-state)
   (place-image (text (number->string world-state) 36 "red")
                           (/ WIDTH 2)
                           (/ HEIGHT 2)
                           BACKDROP)
)

(check-expect (draw-world-state 50)
              (place-image (text (number->string 50) 36 "red")
                           (/ WIDTH 2)
                           (/ HEIGHT 2)
                           BACKDROP))
(check-expect (draw-world-state 100)
              (place-image (text (number->string 100) 36 "red")
                           (/ WIDTH 2)
                           (/ HEIGHT 2)
                           BACKDROP))
(draw-world-state 50)

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

; note -- this check-expect was written BEFORE get-1-bigger's
;    body was filled in!

(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 want big-bang to stop when the world becomes negative --
;    I want 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 2 cases, and 1 for the boundary
;     (in this case, 0)

(check-expect (is-negative -2) true)
(check-expect (is-negative 85) false)
(check-expect (is-negative 0) false)

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

; we might decide we'd 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 as its initial world state, and then
;    it produces the final world state that big-bang produces
;    when it ends

(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 -3)