Problem with Recursion in my program?

BlitzMax Forums/BlitzMax Programming/Problem with Recursion in my program?

Rico(Posted 2008) [#1]
I'd be really grateful if someone would give me some help. I am wrting a test program, that allows you to push blocks around a screen, but unfortunately it doesn't quite work, and I'm not sure why. I'm sure its something obvious but I can't see it and I was hoping someone else would be able to help. Is there a realtime debugger in Max, because that would be really useful. I looked on help, but it doesn't mention anything.
Here's the program if someone wouldn't mind running it. You control the white square with the 'z','x',':' and '.' keys (left/right/up/down) and you can push the other blocks around the screen.
You can also pick up the blocks with the mouse (left mouse button) and put them somewhere else (right mouse button to drop). Anyway its a bit clunky but I'm just trying to get something simple working at the moment.
The problem comes when you try to push a red block onto a yellow block. Red and yellow are objects 2 and 3 in the list, so I presume that this may be something to do with why this isn't working. Other combinations all seem to work as far as I can tell.
Please help - heres the code - you can run it because it creates its own gfx. Thank you! (I just cut and pasted this so it may lose some identing - I don't know how to do it properly - sorry)

Rico

-----------------------CODE BELOW-----------------

Graphics 1024,768,16

'--------------
DrawRect 0,0,128,32

image:TImage=CreateImage(32,32) 'square block
image2:TImage=CreateImage(4,4) 'pointer
GrabImage(image,0,0,0)
GrabImage(image2,0,0,0)

Cls
SetBlend SOLIDBLEND

Type block
Field x,y,xv,yv,id
EndType

Global block_list:TList= New TList
Global num_block=4
Global p:block
Global ir=0

For m=1 To num_block
b:block=New block
ReadData b.id,b.x,b.y,b.xv,b.yv
If b.id=1 Then p=b 'player block set to first object
block_list.addlast b
Next

Global sel:block=Null

gr=0;drwpt=True

While Not KeyDown(KEY_ESCAPE)

Cls
mx=MouseX();my=MouseY()
lb=MouseDown(1);rb=MouseDown(2)

DrawText " px "+p.x+" py "+p.y,0,0
If sel=Null Then ps=0 Else ps=1
DrawText " lb "+lb+" sel "+ps,0,16


lk=KeyDown(KEY_Z);rk=KeyDown(KEY_X)
uk=KeyDown(KEY_SEMICOLON);dk=KeyDown(KEY_PERIOD)


'------mouse selection and player movement

For b=EachIn block_list
If lb And sel=Null
hit=ptinrect(mx,my,b.x,b.y,b.x+31,b.y+31)
If hit
sel=b
xoff=mx-b.x ; yoff=my-b.y
EndIf
EndIf
If rb And sel=b
b.x=b.x-xoff;b.y=b.y-yoff
xoff=0;yoff=0
sel=Null
EndIf

If b=sel Then b.x=mx;b.y=my;drwpt=False
b.xv=0;b.yv=0
If b=p
b.xv=0;b.yv=0
If lk Then b.xv=-1
If rk Then b.xv=1
If uk Then b.yv=-1
If dk Then b.yv=1
EndIf
Next

'--------- collision detection

ir=0
For b=EachIn block_list
If b<>sel Then moveobject(b)
Next

'------draw images

If drwpt Then DrawImage image2,mx,my,0 ' draw mouse pointer
c=0
For b=EachIn block_list
c=c+1
Select c 'draw each block a different colour
Case 1 SetColor 255,255,255
Case 2 SetColor 255,0,0
Case 3 SetColor 255,255,0
Case 4 SetColor 0,0,255
EndSelect
If sel=b

DrawImage image,b.x-xoff,b.y-yoff,0
Else

DrawImage image,b.x,b.y,0
EndIf
Next
SetColor 255,255,255

Flip 1
Wend

End

Function moveobject(bl:block)
Local cond=True
Local b2:block=New block
ir=ir+1

For b2=EachIn block_list
If b2<>bl And b2<>sel
nx=bl.x+bl.xv; ny=bl.y+bl.yv
nbx=b2.x+b2.xv; nby=b2.y+b2.yv

If rectsoverlap(nx,ny,31,31,nbx,nby,31,31)
b2.xv=bl.xv;b2.yv=bl.yv
cond=moveobject(b2)
EndIf

EndIf
Next
bl.x=bl.x+bl.xv; bl.y=bl.y+bl.yv
b2=Null
If ir>60 Then Print "Infinite Recursion? ";End
Return cond
End Function

Function rectsoverlap:Int(x0,y0,w0,h0,x2,y2,w2,h2)
If x0>(x2+w2)Or(x0+w0)<x2 Then Return False
If y0>(y2+h2)Or(y0+h0)<y2 Then Return False
Return True
End Function

Function ptinrect:Int(px,py,x0,y0,x2,y2)
If px>x0 And px<x2 And py>y0 And py<y2 Then Return True
Return False

End Function



DefData 1,60,400,0,0
DefData 2,100,100,0,0
DefData 3,99,200,0,0
DefData 4,132,300,0,0
DefData 5,160,330,0,0
DefData 6,192,500,0,0


Jesse(Posted 2008) [#2]
I can help you but I am not going to look at this code unless you:
1 use minimum strict preferably superstrict.
2 use code or codebox when posting your code.

I think those two should be a standard for anybody asking for help and posting code.
plus strict/superstrict helps solve a lot of stupid bugs at first glance.
use forum codes when posting.

Excuse me if I sound a bit unkind but most programmers here have an agenda of their own. And if they are going to take time of their busy schedule, be at least courteous and try to make it as easy as posible for others to make sence out of the chaos being posted.


jkrankie(Posted 2008) [#3]
superstrict the code and you'll probably find your problem.

Cheers
Charlie


plash(Posted 2008) [#4]
http://www.blitzbasic.com/faq/faq_entry.php?id=2


grable(Posted 2008) [#5]
To solve the recursion problem you could use a global stack.

if you stick this at the beginning of moveobject():
Global stack:TList = New TList
If stack.Contains(bl) Then Return
stack.AddLast(bl)
And this at the end before the return statement:
stack.RemoveLast()

But im sure there is a better way, thats just the first thing i tried ;)


Damien Sturdy(Posted 2008) [#6]
Yes, Blitzmax exits without error when you stack overflow.

I implement my own stack when i have that problem, Tstack, which is essentially just a list with methds PUSH and POP.


Rico(Posted 2008) [#7]
Hopefully this will post ok. BTW when you need to define a load of integers say is there a quicker way of doing it rather than:

Global a:int,b:int,c:int,d:int,e:int,f:int

e.g. Global a,b,c,d,e,f :int

Here's my code again (it still has the same problem but only with those colour boxes, please help. Thank you)



Bye! - Rico


Jesse(Posted 2008) [#8]
you should have listened to gravel and Cygnus. They know what they are talking about.



also pay attention to your infinite recursion check. don't guess.
it should be n^3 in this case 4^3 = 64 -YIKES! 64 times just for four objects. There must be a better way.

now all you need to do is sort the objects. :)


Beaker(Posted 2008) [#9]
Quicker way:
Global a%,b%,c%,d%,e%,f%


Rico(Posted 2008) [#10]
Jesse - I'm not ignoring anyone - I am not a very experienced coder and I don't undertstand. I just wanted an explanation really of why I can push all the boxes around ok, apart from that particular combination. It must be something stupid I've done. Can you explain it to me in simpler terms. Thanks.
I *think* I understand the stack you have implemented, but I'm not sure. Is it to stop the possibility of infinite recursion? If it is isn't this just damage limitation rather than solving the actual problem with the underlying code?
Also why do you global the list in the function, rather than outside it ?(at the begining of the program).
Your program works better but some of the blocks get stuck to each other at times (the same combination of blocks - push red into yellow from above or below), which shouldn't happen.
Thanks you Jesse and everyone else for the help. - Rico


Jesse(Posted 2008) [#11]
Rico, although I have used recursion before I am not that familiar with that method of stack implementation. The best to explain it to you are Cygnus or grable, I believe it's to prevent from checking the same object more than once. "don't quote me".

global inside a function is like a static variable. it is only accessible by the function and it maintains the value when it goes out of scope. the reason they get stuck is because you end up putting them on top of each other instead of next to each other after you reposition them.


Rico(Posted 2008) [#12]
Ok thank you very much for all your help, I'm going to get to sorting the program out now. What did you mean when you said about sorting the objects. Is this a better way to do things? Also do you think using recursion is actually a good idea to solve a problem like pushing blocks around? Maybe it won't be very fast (performance wise).


Jesse(Posted 2008) [#13]
about sorting:
lets say you want to select each object with the mouse and stack them on top of each other (you allow this in your program). the last selected object will not allways be on top. when you grab an object from the stack(i mean on top of each other) it will not always pick the top object. you must have tried it allready.
To solve this, you must search from the bottom of the list to the top and display from the top to the bottom also move the selected object to the bottom of the list. It would be done easyer with an array instead of a list.


Rico(Posted 2008) [#14]
oh right. I didn't really mean to stack objects like that as such, I only put the ability to pick up the objects with the mouse to help position the objects so that they can then be pushed around with the white block (reallly for testing).
I actually just found the error in the program (thanks to the debugger which I have finally found!). I forgot to reset the xvector (xv) and y-vector (yv) of an object after it had been moved in the moveobject routine.
I just put bl.xv=0;bl.yv=0 before the b2=null.
It works ace now, though the objects don't slide over each other yet and can only move 1 pixel at a time.
I appreciate all your help - Thanks - Rico.