How to have ball collide with bricks in Breakout (racket) - scheme

I've been trying to get Breakout to work in Racket, so far the ball bounces from the paddle (paddle is controlled by mouse) and the bricks are present
Here is the full on code:
(require 2htdp/image)
(require 2htdp/universe)
(define WIDTH 400)
(define HEIGHT 400)
(define BALL-RADIUS 10)
(define BALL-IMG (circle BALL-RADIUS "solid" "red"))
(define REC-WIDTH 50)
(define REC-HEIGHT 10)
(define REC-IMG (rectangle REC-WIDTH REC-HEIGHT "solid" "grey"))
(define BRICK-IMG0 (rectangle 60 30 "solid" "blue"))
(define BRICK-IMG1 (rectangle 60 30 "solid" "green"))
(define SCENE (empty-scene WIDTH HEIGHT))
(define STARTGAME
(text "CLICK TO START" 60 "purple"))
(define GAMEOVER
(text "GAMEOVER" 60 "red"))
(define-struct vel (delta-x delta-y))
; a Vel is a structure: (make-vel Number Number)
; interp. the velocity vector of a moving object
(define-struct ball (loc velocity))
; a Ball is a structure: (make-ball Posn Vel)
; interp. the position and velocity of a object
(define-struct rec (pos))
;
;
(define-struct brick (pos))
;
;
; Posn Vel -> Posn
; applies q to p and simulates the movement in one clock tick
(check-expect (posn+vel (make-posn 5 6) (make-vel 1 2))
(make-posn 6 8))
(define (posn+vel p q)
(make-posn (+ (posn-x p) (vel-delta-x q))
(+ (posn-y p) (vel-delta-y q))))
; Ball -> Ball
; computes movement of ball in one clock tick
(check-expect (move-ball (make-ball (make-posn 20 30)
(make-vel 5 10)))
(make-ball (make-posn 25 40)
(make-vel 5 10)))
(define (move-ball ball)
(make-ball (posn+vel (ball-loc ball)
(ball-velocity ball))
(ball-velocity ball)))
; A Collision is either
; - "top"
; - "down"
; - "left"
; - "right"
; - "none"
; interp. the location where a ball collides with a wall
; Posn -> Collision
; detects with which of the bricks the ball collides
;(check-expect (collision (make-posn 0 12)) "left")
;(check-expect (collision (make-posn 15 HEIGHT)) "down")
;(check-expect (collision (make-posn WIDTH 12)) "right")
;(check-expect (collision (make-posn 15 0)) "top")
;(check-expect (collision (make-posn 55 55)) "none")
(define (collision ball rec)
(cond
[(<= (posn-x ball) BALL-RADIUS) "left"]
[(<= (posn-y ball) BALL-RADIUS) "top"]
[(>= (posn-x ball) (- WIDTH BALL-RADIUS)) "right"]
[(>= (posn-y ball) (- HEIGHT BALL-RADIUS)) "GAMEOVER"]
[(and (>= (posn-x ball) (- (posn-x (rec-pos rec)) (/ REC-WIDTH 2)))
(<= (posn-x ball) (+ (posn-x (rec-pos rec)) (/ REC-WIDTH 2)))
(= (posn-y ball) (posn-y (rec-pos rec)))) "down"]
[else "none"]))
; Vel Collision -> Vel
; computes the velocity of an object after a collision
(check-expect (bounce (make-vel 3 4) "left")
(make-vel -3 4))
(check-expect (bounce (make-vel 3 4) "top")
(make-vel 3 -4))
(check-expect (bounce (make-vel 3 4) "none")
(make-vel 3 4))
(define (bounce vel collision)
(cond [(or (string=? collision "left")
(string=? collision "right"))
(make-vel (- (vel-delta-x vel))
(vel-delta-y vel))]
[(or (string=? collision "down")
(string=? collision "top"))
(make-vel (vel-delta-x vel)
(- (vel-delta-y vel)))]
[else vel]))
; WorldState is a Ball
; interp. the current state of the ball
; WorldState -> Image
; renders ball at its position
;(check-expect (image? (render INITIAL-BALL)) #true)
(define (render a-world)
(draw-ball (world-ball a-world)
(draw-bricklist (world-bricks a-world)
(draw-rect (world-rec a-world)))))
(define (draw-ball ball img)
(place-image BALL-IMG
(posn-x (ball-loc ball))
(posn-y (ball-loc ball))
img))
(define (draw-rect rec)
(place-image REC-IMG
(posn-x (rec-pos rec))
(posn-y (rec-pos rec))
SCENE))
(define (draw-bricklist list img)
[cond ((empty? list) img)
((cons? list) (draw-bricklist (rest list) (draw-brick (first list) img)))])
(define (draw-brick brick image)
(place-image (choice BRICK-IMG0 BRICK-IMG1)
(posn-x (brick-pos brick))
(posn-y (brick-pos brick))
image))
(define (choice a b )
(if (zero? (random 1)) a b ))
; WorldState -> WorldState
; moves ball to its next location
;(check-expect (tick (make-ball (make-posn 20 12) (make-vel 1 2)))
; (make-ball (make-posn 21 14) (make-vel 1 2)))
;(define (tick ball)
; (move-ball (make-ball (ball-loc ball)
; (bounce (ball-velocity ball)
; (collision (ball-loc ball))))))
(define (tick world)
(make-world (move-ball (make-ball (ball-loc (world-ball world))
(bounce (ball-velocity (world-ball world))
(collision (ball-loc (world-ball world))
(world-rec world)))))
(world-rec world)
(world-bricks world)))
(define (mouse world mouse-x mouse-y mouse-event)
(cond
[(string=? mouse-event "move") (make-world (world-ball world)
(make-rec (make-posn mouse-x REC-Y-POS))
(world-bricks world))]
[else world]))
(define INITIAL-BALL (make-ball (make-posn 20 12)
(make-vel 1 2)))
(define REC-Y-POS (- HEIGHT (+ 20 REC-HEIGHT)))
(define INITIAL-REC (make-rec (make-posn 100 REC-Y-POS)))
(define INITIAL-BRICKS (list
(make-brick (make-posn 50 100))
(make-brick (make-posn 111 100))
(make-brick (make-posn 172 100))
(make-brick (make-posn 233 100))
(make-brick (make-posn 294 100))
(make-brick (make-posn 355 100))
(make-brick (make-posn 50 131))
(make-brick (make-posn 111 131))
(make-brick (make-posn 172 131))
(make-brick (make-posn 233 131))
(make-brick (make-posn 294 131))
(make-brick (make-posn 355 131))
(make-brick (make-posn 50 162))
(make-brick (make-posn 111 162))
(make-brick (make-posn 172 162))
(make-brick (make-posn 233 162))
(make-brick (make-posn 294 162))
(make-brick (make-posn 355 162))))
(define-struct world (ball rec bricks))
(define INITIAL-WORLD-STATE (make-world INITIAL-BALL INITIAL-REC INITIAL-BRICKS))
(define (main state)
(big-bang state (on-mouse mouse) (on-tick tick 0.01) (to-draw render)))
(main INITIAL-WORLD-STATE)
The Ball just flies straight through the bricks. I've added this following code to it:
;--------------------------------------------------------------------------------------------------
(define (overlap?
brick-one-x brick-one-y brick-one-width brick-one-height
brick-two-x brick-two-y brick-two-width brick-two-height)
(cond
[(and
(and
(>= (+ brick-one-x brick-one-width) brick-two-x); within right bounds
(<= brick-one-x (+ brick-two-x brick-two-width)); within left bounds
)
(and
(>= (+ brick-one-y brick-one-height) brick-two-y) ;within top bounds
(<= brick-one-y (+ brick-two-y brick-two-height)) ; within bottom bounds
))
#t]
[else ;not overlapping
#f]))
(define (brick-collide-ball? brick ball)
(if
(overlap?
;balls dimensions and location
(posn-x (ball-loc ball))
(posn-y (ball-loc ball))
10
10
;first brick in list
(posn-x (brick-pos brick))
(- (posn-y (brick-pos brick)) 10)
60
30)
#t
#f))
(define (delete-bricks bricklist ball)
(cond
[(empty? bricklist) empty]
((cons? bricklist)
(if (brick-collide-ball? (first bricklist) ball)
(delete-bricks (rest bricklist) ball)
(cons (first bricklist)(delete-bricks (rest bricklist) ball))))))
;--------------------------------------------------------------------------------------------------------
but it does not seem to make an impact on anything. I'm stuck now and would appreciate any tips to improve!

I used the following in my version of the Atari classic:
(define (colliding? b1 b2)
(match-define (body x1 y1 w1 h1) b1)
(match-define (body x2 y2 w2 h2) b2)
(not (or (eq? b1 b2)
(< (+ x1 w1) x2) (> x1 (+ x2 w2))
(< (+ y1 h1) y2) (> y1 (+ y2 h2)))))
Here both the paddle and the ball is a "body", which is an rectangle
with and (x,y) position and a width, w, and a height h.
(struct body (x y w h) #:transparent)
Note: If you ball happens to move very fast, it can happen that it "jumps over" the paddle. This can be fixed by having a maximum velocity.

One way you might be able to address this problem without falling into a velocity-jump in the other answer is to calculate the intersection of the line along which the ball is currently traveling and the bounding line of (presumably the front of) the paddle. Then you just determine if this point is actually on the line segment of the paddle and the line segment between the ball's previous position and it's hypothetical position to determine if a collision would have happened "between" frames and handle that reflection. A more thorough check would be to do the same thing with the edge of the paddle since that game did allow the paddle to hit the ball from the side.
Example calculation:
#lang racket/base
(require racket/struct)
(struct line (a b c) #:transparent) ; ax+by=c
(struct pos (x y) #:transparent)
(define (meet l1 l2)
(let-values (((a b c) (apply values (struct->list l1)))
((d e f) (apply values (struct->list l2))))
(let ((denominator (- (* a e) (* b d))))
(if (zero? denominator)
'parallel ;probably impossible in your game
(let ((x* (- (* c e) (* b f)))
(y* (- (* a f) (* c d))))
(pos (/ x* denominator)
(/ y* denominator)))))))

Related

Programming Breakout with Racket

I'm trying to program the breakout game (https://www.youtube.com/watch?v=hW7Sg5pXAok) using DrRacket (BSL). I started by writing the code for the bar controlled by the player. The bar should move alongside with the mouse until following the x-Axis and stay immobile on the y-Axis. My code is the following, the bar is moving but the mouse-event doesn't seem to work, can you help debug it ?
(require 2htdp/universe)
(require 2htdp/image)
(define-struct playerState (locPlayer))
(define playerRectangle (rectangle 20 10 "solid" "red"))
(define playerScene (empty-scene 200 200))
; WorldState -> Image
; draws a player's state to an image
(check-expect (drawPlayer (make-playerState (make-posn 50 99))) (place-image playerRectangle 50 99 playerScene))
(define (drawPlayer state)
(place-image playerRectangle (posn-x (playerState-locPlayer state)) (posn-y (playerState-locPlayer state)) playerScene))
; WorldState -> WorldState
; computes a new player worldstate after a clock tick
(check-expect (tickPlayer (make-playerState (make-posn 50 99))) (make-playerState (make-posn 51 99)))
(define (tickPlayer state)
(make-playerState (make-posn (+ 1 (posn-x (playerState-locPlayer state))) (posn-y (playerState-locPlayer state)))))
; mouseEvent -> WorldState
; computes a new player worldstate if the mouse is moved
(define (mouse state x y mouse-event)
(cond [(string=? mouse-event "move")
(cond
[(> x (posn-x (playerState-locPlayer state))) (make-playerState (make-posn (+ 1 (posn-x (playerState-locPlayer state))) (posn-y (playerState-locPlayer state))))]
[(< x (posn-x (playerState-locPlayer state))) (make-playerState (make-posn (- 1 (posn-x (playerState-locPlayer state))) (posn-y (playerState-locPlayer state))))])]
[else (make-playerState (make-posn (posn-x (playerState-locPlayer state)) (posn-y (playerState-locPlayer state))))]))
(define (main state)
(big-bang state (to-draw drawPlayer) (on-mouse mouse) (on-tick tickPlayer)))
(define initialPlayer (make-playerState (make-posn 100 199)))
(main initialPlayer)
Some things i see here is your tick-handler. This does not need to update the players position if you want the mouse-handler to update the player position so for now you can take that out. From now on when you type i suggest you indent on every half screen, this makes it look more managed. Now the problem with your on-mouse handler is simple. While it is deciding which way you are moving the mouse it confuses itself and makes some really interesting decisions. At the same time if you were to start on the right-hand side of the screen and drag the mouse to the left it will result in an error. So to fix this i decided to do this.
(define (mouse state x y mouse-event)
(cond [(string=? mouse-event "move")
(make-playerState
(make-posn (- 200 x);200 is the width of the screen
(posn-y (playerState-locPlayer state))))]
[else state]))
All this does is give the reversed control to the player. That is what i interpreted, from playing what you had posted.

.Dynamically changing the clock tick rate in big-bang

The on-tick clause includes an option to change the clock tick rate. I have included my code to dynamically change the value depending on the world state value. The code is not working and I can't understand why. Another issue - how are world programs debugged? The "step" option doesn't work.
; physical constants
(define HEIGHT 300)
(define WIDTH 100)
(define YDELTA 3)
; graphical constants
(define BACKG (empty-scene WIDTH HEIGHT))
(define ROCKET (rectangle 5 30 "solid" "red"))
(define ROCKET-CENTER (/ (image-height ROCKET) 2))
(define ROCKET-XPOS 10)
; LRCD -> LRCD
(define (main1 s)
(big-bang s
[to-draw show]
[on-key launch]
[on-tick fly (clock-rate s)]))
; LRCD -> Image
; renders the state as a resting or flying rocket
(define (show x)
(cond
[(string? x) (rocket-ht HEIGHT)]
[(<= -3 x -1)
(place-image (text (number->string x) 20 "red")
ROCKET-XPOS (* 3/4 WIDTH)
(rocket-ht HEIGHT))]
[(>= x 0)
(rocket-ht x)]))
; LRCD -> image
; positions the rocket at correct height
(define (rocket-ht ht)
(place-image ROCKET ROCKET-XPOS (- ht ROCKET-CENTER) BACKG))
; LRCD KeyEvent -> LRCD
; starts the count-down when space bar is pressed,
; if the rocket is still resting
(define (launch x ke)
(cond
[(string? x) (if (string=? ke " ") -3 x)]
[else x]))
; LRCD -> LRCD
; raises the rocket by YDELTA,
; if it is moving already
(define (fly x)
(cond
[(string? x) x]
[(<= -3 x -1) (if (= x -1) HEIGHT (add1 x))]
[else (- x YDELTA)]))
(define (clock-rate s)
(cond
[(number? s) (if (< s 0) 1 1/28)]
[else 1/28]))

N-Queens does not return n amount of Queens

I am confused as to why the following Racket code doesn't produce a correct result. It works well for when n = 4 or 5, but for any result higher than this the function returns false. However, I know that there are solutions to some of these. Any help would be appreciated. The problem can be found here.
(define QUEEN (text "♛" 25 "black"))
(define SQR (square 30 "outline" "black"))
(define QNPEC (place-image QUEEN 15 15 SQR))
; QP is (make-posn CI CI)
; CI is a natural number in [0,8)
; interpretation a CI denotes a row or column index for a chess board,
; (make-posn r c) specifies the square in the r-th row and the c-th column
; QP QP -> Boolean
; determines whether or not a QP is threatened
; by another
(define (threatening? er nee)
(cond
[(= (posn-x er) (posn-x nee)) true]
[(= (posn-y er) (posn-y nee)) true]
[(diagonal? er nee) true]
[else false]))
(check-expect (threatening? (make-posn 1 0) (make-posn 4 3)) true)
(check-expect (threatening? (make-posn 1 0) (make-posn 1 3)) true)
(check-expect (threatening? (make-posn 3 54) (make-posn 9 54)) true)
(check-expect (threatening? (make-posn 3 55) (make-posn 9 54)) false)
; QP QP -> Boolean
; determines whether or not a QP is diagonal
; to another
(define (diagonal? er nee)
(cond
[(and (or (= (posn-x nee) (- (posn-x er)
(- (posn-y er) (posn-y nee))))
(= (posn-x nee) (+ (posn-x er)
(- (posn-y er) (posn-y nee)))))
(= (posn-y nee) (- (posn-y er)
(- (posn-y er) (posn-y nee))))) true]
[else false]))
(check-expect (diagonal? (make-posn 0 0) (make-posn 2 2)) true)
(check-expect (diagonal? (make-posn 1 0) (make-posn 4 3)) true)
(check-expect (diagonal? (make-posn 4 3) (make-posn 1 0)) true)
(check-expect (diagonal? (make-posn 12 0) (make-posn 4 3)) false)
(define (make-hgrid n i)
(cond
[(zero? n) empty-image]
[else (beside i (make-hgrid (sub1 n) i))]))
(define (make-vgrid n i)
(cond
[(zero? n) empty-image]
[else (above i (make-vgrid (sub1 n) i))]))
(define (make-sgrid n i)
(make-vgrid n (make-hgrid n i)))
; N [List-of QP] Image -> Image
; returns image of n-by-n chess board
(define (render-queens n l i)
(cond
[(empty? l) (make-sgrid n SQR)]
[else (local ((define F (first l))
(define IW (* (image-width SQR)))
(define PR (/ IW 2)))
(place-image i (+ (* (posn-x F) IW) PR)
(+ (* (posn-y F) IW) PR)
(render-queens n (rest l) i)))]))
; Set Set -> Boolean
; determines equivalence of sets
(define (set=? s1 s2)
(if (= (length s1) (length s2))
(andmap (lambda (x) (member? x s2)) s1)
false))
(check-expect (set=? '(a b c) '(c b a)) true)
(check-expect (set=? '(1 2 4) '(4 2 1)) true)
(check-expect (set=? '(1 2 3 4) '(a b c 1)) false)
; N -> [Maybe [List-of QP]]
; find a solution to the n queens problem
; data example:
(define 4QUEEN-SOLUTION-2
(list (make-posn 0 2) (make-posn 1 0) (make-posn 2 3) (make-posn 3 1)))
(define (n-queens n)
(local ((define MAIN (find-boards n)))
(cond
[(or (= n 2) (= n 3)) false]
[(= (length MAIN) n) MAIN]
[else false])))
; checks
(check-expect (n-queens-solution? 4 (n-queens 4)) true)
(check-expect (n-queens 2) false)
; N [List-of QP] -> Boolean
; determines whether or not a list of QP is an
; n-queens solution
(define (n-queens-solution? n l)
(cond
[(= (length l) n)
(local ((define (ds n l)
(cond
[(empty? l) true]
[else (or (ormap (lambda (x) (threatening? (first l) x)) l)
(ds n (rest l)))])))
(ds n l))]
[else false]))
(check-expect (n-queens-solution? 4 4QUEEN-SOLUTION-2) true)
(check-expect (n-queens-solution? 3 4QUEEN-SOLUTION-2) false)
; a Board is a [List-of Posn]
; N -> Board
; creates board
(define (make-board n)
(take-all-elems (build-list n (lambda (b) (build-list n (lambda (m) (make-posn m b)))))))
; checks
(check-expect (set=? (make-board 3)
(list (make-posn 0 0) (make-posn 1 0) (make-posn 2 0)
(make-posn 0 1) (make-posn 1 1) (make-posn 2 1)
(make-posn 0 2) (make-posn 1 2) (make-posn 2 2))) true)
; [List-of List] -> List
; inserts all elements of sublists into a single list
(define (take-all-elems l)
(foldr append empty l))
; Posn [List-of QP] -> Boolean
; determines whether a QP threatens any element in list
(define (threatens-list? e l)
(ormap (lambda (x) (threatening? x e)) l))
; checks
(check-expect (threatens-list? (make-posn 0 0)
(list (make-posn 0 0) (make-posn 1 0) (make-posn 2 0))) true)
(check-expect (threatens-list? (make-posn 0 0)
(list (make-posn 134 34) (make-posn 1 32) (make-posn 1292 39090))) false)
; N Posn -> [List-of QP]
; see n-queens
(define (find-boards n)
(local ((define BOARD (make-board n))
(define (trials l b)
(cond
[(empty? b) l]
[(empty? l) (trials (list (first b)) b)]
[(threatens-list? (first b) l) (trials l (rest b))]
[(not (threatens-list? (first b) l)) (trials (cons (first b) l) (rest b))]))
(define MAIN (trials empty BOARD)))
(cond
[(n-queens-solution? n MAIN) MAIN]
[else (trials empty (rest BOARD))])))
(define (render-n-queens n)
(render-queens n (n-queens n) QUEEN))

data definitions DrRacket?

I am having problem with this. It's quite long.
First, heres the data definition for this
(define-struct ball (x y color))
;; Ball = (make-ball Number Number Color)
;; Color is one of 'red, 'yellow, 'blue, etc.
Heres my program
(require 2htdp/image)
(require 2htdp/universe)
;;An LoB is one of
;;--empty
;;--(cons ball LoB)
;;(define (ball-template lob)
;; (cond
;; [(empty? lob) ...]
;; [else
;; (first lob)...
;; (ball-template (rest lob))]))
;;lob-length : LoB -> number
;;Counts the balls in the list
(define (lob-length lob)
(cond
[(empty? lob) 0]
[else
(add1 (lob-length (rest lob)))]))
;;Examples
(check-expect (lob-length empty) 0)
(check-expect (lob-length(cons (make-ball 1 2 "red")
(cons(make-ball 3 3 "blue")
(cons(make-ball 5 86 "white")empty))))3)
;;lob-draw : LoB -> Scene
;;Adds the balls to an empty scene in the form of circles
(define (lob-draw lob)
(cond
[(empty? lob) (empty-scene 300 300)]
[else
(place-image (circle 3 "solid" (ball-color (first lob)))
(ball-x (first lob))
(ball-y (first lob))
(lob-draw (rest lob)))]))
;;Examples
(lob-draw empty)
(lob-draw (cons (make-ball 50 60 "red")
(cons(make-ball 20 15 "blue")
(cons(make-ball 5 200 "black")empty))))
;;lob-member? LoB, ball -> boolean
;;Checks to see if the ball is in the list
(define (lob-member? lob b)
(cond
[(empty? lob) false]
[(same-ball? b (first lob)) true]
[else (lob-member? (rest lob) b)]))
;;Examples
(check-expect (lob-member? empty (make-ball 300 70 "blue"))
false)
(check-expect (lob-member? (cons (make-ball 30 70 "blue")
(cons (make-ball 310 500 "black")
(cons (make-ball 30 340 "yellow") empty)))
(make-ball 310 500 "black")) true)
;;same-ball? ball ball -> boolean
;;Compares two balls
(define (same-ball? b1 b2)
(and (= (ball-x b1) (ball-x b2))
(= (ball-y b1) (ball-y b2))
(string=? (ball-color b1) (ball-color b2))))
;;Example
(check-expect (same-ball? (make-ball 30 30 "white")(make-ball 30 30 "white"))
true)
(check-expect (same-ball? (make-ball 30 30 "white")(make-ball 23 40 "black"))
false)
Just a simple program where consume lists of balls, add them to empty scenes, count how many balls are on a given list, etc...
I've done everything but one thing. I have to design a function lob-yellow, which changes the color of all the balls in a list of Balls to yellow. I am guessing I need cond, but I am not sure how to. Any ideas?
Assuming that the struct is immutable, here are some hints to get you started, fill-in the blanks:
(define (lob-yellow lob)
(cond [<???> ; if the list is empty
<???>] ; return the empty list
[else ; otherwise,
(cons (make-ball ; cons a new ball, build it with:
(<???> (first lob)) ; the x coordinate of the first ball
(ball-y <???>) ; the y coordinate of the first ball
<???>) ; and always the yellow color
(lob-yellow <???>))])) ; recur over the rest of the list
But if the struct were defined like this:
(define-struct ball (x y color) #:mutable) ; now the struct is mutable
... We could implement a solution that modifies each ball in the list in-place:
(define (lob-yellow lob)
(cond [<???> ; if the list is empty
<???>] ; return the empty list
[else ; otherwise,
(set-ball-color! <???> 'yellow) ; set the color of the first ball
(lob-yellow <???>)])) ; recur over the rest of the list
I have filled in a little of your template.
(define (yellow-to-blue lob)
(cond
[(empty? lob) ...]
[else
(cond
[(symbol=? (first lob) 'yellow)
(cons ... (yellow-to-blue (rest lob)))]
[else (cons ... (yellow-to-blue (rest lob)))])]))
Remember to write some test cases before you fill out the dots.

Why can't I make two make function calls in function body?

So I'm going through the first chapter of How To Design Programs 2nd Edition. I believe I made pretty good progress. But there's a "suggestion" to add another graphic to the grid. Every time I try I get an error. At this point, I'm stuck. Below is the code and the error.
Note: the ROCKET image is in the Chapter 1. I just copy and pasted it into the IDE.
Note: The "suggestion" is: How would change the program so that the rocket lands on a flat rock bed that is 10 pixels higher than the bottom of the scene? Don’t forget to change the scenery, too.
HTDP Chapter 1
Here's code that works.
(define BOARDWIDTH 200)
(define BOARDHEIGHT 200)
(define STARTPOSITION 50)
(define BOARDBKGR "blue")
(define GAMEBOARD (empty-scene BOARDWIDTH BOARDHEIGHT BOARDBKGR))
(define ROCKET .)
(define UFO (overlay (circle 10 "solid" "red")
(rectangle 40 4 "solid" "green")))
(define FLATBED (rectangle 60 10 "outline" "black"))
(define (SPACESHIP option)
(cond
[(= option 1) ROCKET]
[(= option 2) UFO]))
(define SHOWNSHIP (SPACESHIP 1))
(define V 20) ;Velocity
(define A 1) ;Acceleration
(define (distance t) ;t = Time
(- (* V t) (* 1/2 A (sqr t))))
(define SPACESHIP-BOTTOM (- BOARDHEIGHT (/ (image-height SHOWNSHIP) 2)))
(define (render-shownship x y)
(place-image SHOWNSHIP x y GAMEBOARD))
(define (create-rocket-scene.v7 t)
(cond
[(<= (distance t) SPACESHIP-BOTTOM)
(render-shownship STARTPOSITION (distance t))]
[(> (distance t) SPACESHIP-BOTTOM)
(render-shownship STARTPOSITION SPACESHIP-BOTTOM)]))
Here's the code that doesn't work:
(define BOARDWIDTH 200)
(define BOARDHEIGHT 200)
(define STARTPOSITION 50)
(define BOARDBKGR "blue")
(define GAMEBOARD (empty-scene BOARDWIDTH BOARDHEIGHT BOARDBKGR))
(define ROCKET .)
(define UFO (overlay (circle 10 "solid" "red")
(rectangle 40 4 "solid" "green")))
(define FLATBED (rectangle 60 10 "outline" "black"))
(define (SPACESHIP option)
(cond
[(= option 1) ROCKET]
[(= option 2) UFO]))
(define SHOWNSHIP (SPACESHIP 1))
(define V 20) ;Velocity
(define A 1) ;Acceleration
(define (distance t) ;t = Time
(- (* V t) (* 1/2 A (sqr t))))
(define SPACESHIP-BOTTOM (- BOARDHEIGHT (/ (image-height SHOWNSHIP) 2)))
(define (render-shownship x y)
(place-image SHOWNSHIP x y GAMEBOARD)
(place-image FLATBED STARTPOSITION 195 GAMEBOARD)) ;offender
(define (create-rocket-scene.v7 t)
(cond
[(<= (distance t) SPACESHIP-BOTTOM)
(render-shownship STARTPOSITION (distance t))]
[(> (distance t) SPACESHIP-BOTTOM)
(render-shownship STARTPOSITION SPACESHIP-BOTTOM)]))
And the error I get is:
define: expected only one expression for the function body, but found
1 extra part
place-image always takes 4 arguments - the image to be placed, x and y coordinates, and the scene (background) on which to place the image. The problem in your code is that the expression (place-image FLATBED STARTPOSITION 195) is providing only 3 inputs to place-image.
So, back up a little and consider: what does the first expression produce? (place-image SHOWNSHIP x y GAMEBOARD) produces a game board scene with a ship on it, correct? Now on top of that scene you further want to place the FLATBED. So instead of sequencing the place-image function calls, instead consider composing them - i.e. what do you think the missing piece is in (place-image FLATBED STARTPOSITION 195 ____)? upon what scene do you want to place the FLATBED? (Hint: we just answered that above). What expression produces that scene? (hint: you already have that expression).
If you understand the idea, you see that to place multiple images on a scene, you compose or nest the function calls (instead of sequencing them as you are attempting):
(place-image img1 x1 y1 (place-image img2 x2 y2 ...))

Resources