Search code examples
schemerackethtdp

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


Solution

  • 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 ...))