;; Moving a Ball in a Room with a Vertical Wall (2 variants) ;; ----------------------------------------------------------------------------- ;; DATA DEFINITION ;; --------------- (define-struct ball (x y dx dy)) ;; Ball = (make-ball Number Number Number Number) ;; interp. the (x,y) coordinate paired with the velocity (dx,dy) ;; CONSTANTS ;; --------- (define XWALL 40) ;; the wall is a line from (XWALL,YUP) to (XWALL,YLO) (define YUP 30) (define YLO (+ YUP 100)) ;; ----------------------------------------------------------------------------- ;; Ball -> Ball ;; move the ball and, if it hits the wall, bounce it ;; a simplistic auxiliary function for testing the move function (define (ball0 dy dx) (make-ball (- XWALL 10 dx) (+ YUP dy) 20 0)) ;; this ball bounces: (check-expect (move (ball0 +5 0)) (make-ball (- XWALL 10) (+ YUP 5) -20 0)) ;; this ball doesn't bounce: (check-expect (move (ball0 -5 0)) (make-ball (+ XWALL 10) (- YUP 5) +20 0)) ;; this ball would bounce if the move continued beyond one tick, but it doesn't: (check-expect (move (ball0 +5 15)) (make-ball (- XWALL 5) (+ YUP 5) 20 0)) (define (move b) (cond ;; ALTERNATIVE 1: [(hitwall? b) (reflect (straight b 1.))] [else (straight b 1.)])) ;; ALTERNATIVE 2: ;; an alternative solution uses this cond clauses instead of the first: ;; [(hitwall? b) (rst (ball-x b) (ball-y b) (ball-dx b) (ball-dy b) (where b))] ;; ----------------------------------------------------------------------------- ;; Ball -> Boolean ;; does the ball intersect with the vertical WALL as it travels from b to c? (check-expect (hitwall? (ball0 +5 0)) true) (check-expect (hitwall? (ball0 -5 0)) false) (check-expect (hitwall? (make-ball (- XWALL 20) (+ YUP 10) 5 0)) false) (define (hitwall? b) (and (<= YUP (where b) YLO) (or (<= (ball-x b) XWALL (+ (ball-x b) (ball-dx b))) (>= (ball-x b) XWALL (+ (ball-x b) (ball-dx b)))))) ;; ----------------------------------------------------------------------------- ;; Ball -> Ball ;; move the ball straight, regardless of the wall (check-expect (straight (make-ball 10 10 -5 5) 1.) (make-ball 5 15 -5 5)) (define (straight b delta) (make-ball (+ (ball-x b) (* delta (ball-dx b))) (+ (ball-y b) (* delta (ball-dy b))) (ball-dx b) (ball-dy b))) ;; ALTERNATIVE 1: use mathematical symmetry ;; ----------------------------------------------------------------------------- ;; Ball -> Ball ;; reflect the ball along the (vertical) wall, change its y coordinate (check-expect (reflect (make-ball (+ XWALL 5) YUP -10 5)) (make-ball (- XWALL 5) YUP +10 5)) (define (reflect b) (make-ball (- (* 2 XWALL) (ball-x b)) (ball-y b) (- (ball-dx b)) (ball-dy b))) ;; ALTERNATIVE 2: physically move to the ball, change direction, move rest ;; ----------------------------------------------------------------------------- ;; Ball -> Ball ;; the given ball moves to (XWALL,y), then bounces, then moves rest of the way (check-expect (rst (- XWALL 10) (+ YUP 5) 20 0 (+ YUP 5)) (make-ball (- XWALL 10) (+ YUP 5) -20 0)) (define (rst x y dx dy ywall) (straight (make-ball XWALL ywall (- dx) dy) (- 1 (/ (distance x y XWALL ywall) (distance x y (+ x dx) (+ y dy)))))) ;; ----------------------------------------------------------------------------- ;; Number Number Number Number -> Number ;; compute the distance between (x0,y0) and (x1,y1) (check-expect (distance 0 0 3 4) 5) (define (distance x0 y0 x1 y1) (sqrt (+ (sqr (- x0 x1)) (sqr (- y0 y1))))) ;; ----------------------------------------------------------------------------- ;; Ball -> Number ;; where does the line intersect the wall (we know that it does) (check-expect (where (make-ball (- XWALL 10) (+ YUP 5) 20 0)) (+ YUP 5)) (define (where A) (+ (* (/ (ball-dy A) (ball-dx A)) (- XWALL (ball-x A))) (ball-y A)))