[racket] use plot as render in universe

From: J G Cho (gcho at fundingmatters.com)
Date: Sun Aug 11 16:23:55 EDT 2013

Ouch. I just spent a better part of Friday trying to convince my colleague
to provide unit tests in one of his library. I have been under the
self-deception/illusion that I tend to test my codes. But I am willing to
accept that my test coverage was not enough in this case. I would be most
curious in hearing your professional opinion as to whether I have "enough"
tests for the given task here (the full code pasted below with the bug fix).

Also, it's not clear testing would have helped me in my earlier problem
since it did not occur to me that passing list of 1 vector to a plot
procedure was a NO-NO. (My bad I did not read the doc carefully of courese.
I tend to shoot-aim-shoot-aim... But was I that reckless to assume that
plot procedure might have put a dot on the screen given one data point
instead of throwing an error?) At the end of the day, I am willing to
concede that I should have tested rendering the initial world. Then the
question is how does one go about testing rendering a scene in a unit test?

#lang racket

(require (prefix-in p: plot)
         2htdp/image
         2htdp/universe
         test-engine/racket-tests)

;; World is a list of current price and
;; a list of all past prices in chronological order
(define initial-world
  (list 1 (list 1)))

;; World -> Number
(define (world-price world)
  (first world))

;; World -> [Number]
(define (world-prices world)
  (second world))

(check-expect (world-price initial-world) 1)
(check-expect (world-prices initial-world) (list 1))

;; -> Number in [-0.5, 0.5]
(define (random-btw-neg-half-and-pos-half)
  (- (random) 1/2))

(define (damper)
  1/100)

;; -> Number in [-0.5/100, 0.5/100] if damper returns 1/100
(define (step)
  (* (damper)
     (random-btw-neg-half-and-pos-half)))

;; World -> World
;; advances world by one more trading session
(define (random-walk world)
  (let* ((price (first world))
         (new-price (+ price (step))))
    (list new-price
          (append (second world)
                  (list new-price)))))

;; (Number n) =>'(1 (1)) -> (n (1 n))
(check-expect (length (world-prices (random-walk initial-world)))
              2)

;; World Decimal -> World
(define (market-shock world shock)
  (let* ((price (first world))
         (new-price (* price shock)))
    (list new-price
          (append (second world)
                  (list new-price)))))

(check-expect (world-price (market-shock initial-world 1.5))
              1.5)

;; world key-event? -> world
(define (shock world a-key)
  (cond
    [(key=? a-key "up")
     (market-shock world 1.25)]
    [(key=? a-key "down")
     (market-shock world 0.75)]
    [else world]))

;; World -> [#(Int Number)]
(define (world->list-of-vectors world)
  (for/list ((price (world-prices world))
             (i (in-naturals)))
            (vector i price)))

;; need to have at least 2 data points otherwise you are greeted by
;; plot: could not determine sensible plot bounds; got x ∈ [0,0], y ∈ [1,1]
(define (plot-render world)
  (if (< (length (world-prices world))
         2)
      (square 600 'solid 'black)
      (overlay
      (p:plot
       (p:lines
        (world->list-of-vectors world)))
      (square 600 'solid 'black))))

(define (sim init)
  (big-bang init
            (on-tick random-walk 1/2)
            (on-key shock)
            (to-draw plot-render)
            ))

(sim initial-world)



On Sun, Aug 11, 2013 at 3:58 PM, Matthias Felleisen <matthias at ccs.neu.edu>wrote:

>
> Tests your functions. Use Rackunit Luke.
>
> On Aug 11, 2013, at 3:40 PM, J G Cho wrote:
>
> Thanks for the assurance. It helped me to focus on my
> world->list-of-vectors It turns out it did not return enough vectors (at
> least 2, I think) for initial-world.
>
>
>
>
> On Sun, Aug 11, 2013 at 12:34 PM, Matthias Felleisen <matthias at ccs.neu.edu
> > wrote:
>
>>
>> On Aug 10, 2013, at 7:04 PM, J G Cho wrote:
>>
>> I get an error (somewhat expectedly) when I try
>>
>>   (big-bang init
>>             (on-tick random-walk 1)
>>             ;(on-key door-actions)
>>             (to-draw plot-render)
>>             ))
>>
>> where plot-render is defined as
>>
>> (define (plot-render world)
>>   (p:plot (p:lines
>>          (world->list-of-vectors world)
>>          #:color 6 #:label "Random walk")))
>>
>> with the following at the top
>>
>> (require (prefix-in p: plot))
>>
>> The error msg is
>>
>> plot: could not determine sensible plot bounds; got x ∈ [0,0], y ∈ [1,1]
>>
>> Is there way to let plot know of the context? Or pass a context to plot
>> and extract the pixels and hand it over to via some proc in 2htdp/image? Or
>> maybe there is a simple way?
>>
>>
>>
>> This works like a charm for me:
>>
>> #lang racket
>>
>> (require (prefix-in p: plot) 2htdp/universe)
>>
>> (define (plot-render world)
>>   (p:plot (p:lines (world->list-of-vectors world)
>>            #:color 6 #:label "Random walk")))
>>
>> (define (world->list-of-vectors world)
>>   `(#(1 3) #(2 -2) #(4 3)))
>>
>> (define (random-walk world)
>>   'more-dummy)
>>
>> (big-bang 'dummy ; init
>>           (on-tick random-walk 1)
>>           (to-draw plot-render))
>>
>> ;; ---
>>
>> When I had a student implement the first plot version, I intentionally
>> made sure that plot returned something I could use in big-bang.
>>
>> And btw, this works too:
>>
>> #lang racket
>>
>> (require (prefix-in p: plot) 2htdp/universe 2htdp/image)
>>
>> (define (plot-render world)
>>   (overlay
>>    (p:plot (p:lines (world->list-of-vectors world)
>>                     #:color 6 #:label "Random walk"))
>>    (square 800 'solid 'blue)))
>>
>> (define (world->list-of-vectors world)
>>   `(#(1 3) #(2 -2) #(4 3)))
>>
>> (define (random-walk world)
>>   'more-dummy)
>>
>> (big-bang 'dummy ; init
>>           (on-tick random-walk 1)
>>           (to-draw plot-render))
>>
>>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.racket-lang.org/users/archive/attachments/20130811/5db09309/attachment-0001.html>

Posted on the users mailing list.