I'm doing a project for my Comp-160 class and my on-key function is doing something odd.
(define (KEY-PRESS W key)
(cond
[(key=? key "left") (make-MOVEB
(- 15 (MOVEB-x W))
(MOVEB-y W))]
[(key=? key "right") (make-MOVEB
(+ 15 (MOVEB-x W))
(MOVEB-y W))]))
For context my MOVEB is a structure which holds a position for a bucket to move left and right along the ground level of my scene. When I run this function it let's me move right with no problems but whenever I go left my bucket disappears or moves all the way back to the starting point.
Does anyone have any idea why this is happening?
I realize that this is probably way too late to matter, but when you say
(- 15 (MOVEB-x W))
That's like 15 - (MOVEB-x W); so if (MOVEB-x W) is 100, then this gives you -85, which is probably not what you wanted. You probably wanted (- (MOVEB-x W) 15).
Related
I'm making a function that adds or subtracts x and y from the original coordinates.This function accepts a command ("left", "right", "up", "down") an (x, y) position, and a non-negative distance and produces a new point moving according to the command and distance.It's like "left" x-num, "right" x+num, "down" y+num, "up" y-num. For example, if you start at (2, 3), the command "left" 1 should produce (1, 3), whereas "down" 2.2 would produce (2, 5.2). Each part might works, but how can I add them into one function.
This is my code:
(define POSN-0 (make-posn 5 5))
(define POSN-1 (make-posn 10 10))
(define POSN-2 (make-posn 20 20))
(define (shift-left p)
(make-posn (- (posn-x p) num)
(posn-y p)))
(define (shift-right p)
(make-posn (+ (posn-x p) num)
(posn-y p)))
(define (shift-up p)
(make-posn (posn-x p)
(- (posn-y p) num)))
(define (shift-down p)
(make-posn (posn-x p)
(+ (posn-y p) num)))
How can I add all this in one function? Also, how can I define the add/subtract number?
After your edit, it's a little bit more clear what do you want, so here is my try.
Anyway, when you work with specific language (BSL in this case), you should mention that in the question. This will lead to answers more useful to you.
And see also this similar question- it seems that you're both attendees of the same course, so I suggest you to join forces and next time, post one well-thought question and not two similar.
(define (shift command p dist)
(cond
((string=? command "left")
(make-posn (- (posn-x p) dist)
(posn-y p)))
((string=? command "right")
(make-posn (+ (posn-x p) dist)
(posn-y p)))
((string=? command "up")
(make-posn (posn-x p)
(- (posn-y p) dist)))
((string=? command "down")
(make-posn (posn-x p)
(+ (posn-y p) dist)))))
Examples:
> (define p0 (make-posn 2 3))
> (shift "left" p0 1)
(make-posn 1 3)
> (shift "down" p0 2.2)
(make-posn 2 5.2)
You most certainly can have multiple parameters to a given function, and indeed you can see this with such built-in functions as + and -, as well as in the constructor (make-point) (which takes the four parameters as currently defined).
Speaking of which, what are the xp and yp members of the point structure for? A point in 2-dimensional space only need two coordinates. What are the other two for? Also, the (define-struct) form is deprecated in favor of the (struct) form, but that's not really important here.
As for how you would implement the 'commands', assuming that you are referring to the (command-point) function, you would have a parameter for the operation, another for the distance to move, and a case analysis (e.g., a (cond) form, or series of (if) forms, or in this instance, a (case) form) switching on the given command. Something like the following (untested code, you'll probably need to make adjustments):
(define (command-point p cmd dist)
(case cmd
(`left (make-point (- (point-x1 p) 1) (point-y1 p) (point-xp p) (point-yp p)))
(`right (make-point (+ (point-x1 p) 1) (point-y1 p) (point-xp p) (point-yp p)))
(`fwd (make-point (point-x1 p) (- (point-y1 p) 1) (point-xp p) (point-yp p)))
(`back (make-point (point-x1 p) (+ (point-y1 p) 1) (point-xp p) (point-yp p)))))
Note that this doesn't change the point passed through p; it instead generates a new point structure.
I hope this is what you were looking for, as to be honest your question wasn't entirely clear.
I'm currently making a game where your character must dodge objects going on and off the scene.
My problem is that, when the objects go off the scene, they do not reappear on the other side.
Each object is represented by a posn structure, and they move a certain distance on the scene each time there's a tick from left to right and vise versa. I've attached which part of the code I think needs to be edited.
For clarity, a world is a struct containing a chicken and car, both of which are structs containing x and y posns.
And MOVE-CAR is a constant set to (add1 (random 49)) that determines how fast or slow the car will move during gameplay.
;update-world: world -> world
;purpose: updates the position of the car
(define (update-world a-world)
(make-world (world-chicken a-world) (move-horiz (world-car a-world) (* -1 MOVE-CAR))))
;move-horiz: posn number -> posn
;purpose: moves the posn left or right
(define (move-horiz a-posn delta-x)
(make-posn (+ delta-x (posn-x a-posn)) (posn-y a-posn)))
If more code is necessary, I will try and sift through the rest of what I have.
Any help is much appreciated.
To calculate the new x position, you are currently using:
(+ delta-x (posn-x a-posn))
If the result is between 0 and the width, this gives the correct result.
If the result is greater than the width, then the new x should be 0.
If the result is less than 0, then the new x should be the width.
Let's write a function adjust-x that adjusts the x-position you have calculated:
(define WIDTH 100)
(define (adjust-x x)
(cond
[(and (<= 0 x) (<= x WIDTH)) x]
[(> x WIDTH) 0]
[(< x 0) WIDTH]
Then you can change move-horiz to:
(define (move-horiz a-posn delta-x)
(make-posn (adjust-x (+ delta-x (posn-x a-posn)))
(posn-y a-posn)))
I'm learning common lisp I've been given a problem out of the uVA database (http://acm.uva.es/p/v101/10120.html) and a breadth search function (which takes in a start point, goal point and a legal move generator), i've got the theory down as to how i'm meant to get the answer but Lisp just isn't agreeing with me. Can i have some advice on how to proceed from this point onwards? Below is a link to the given problem and my two of my attempted solutions with lisp source code. Any help would be greatly appreciated! Thanks!
1.
(defun gift (N G)
(setq CR 9)
(setq i 3)
(cond ((= N G) "N and G equal")
((< N G) "Gift it on a rock outside limits")
((> N 49) "number of rocks is bigger than 49 - it will work")
((< N 9) "number of rocks is less than 9, it wont work")
((= N 0) "number of rocks is 0, it wont work")
((= G 0) "gift isn't on a rock, it wont work"))
(loop
(setq I (+ I 1))
(setq I (-(* I 2) 1))
(setq CR 9)
(breadth-search CR G #'lmg-moves)
(when (= CR G) (return "Let me Try!"))
(when (> CR N) (return "Don't laugh at me!"))
))
(defun lmg-moves (I)
(list (+ 9 I)
(- 9 I)
))
2.
(defvar *currentRock* 9)
(defvar *iterator* 3)
(defun gift (N G)
(setq *iterator* (+ *iterator* 1))
;; (breadth-search *currentRock* G #'LMG)
)
(defun LMG (a)
(+ a (-(* *iterator* 2) 1))
)
As can be seen above, the general idea is to simply apply a breadth-search function with the given legal move generator and hopefully, by analizing it's output we can determine whether we can reach the goal state or not. I will be glad to answer any questions if the code above is too confusing, thanks again!.
Among other potential issues:
You're using LOOP wrong. See PCL for info on loop. I've rehacked it a bit, but I don't know what you are attempting.
SETF is recommended over SETQ, as SETF is more general.
INCF increments a place by 1.
Your indentation is bad; if you fixed that you would notice that you're falling off the end of COND into the LOOP. I'd recommend an auto-indenting editor for using Lisp here. (Emacs is the standby).
(defun gift (N G)
(setq CR 9)
(setq i 3)
(cond ((= N G) "N and G equal")
((< N G) "Gift it on a rock outside limits")
((> N 49) "number of rocks is bigger than 49 - it will work")
((< N 9) "number of rocks is less than 9, it wont work")
((= N 0) "number of rocks is 0, it wont work")
((= G 0) "gift isn't on a rock, it wont work")) )
(loop
while t
do
(setq I (+ I 1))
(setq I (-(* I 2) 1))
(setq CR 9)
(breadth-search CR G #'lmg-moves)
(when (= CR G)
(return "Let me Try!"))
(when (> CR N)
(return "Don't laugh at me!"))))
There are some things that are immediately obvious:
You have exactly two legal return values, "Let me try!", and "Don't make fun of me!". You misspelt the first, rephrased the second, and added a lot of strings that do not have a use for the problem (are they meant as comments?).
The description calls the variables N and M, but your attempts take parameters N and G. Why confuse yourself? Either call them N and M, or (better) use meaningful names, like rock-number and gift-place.
Now, let's see your program structure.
(defun gift (N G)
(setq CR 9)
(setq i 3))
These setq instructions have undefined behaviour at this point, because CR and I are not defined yet. Many Lisp implementations will implicitly create globally special variables of these names, but it is bad style to depend on it. I have the impression that you want to use let here, like this:
(defun gift (rock-number gift-place)
(let ((current-rock 0)
(jump-number 0))
;; ...
))
Note that you should really start from the beginning, because you would miss the solution when the gift is on rock 1 or 4.
Next up, that cond form: it is dead code, because it has no side effects, and you throw away its return value immediately. It is thus at best a comment, and you should use a comment for that.
Finally, we have this funny loop:
(loop
(setq I (+ I 1))
(setq I (-(* I 2) 1))
(setq CR 9)
(breadth-search CR G #'lmg-moves)
(when (= CR G) (return "Let me Try!"))
(when (> CR N) (return "Don't laugh at me!"))))
I don't know what breadth-search does, but it seems that you really depend on the manipulation of globally special variables. I cannot say what might happen here. However, I can see several problems:
You can have up to two locations when jumping a certain distance from a given rock. It cannot be right to check only a single variable after each jump.
You seem to confuse the jump number with its jump distance. I goes in the sequence 1, 3, 7, 15 …, but the jump number sequence would be 1, 2, 3, 4 … while the jump distance sequence would be 1, 3, 5, 7 …. Even the rocks visited when always jumping right are a different sequence (1, 4, 9, 16 …).
You reset CR to 9 each time through the loop. I do not see how that could be right.
Stylistically, you should keep your variables as local as possible, using for example let, do, or the extended loop keywords :for and :with, then pass them into the functions that need them as arguments. This makes it much easier to reason about what is happening.
I think that your mental model of the solution algorithm is a bit confused. I would structure this in such a way that you loop over the jumps and keep a set of rocks that you can possibly be on after exactly this number of jumps. A special treatment for small N does not seem to really give a lot of efficiency gain. If you have a proof that N > 49 always has a solution, on the other hand, you should have a guard clause and a comment that outlines the proof.
My first steps with Lisp macros...
(defconstant width 7)
(defconstant height 6)
...
; board is a 2D array of width x height
; and this is my first ever macro:
(defmacro at (y x)
`(aref board ,y ,x))
; "board" must be available wherever the macro is used.
(defun foo (board ...)
...
(loop for y from 0 to (1- height) do
; thanks to the "at" macro, this is cleaner:
(let ((score (+ (at y 0) (at y 1) (at y 2))))
(loop for x from 3 to (1- width) do
(incf score (at y x))
; ...do something with score
(decf score (at y (- x 3)))))))
The code uses my first ever macro, the "at" one. It emits "access instructions" to read from board[y][x], so it can only be used in places where "board" exists, like the function "foo" above.
This worked - and then I realized that... I can go further.
The two nested loops are "statically" constrained: from 0 to height-1 for y, from 3 to (width-1) for x... so in theory, I can create a macro that emits (unrolls!) the exact incf and decf instructions done in the loops' code!
I tried this:
(defmacro unroll ()
(loop for y from 0 to (1- height) do
`(setf score (+ (at ,y 0) (at ,y 1) (at ,y 2)))
(loop for x from 3 to (1- width) do
`(incf score (at ,y ,x))
`(decf score (at ,y (- ,x 3))))))
...but failed - "(macroexpand-1 '(unroll))" shows me NIL.
What am I doing wrong?
In case it is not clear, I want to use two nested loops and emit "code" at the beginning of the outer loop, and for each iteration of the inner loop.
Any help most appreciated (I am a LISP newbie).
UPDATE: After #larsmans' kind advice, I succeeded in applying this change to my code - and to my immense satisfaction, I watched the Lisp version of my Score4 algorithm become the 2nd fastest implementation, behind only C and C++ (and faster than OCaml!).
You should collect the statements you generate inside the macro's loop, not pretend to execute them with do:
(defmacro unroll ()
(loop for y from 0 to (1- height)
collect
`(begin (setf score (+ (at ,y 0) (at ,y 1) (at ,y 2)))
,#(loop for x from 3 to (1- width)
collect `(begin (incf score (at ,y ,x))
(decf score (at ,y (- ,x 3))))))))
I have some code which collects points (consed integers) from a loop which looks something like this:
(loop
for x from 1 to 100
for y from 100 downto 1
collect `(,x . ,y))
My question is, is it correct to use `(,x . ,y) in this situation?
Edit: This sample is not about generating a table of 100x100 items, the code here just illustrate the use of two loop variables and the consing of their values. I have edited the loop to make this clear. The actual loop I use depends on several other functions (and is part of one itself) so it made more sense to replace the calls with literal integers and to pull the loop out of the function.
It would be much 'better' to just do (cons x y).
But to answer the question, there is nothing wrong with doing that :) (except making it a tad slower).
I think the answer here is resource utilization (following from This post)
for example in clisp:
[1]> (time
(progn
(loop
for x from 1 to 100000
for y from 1 to 100000 do
collect (cons x y))
()))
WARNING: LOOP: missing forms after DO: permitted by CLtL2, forbidden by ANSI
CL.
Real time: 0.469 sec.
Run time: 0.468 sec.
Space: 1609084 Bytes
GC: 1, GC time: 0.015 sec.
NIL
[2]> (time
(progn
(loop
for x from 1 to 100000
for y from 1 to 100000 do
collect `(,x . ,y)) ;`
()))
WARNING: LOOP: missing forms after DO: permitted by CLtL2, forbidden by ANSI
CL.
Real time: 0.969 sec.
Run time: 0.969 sec.
Space: 10409084 Bytes
GC: 15, GC time: 0.172 sec.
NIL
[3]>
dsm: there are a couple of odd things about your code here. Note that
(loop for x from 1 to 100000
for y from 1 to 100000 do
collect `(,x . ,y))
is equivalent to:
(loop for x from 1 to 100
collecting (cons x x))
which probably isn't quite what you intended. Note three things: First, the way you've written it, x and y have the same role. You probably meant to nest loops. Second, your do after the y is incorrect, as there is not lisp form following it. Thirdly, you're right that you could use the backtick approach here but it makes your code harder to read and not idiomatic for no gain, so best avoided.
Guessing at what you actually intended, you might do something like this (using loop):
(loop for x from 1 to 100 appending
(loop for y from 1 to 100 collecting (cons x y)))
If you don't like the loop macro (like Kyle), you can use another iteration construct like
(let ((list nil))
(dotimes (n 100) ;; 0 based count, you will have to add 1 to get 1 .. 100
(dotimes (m 100)
(push (cons n m) list)))
(nreverse list))
If you find yourself doing this sort of thing a lot, you should probably write a more general function for crossing lists, then pass it these lists of integers
If you really have a problem with iteration, not just loop, you can do this sort of thing recursively (but note, this isn't scheme, your implementation may not guaranteed TCO). The function "genint" shown by Kyle here is a variant of a common (but not standard) function iota. However, appending to the list is a bad idea. An equivalent implementation like this:
(defun iota (n &optional (start 0))
(let ((end (+ n start)))
(labels ((next (n)
(when (< n end)
(cons n (next (1+ n))))))
(next start))))
should be much more efficient, but still is not a tail call. Note I've set this up for the more usual 0-based, but given you an optional parameter to start at 1 or any other integer. Of course the above can be written something like:
(defun iota (n &optional (start 0))
(loop repeat n
for i from start collecting i))
Which has the advantage of not blowing the stack for large arguments. If your implementation supports tail call elimination, you can also avoid the recursion running out of place by doing something like this:
(defun iota (n &optional (start 0))
(labels ((next (i list)
(if (>= i (+ n start))
nil
(next (1+ i) (cons i list)))))
(next start nil)))
Hope that helps!
Why not just
(cons x y)
By the way, I tried to run your code in CLISP and it didn't work as expected. Since I'm not a big fan of the loop macro here's how you might accomplish the same thing recursively:
(defun genint (stop)
(if (= stop 1) '(1)
(append (genint (- stop 1)) (list stop))))
(defun genpairs (x y)
(let ((row (mapcar #'(lambda (y)
(cons x y))
(genint y))))
(if (= x 0) row
(append (genpairs (- x 1) y)
row))))
(genpairs 100 100)