scheme update a list of bullet location with location speed direction - scheme

I'm trying updates each bullet's location based on the bullets direction and speed for a list of bullets. And returns back the updated bullet list.
I think my code works logically but scheme gives me the error code
function call: expected a function after the open parenthesis,
but received (make-signature ...)
;; A Bullet is (make-bullet Posn Number Direction Number)
;; interpetation: represents a bullet, its current position,
;; its speed, its direction and its potential damage
(define-struct bullet (location speed direction damage))
;; A Direction is one of
;; - 'Up
;; - 'Down
;; - 'Left
;; - 'Right
;; a list of bullets(lob) is either
;; - empty
;; - (cons bullet lob)
;; A location is Lof[location]
;; A location is a Posn
;; move-bullets: lob -> lob
;; takes in a list of bullets and updates each bullet's location
;; based on the bullets direction and speed
(define (move-bullets lob)
(cond
[(empty? lob) empty]
[(cons? lob) (cons (create-new-bullet (first lob))
lob)]))
;; create-new-bullet: location direction speed-> location
;; takes in a list of bullets' location and create the "moved" bullet
;; base on given direction, speed
(define (create-new-bullet location dir speed)
(cond
[(symbol=? 'Up dir)
(make-posn (posn-x location) (- (posn-y location) speed))]
[(symbol=? 'Down dir)
(make-posn (posn-x location) (+ (posn-y location) speed))]
[(symbol=? 'Left dir)
(make-posn (- (posn-x location) speed) (posn-y location))]
[(symbol=? 'Right dir)
(make-posn (+ (posn-x location) speed) (posn-y location))]))
hummh. Anything goes wrong here???

You're passing a bullet as a parameter, so you need to extract each of its components. Try this:
(define (create-new-bullet bullet)
(let ((location (bullet-location bullet))
(speed (bullet-speed bullet))
(direction (bullet-direction bullet))
(damage (bullet-damage bullet)))
(cond
[(symbol=? 'Up direction)
(make-bullet
(make-posn (posn-x location) (- (posn-y location) speed))
speed direction damage)]
[(symbol=? 'Down direction)
(make-bullet
(make-posn (posn-x location) (+ (posn-y location) speed))
speed direction damage)]
[(symbol=? 'Left direction)
(make-bullet
(make-posn (- (posn-x location) speed) (posn-y location))
speed direction damage)]
[(symbol=? 'Right direction)
(make-bullet
(make-posn (+ (posn-x location) speed) (posn-y location))
speed direction damage)])))
Also, you forgot to advance the recursion:
(define (move-bullets lob)
(cond
[(empty? lob) empty]
[(cons? lob) (cons (create-new-bullet (first lob))
(move-bullets (rest lob)))]))

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.

How can I improve this auxilary function in Racket?

I'm working in HtDP, Chapter 4 using the BSL language.
The problem I was working on is:
Exercise 136: If you run main, press the space bar (fire a shot), and
wait for a good amount of time, the shot disappears from the canvas.
When you shut down the world canvas, however, the result is a world
that still contains this invisible shot.
Design an alternative tock function, which not just moves shots one
pixel per clock tick but also eliminates those whose coordinates
places them above the canvas. Hint: You may wish to consider the
design of an auxiliary function for the recursive cond clause.
The solution that I came up with is below (in a spoiler). However, I feel that I'm doing something redundant. Basically my application of the auxiliary function isn't quite correct.
(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]))
UPDATE:
(This is much cleaner than before)
(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 added:
I'm still working on the 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))))
TEST with world functions added:
(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))
The usual comments about missing contracts, purpose statements, and data definitions apply here. As well as tests of the individual functions; a big reason why world.ss/universe.ss are really nice libraries is that they enable one to test functions that are conceptually performing Input/Output.
I'm inferring a lot about what your data definition is from the code, but (1.) you should not put that onus on the reader, and (2.) it could lead to mistakes in my reasoning.
It looks to me like you have deviated significantly from the template in your definition of ticking; it does not look like any template I can think of. A similar comment applies to only-inbound-shots
You may want to break ticking up into multiple subroutines, and then compose them.
An example of what I mean by this: If you were to make a function to take the average of a list of numbers, a simple way to do it is to make two new functions: the first produces the sum of the numbers, and the second produces the length of the list; these are trivial to write via the Design Recipe. Then average is:
;; average : [Listof Number] -> Number
;; produces average value of input (x_1 x_2 ... x_n
(define (average l)
(/ (sum-of-list l) (length-of-list l)))
But if you were to try to do it in a single definition of average that followed the template for [Listof Number], you would have some problems getting the right answer. (I do not think it can be done properly without using an accumulator or two.)
That factoring into very simple subroutines and then composing them at the end to get the desired effect is what I mean by breaking ticking up and then composing the pieces. (If you're not destructuring your input, function composition is a perfectly valid design process: see HtDP section 3.1.)
More importantly, though, I think is to make some tests for the individual functions. Especially only-inbound-shots: I suggest you think about this function on its own.
Pretend that you don't know who might call it, and only that they will obey its contract (e.g. they will only pass in a World, whatever you defined that to be here).
And then make sure you produce the right answer for any possible legal input they provide.
Don't think about how you use it yourself in your other code above, because you don't want to try to keep all that in your head at the same time. Its actually simpler to generalize here, and think about what only-inbound-shots should do on any possible input.
To provide you with some concrete food for thought on the matter of testing, here are some hypothetical pictures describing the inputs you might try to handle in your tests:
, ,
Update 28 Feb 2013:
While I still recommend writing individual unit tests of each of your functions, end-to-end testing is also important. In this case, the game as currently rendered won't tell you if have shots lying outside the scene or not (because place-image, unlike say overlay, automatically crops them from the rendering).
So, if you want to debug the game while it is running, it can be useful to get that kind of information. Say like a drop down bit of text that renders on top of the game (one often sees this in video games to show you things like Frame Rate). So here is one strategy for getting that information out while the game is running: Swap in an alternative rendering function, that is layered on top of your existing one, but prints out other information about the world w0 argument.
(In this case, it might be useful to see its length, though one can imagine extracting other information.)
;; List-of-numbers -> Image
;; Renders w0 via to-render, with a printout of shot count in top left corner.
(define (to-render-with-count w0)
(place-image/align (text (number->string (length w0)) 30 'blue)
0 0 "left" "top"
(to-render w0)))
Then you hook in to-render-with-count in your big-bang invocation. It may also be useful to slow down the clock tick rate, so that you can see what happens as keystrokes and clock ticks are intermixed, so I have made that change too (in the on-tick clause):
(define (main w0)
(big-bang w0
(on-tick ticking 0.1)
(on-key fire-key)
(to-draw to-render-with-count)))
Now, I can interactively notice interesting trends. Trends that yield situations like this:
How is it that I have 148 balls on the screen but only four are showing? What kind of world would have that happen? (If you close the window created by big-bang, it will return the current world to the Interactions Window, so you will see right there exactly what kind of World would have that happen.)
I put the final answer here because the original question has a lot going on already.
(define HEIGHT 200) ;height of scene
(define WIDTH 80) ;width of scene
(define TURRET-X-POS (/ WIDTH 2)) ;position of turret, ie. where 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
;updates world state every clock tick
(define (ticking w0)
(cond
[(empty? w0) w0]
[else (remove-outbound-shots (update-shots w0) Y-BOUNDARY)]))
;List-of-numbers -> List-of-numbers
;updates all shots
(define (update-shots w0)
(cond
[(empty? w0) w0]
[else (cons (sub1 (first w0)) (update-shots (rest w0)))]))
;List-of-numbers -> List-of-numbers
;removes all shots exceeding the y-boundary from list
(define (remove-outbound-shots w0 y-boundary)
(cond
[(empty? w0) w0]
[(< (first w0) y-boundary) (remove-outbound-shots (rest w0) y-boundary)]
[else (cons (first w0) (remove-outbound-shots (rest w0) y-boundary))]))
;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-1
(cons 1 (cons 4 (cons 10 (cons -6 (cons -5 (cons 1 (cons 4 (cons 10 (cons 10 (cons -6 (cons -9 empty))))))))))))
(define test-shots-4
(cons 10 (cons -6 (cons -5 (cons 1 (cons 4 (cons 10 empty)))))))
(check-expect (remove-outbound-shots test-shots-4 -4) (list 10 1 4 10))
(check-expect (remove-outbound-shots test-shots-1 -4) (list 1 4 10 1 4 10 10))

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.

on-key in racket

(require 2htdp/image)
(require 2htdp/universe)
(define (render t)
(text (number->string t) 10 "red"))
(define (ball-image t)
(place-image (circle 10 "solid" "red")
150
150
(empty-scene 300 300)))
(define (change w a-key)
(cond
[(key=? a-key "left") (ball-image w)]
[(key=? a-key "right") (ball-image w )]
[(= (string-length a-key) 1) w]
[(key=? a-key "up") (ball-image w )]
[(key=? a-key "down") (ball-image w )]
[else w]))
(big-bang 100
(on-tick sub1 )
(to-draw ball-image)
(on-key change))
I am trying to get the red ball I have placed in the middle to move up, down, left, or right. When I press any of the arrow keys, it says it expects a number but given an image. What am I doing wrong?
First of all you need to understand how the world is processed in this main circle:
The system takes the first argument of big-bang - 100, and remembers it as a WorldState.
Then it passes it to a on-tick (sub1) function, provided it exists on each tick.
When the key is pressed, it calls on-key (change) and passes the woldState there, as a w argument.
There you draw some pictures and return it in case of an arrow key is pressed. So when an arrow is pressed, it returns the result of ball-image = result of place-image - image
The system remembers it as a current worldState,
and with the next tick, it passes the new value to the old procedure: sub1.
Since the value is now an image, sub1 rejects it.
--
If you want to move a ball in two directions, you have to store at least two coordinates (x . y). So let now the WorldState be the pair of two numbers. We don't need a on-tick function, since nothing changes on its own. Also we don't need to draw the ball in the keyboard processor, so let's simple change the corresponding value in the pair (worldState), and draw it only during the call (ball-image) which puts the ball into the new place (remember, x = (car t), y = (cdr t), and (x . y) = (cons x y)):
(require 2htdp/image)
(require 2htdp/universe)
(define (ball-image t) ;<-- the t-parameter is our WorldState
(place-image (circle 10 "solid" "red")
(car t) ;<-- here now x variable coordinate
(cdr t) ;<-- here now y variable, instead of 150
(empty-scene 300 300)))
(define (change w a-key)
(cond ;w - is the previous worldState, V here we change it
[(key=? a-key "left") (cons (sub1 (car w)) (cdr w))];and
[(key=? a-key "right") (cons (add1 (car w)) (cdr w))];return
[(= (string-length a-key) 1) w] ;<-- this line is excess
[(key=? a-key "up") (cons (car w) (sub1 (cdr w)))]
[(key=? a-key "down") (cons (car w) (add1 (cdr w)))]
[else w])) ;<-- If the key of no interest, just
return the previous WorldState
(big-bang '(150 . 150) ;<-- initial state
(to-draw ball-image) ;<-- redraws the world
(on-key change)) ;<-- process the event of key press

Spaceship Game in Scheme

The following Scheme code is about a game with a spaceship and right now it doesn't take into account when the spaceship runs out of fuel, which is what I'm trying to do. Here is the code:
;; this is the code for problem rrset -- Lunar Lander
(define (update ship-state fuel-burn-rate)
(make-ship-state
(+ (height ship-state) (* (velocity ship-state) dt)) ; height
(+ (velocity ship-state)
(* (- (* engine-strength fuel-burn-rate) gravity)
dt)) ; velocity
(cond (<= (fuel 0)
((write-line "no fuel left")
'game-over)
(else
(- (fuel ship-state) (* fuel-burn-rate dt)))))) ; fuel
(define (lander-loop ship-state)
(show-ship-state ship-state)
(if (landed? ship-state)
(end-game ship-state)
(lander-loop (update ship-state (get-burn-rate)))))
(define (show-ship-state ship-state)
(write-line
(list 'height (height ship-state)
'velocity (velocity ship-state)
'fuel (fuel ship-state))))
(define (landed? ship-state)
(<= (height ship-state) 0))
(define (end-game ship-state)
(let ((final-velocity (velocity ship-state)))
(write-line final-velocity)
(cond ((>= final-velocity safe-velocity)
(write-line "good landing")
'game-over)
(else
(write-line "you crashed!")
'game-over))))
(define (get-burn-rate)
(if (= (player-input) burn-key)
1
0))
(define (play) (lander-loop (initial-ship-state)))
(define (initial-ship-state)
(make-ship-state 50 ; 50 km high
0 ; not moving (0 km/sec)
20)) ; 20 kg of fuel left
(define dt 1) ; 1 second interval of simulation
(define gravity 0.5) ; 0.5 km/sec/sec
(define safe-velocity -0.5) ; 0.5 km/sec or faster is a crash
(define engine-strength 1) ; 1 kilonewton-second
(define (player-input)
(char->integer (prompt-for-command-char " action: ")))
(define burn-key 32) ;space key
(define (make-ship-state height velocity fuel)
(list 'HEIGHT height
'VELOCITY velocity
'FUEL fuel))
(define (height state) (second state))
(define (velocity state) (fourth state))
(define (fuel state) (sixth state))
(define (second l) (cadr l))
(define (fourth l) (cadr (cddr l)))
(define (sixth l) (cadr (cddr (cddr l))))
; Users of DrScheme or DrRacket: add these for compatibility with MIT Scheme...
(define (write-line x)
(display x)
(newline))
(define (prompt-for-command-char prompt)
(display prompt)
(read-char))
To modify it, I modified the "update" procedure, so now there is a conditional statement:
(define (update ship-state fuel-burn-rate)
(make-ship-state
(+ (height ship-state) (* (velocity ship-state) dt)) ; height
(+ (velocity ship-state)
(* (- (* engine-strength fuel-burn-rate) gravity)
dt)) ; velocity
(cond (<= (fuel 0)
((write-line "no fuel left")
'game-over)
(else
(- (fuel ship-state) (* fuel-burn-rate dt))))))
however this doesn't work.
You're going to want to add your conditional to the lander-loop procedure. This is the part of the code that checks whether the game is over each cycle.
(define (lander-loop ship-state)
(show-ship-state ship-state)
(if (or (landed? ship-state) (<= (fuel ship-state) 0))
(end-game ship-state)
(lander-loop (update ship-state (get-burn-rate)))))
Then you can add your out of fuel message to the end-game procedure.

Resources