on-key in racket - scheme

(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

Related

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

The compound object is not applicable

I'm writing a small plotting utility for MIT-Scheme. Source: [plotlib].
At the top level is the (make-plot output mode args) function that takes in an output device object, the plotting mode, and a list containing the parameters for the kind of plot specified in the mode.
I will use the function (range start stop increment) to generate lists from inclusive start to exclusive stop for each increment. (range -1 1 .1) creates the list (-1 -.9 -.8 ... .9).
make-plot works for its other modes, but does not work when called with 'vector-field-plot
(define window (make-graphics-device 'win32))
(define (vector-field-plot device color xrange yrange func)
(let* ((cords (append-all (map (lambda (i)
(map (lambda (j)
(cond ((eq? j '()) '())
(else (cons i j))))
xrange))
yrange)))
(input (map (lambda (point)
(list (car point) (cdr point)
(car (func (car point) (cdr point)))
(cdr (func (car point) (cdr point)))))
cords)))
(draw-vector-list device color input)))
;This is the part of make-plot that is called for
;(make-plot window 'vector-field-plot '(args))
((eq? mode 'vector-field-plot)
;does not work yet
(let* ((bg-color (car args))
(grid-color (cadr args))
(line-color (caddr args))
(xrange (car (cadddr args)))
(yrange (cadr (cadddr args)))
(func (cddr (cadddr args))))
(clear output bg-color);sets background to white
(coord-grid-cart output grid-color);prints Cartesian coordinate grid
(vector-field-plot output line-color xrange yrange func)))))
;calls vector-field-plot with parameters given to make-plot
;I have left out some function definitions here, they are in the source file
;but you can assume all of those work correctly for this section
One mode of make-plot prints vector fields, It calls the function (vector-field-plot output line-color xrange yrange func) With xrange and yrange being lists of numbers like '(-1 -.9 ... 1) and a func of the form (lambda (x y) (cons x y)). If I use:
(make-plot window 'vector-field-plot (list "white" "black" "red"
(list (range -1 1 .1) (range -1 1 .1)
(lambda (x y) (cons (* -.1 y) (* -.1 x))))))
It returns The object (#[compound procedure ]) is not applicable.
But if I use:
(vector-field-plot window "red" (range -1 1 .1) (range -1 1 .1)
(lambda (x y) (cons (* -.1 y) (* .1 x))))
It displays the correct plot (a circular vector field) in the graphics window.
The error is because the expression to get the function outside the list of arguments returns a list containing the function, not the function itself.
You should change:
(func (cddr (cadddr args))))
with:
(func (caddr (cadddr args))))
Jordan,
I am trying to resolve the LNK1168 error on Windows 10 that is identical to the one you described in a question a few months ago. I have no other way of contacting you, and since you've obviously coded since then, I assume you've fixed the issue.
What did you do to fix it?
Thanks

Drawing table/board in Racket

I'm trying to create a game whose name is "Same" in Racket 5.0.2 version.
Here is explanation of the game:
http://download.racket-lang.org/docs/5.0.2/html/games/same.html?q=games
I created a row and draw it:
a: width
b: height
r: radius
(define (color x) ///for random colors
(cond [(< (random x) 100) 'blue]
[(< (random x) 200) 'purple]
[(< (random x) 300) 'yellow]
[(< (random x) 400) 'red]
[else 'green]))
(define-struct top (coord color))
(define (row x y)
(if (> x (- a r)) empty
(cons (make-top (make-posn x y)(color 500)) (row (+ x (* 2 r)) y))))
(define (draw-row L)
(if (empty? L) #f
(and
(draw-solid-disk (top-coord (first L)) r (top-color (first L)))
(draw-row (rest L)))))
So I've got a top row included 20 disks with random colors. But I need 200 disks in 20 rows and 10 columns. So I created a board like this:
(define (board x y)
(if (> y (- b r)) empty
(cons (row x y) (board x (+ y (* 2 r))))))
But I couldn't draw it. I tried to create a function as "draw-row" but I got error.
So my question is: How can I draw this board?
You can draw a row, and a board is just a list of rows, so I would expect
(define (draw-board b)
(for-each draw-row b))
to Just Work.
Based on your comment, an example I would expect to work:
(draw-board (board 10 10))
and it does for me, at least.

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