我正在使用 BSL 语言在 HtDP 第 4 章中工作。
我正在处理的问题是:
练习 136:如果你运行 main,按下空格键(开枪),然后等待很长一段时间,镜头从画布上消失。但是,当您关闭世界画布时,结果是仍然包含这个不可见镜头的世界。
设计一个替代的 tock 函数,它不仅在每个时钟周期移动一个像素,而且还消除了那些坐标将它们放在画布上方的镜头。提示:您可能希望考虑为递归 cond 子句设计一个辅助函数。
我想出的解决方案如下(在剧透中)。但是,我觉得我在做一些多余的事情。基本上我对辅助功能的应用不太正确。
(define (main w0)
(big-bang w0
(on-tick ticking)
(on-key fire-key)
(to-draw to-render)))
(define HEIGHT 100)
(define WIDTH 80)
(define TURRET-X-POS (/ WIDTH 2))
(define BKGRND (empty-scene WIDTH HEIGHT))
(define SHOT-IMG (triangle 4 "solid" "red"))
(define (to-render w0)
(cond
[(empty? w0) BKGRND]
[else (place-image SHOT-IMG TURRET-X-POS (first w0) (to-render (rest w0)))]))
(define (fire-key w0 ke)
(cond
[(key=? ke " ") (cons HEIGHT w0)]
[else w0]))
(define (ticking w0)
(cond
[(empty? w0) empty]
[(empty? (only-inbound-shots w0)) empty]
[else (cons (sub1 (first (only-inbound-shots w0)))
(ticking (rest (only-inbound-shots w0))))]))
(define (only-inbound-shots w0)
(cond
[(< (first w0) -4) (rest w0)]
[else w0]))
更新:(
这比以前干净多了)
(define HEIGHT 100) ;height of scene
(define WIDTH 80) ;width of scene
(define TURRET-X-POS (/ WIDTH 2)) ;position of turret, ie. shot's x-coordinate
(define BKGRND (empty-scene WIDTH HEIGHT)) ; scene itself
(define SHOT-IMG (triangle 4 "solid" "red")) ;image representing the shot
(define Y-BOUNDARY -4) ;y-coordinate where shot is no longer visible in scene
;List-of-numbers -> List-of-numbers
;renders all shots fired
(define (to-render w0)
(cond
[(empty? w0) BKGRND]
[else (place-image SHOT-IMG TURRET-X-POS (first w0)
(to-render (rest w0)))]))
;List-of-numbers, key event -> List-of-numbers
;only allows the space bar to fire a shot
;one space bar event produces one shot
(define (fire-key w0 ke)
(cond
[(key=? ke " ") (cons HEIGHT w0)]
[else w0]))
;List-of-numbers -> List-of-numbers
;during each clock tick, the y-coordinate each of the shot
; in List-of-numbers is updated
;each y-coordinate decreases by -1
(define (ticking w0)
(cond
[(empty? w0) w0]
[else (only-inbound-shots (update-shots w0) Y-BOUNDARY)]))
;List-of-numbers -> List-of-numbers
;does the actual updating of the shots in List-of-numbers
;each shot's value is decreased by -1
(define (update-shots w0)
(cond
[(empty? w0) w0]
[else (cons (sub1 (first w0)) (update-shots (rest w0)))]))
;List-of-numbers -> List-of-numbers
;checks to see if the first shot in the List-of-numbers has gone past the Y-BOUNDARY
;if so then remove shot from the List-of-numbers and return the rest of the List
;otherwise return the List without change
(define (only-inbound-shots w0 y-boundary)
(cond
[(empty? w0) w0]
[(< (first w0) y-boundary) (rest w0)]
[else w0]))
;List-of-numbers -> List-of-numbers
;creates the world of shots
;seed value is empty, additional values created by space bar
(define (main w0)
(big-bang w0
(on-tick ticking)
(on-key fire-key)
(to-draw to-render)))
TESTS补充说:
我仍在进行测试。
(define test-shots
(cons -6 (cons -5 (cons 10 empty))))
(define test-shots-2
(cons -6 (cons 2 (cons 7 empty))))
(define test-shots-3
(cons 4 (cons 9 (cons 10 empty))))
(check-expect (to-render test-shots)
(place-image SHOT-IMG TURRET-X-POS -6
(place-image SHOT-IMG TURRET-X-POS -5
(place-image SHOT-IMG TURRET-X-POS 10
BKGRND))))
(check-expect (to-render test-shots-2)
(place-image SHOT-IMG TURRET-X-POS -6
(place-image SHOT-IMG TURRET-X-POS 2
(place-image SHOT-IMG TURRET-X-POS 7
BKGRND))))
添加了世界功能的测试:
(define HEIGHT 1) ; makes test a little faster
(check-expect
(fire-key
(ticking
(ticking
(ticking
(ticking
(fire-key
(ticking
(ticking
(ticking
(ticking (fire-key empty " ")))))
" ")))))
" ")
(cons -3 (cons 1 empty))