Calculator Community > Axe

Looping Through an Array in Axe

<< < (3/3)

E37:
I agree with Xeda about the parenthesis. I did notice you called main() and didn't return after that. Instead you fall through and run main() a second time and quit the program with its return. Since all main only does something when you hit enter, it shouldn't matter. Without picking through your logic, I can't say more.

Here are some tips for your code. What you have will work, but there are better ways for some things.

I would strongly recommend using the ? and ?? operators for 'and' and 'or'. The 'and' and 'or' you are using are bitwise. This means "1 and 2" returns false. The ? and ?? operators work like && and || in C and even short circuit which is nice. (the same left to right order of operations still apply) This means you can rewrite:

--- Code: ---If (RoomX≥XMin and RoomX≤XMax) and (RoomY≥YMin and RoomY≤YMax)
--- End code ---
as

--- Code: ---If RoomX≥XMin ? (RoomX≤XMax) ? (RoomY≥YMin) ? (RoomY≤YMax) .I omitted the first pair of parenthesis because of order of operations. You can add it in if you want, it will be compiled out
--- End code ---

Using →→ is the same as → if the constant hasn't been declared before. No reason to change it if you don't want to. Just be careful you don't double declare constants as you won't get an error!

You can chain constant declarations together to make them easier to read.

--- Code: ---L₄+12→→°XMin
L₄+14→→°XMax
L₄+16→→°YMin
L₄+18→→°YMax
L₄+20→→°Rooms
--- End code ---
can become

--- Code: ---L₄+12→°XMin+2→°XMax+2→°YMin+2→°YMax+2→°Rooms
--- End code ---

Nice work on making a custom text routine! If all you are after is speed and flexibility, I made a super fast text axiom that can draw to any buffer.

As for putting rooms in the map, making a rectangle collision routine would probably make things a lot smoother. Here is one, I haven't tested it, but it is a translation of one that I wrote in C so it should work. It assumes the rectangles are in the format top_left_x, top_left_y, width, height.

--- Code: ---Lbl Intersect
...
Since each rectangle is made of 4 points and we only have 6 parameters max, I will use A, B, C, D for the second rectangle. Change them to whatever you want
r1, r2, r3, r4 = the first rectangle
A, B, C, D = the second rectangle
returns 1 if the 2 intersect anywhere
...
max(r1, A) < min(r1 + r3, A + C) ? (max(r2, B) < min(r2 + r4, B + D))
Return
--- End code ---

Ki1o:
A few more months, a bit more progress. Once again I'd like to say thanks for all the help and suggestions. With that being said, I've run into another issue and this time I'm not even sure what the cause is.

So here is the problem:
I have successfully written an algorithm to generate 4-6 non-intersecting rooms and I'm attempting to connect them. I wrote some code that is supposed to accomplish this task, but it seems to only work once. As in, any attempts to execute this task consecutively in any manner promptly results in a RAM clear. Here is the code in question that I am using to connect rooms:

--- Code: ---Data(31,31,3,31,31,3,1,1)->°RegionCheck
Lbl ConnectRooms
For(I,0,7)
If {°RegionArray+I}
{°RegionCheck+I}^10->AdjacentRoom
If {°RegionArray+I+AdjacentRoom}
GetAdjRoom()
°RoomArray+(I*4)->Room
ConnectTo(AdjacentRoom)
End
If {°RegionCheck+I}/10->AdjacentRoom
GetAdjRoom()
°RoomArray+(I*4)->Room
ConnectTo(AdjacentRoom)
End
End
End
Return
Lbl GetAdjRoom
°RoomArray+(I+AdjacentRoom*4)->Room
{°RoomX+Room}->AdjacentRoomX
{°RoomY+Room}->AdjacentRoomY
{°RoomWidth+Room}->AdjRoomWidth
{°RoomHeight+Room}->AdjRoomHeight
Return
Lbl ConnectTo
.../Args
ConnectTo(AdjacentRoom)
...
If [r1]=°Below
{°RoomX+Room}+1+(Rand()^({°RoomWidth+Room}-2))->PathFromX
AdjacentRoomX+1+(Rand()^(AdjRoomWidth-2))->PathToX
If PathFromX=PathToX
Connect(PathFromX,{°RoomY+Room}+{°RoomHeight+Room},PathToX,AdjacentRoomY-1)
Else
If AdjacentRoomY-1-{°RoomY+Room}+{°RoomHeight+Room}>4
{°RoomY+Room}+{°RoomHeight+Room}+1+(Rand()^(AdjacentRoomY-({°RoomY+Room}+{°RoomHeight+Room}-1)))->CorridorY
Connect(min(PathFromX,PathToX),CorridorY,max(PathToX,PathFromX),CorridorY)
Connect(PathFromX,{°RoomY+Room}+{°RoomHeight+Room},PathFromX,CorridorY)
Connect(PathToX,CorridorY,PathToX,AdjacentRoomY-1)
Else
Rand()^1->P
If P
Connect(PathFromX,{°RoomY+Room}+{°RoomHeight+Room},PathFromX,AdjacentRoomY-1)
Else
Connect(PathToX,{°RoomY+Room}+{°RoomHeight+Room},PathToX,AdjacentRoomY-1)
End
End
End
End
If [r1]=°Right
{°RoomY+Room}+1+(Rand()^({°RoomHeight+Room}-2))->PathFromY
AdjacentRoomY+1+(Rand()^(AdjRoomHeight-2))->PathToY
If PathFromY=PathToY
Connect({°RoomX+Room}+{°RoomWidth+Room},PathFromY,AdjacentRoomX-1,PathToY)
Else
If AdjacentRoomX-1-{°RoomX+Room}+{°RoomWidth+Room}>4
{°RoomX+Room}+{°RoomWidth+Room}+1+(Rand()^(AdjacentRoomX-({°RoomX+Room}+{°RoomWidth+Room}-1)))->CorridorX
Connect(CorridorX,min(PathFromY,PathToY),CorridorX,max(PathToY,PathFromY))
Connect({°RoomX+Room}+{°RoomWidth+Room},PathFromY,CorridorX,PathFromY)
Connect(CorridorX,PathToY,AdjacentRoomX-1,PathToY)
Else
Rand()^1->P
If P
Connect({°RoomX+Room}+{°RoomWidth+Room},PathFromY,AdjacentRoomX-1,PathFromY)
Else
Connect({°RoomX+Room}+{°RoomWidth+Room},PathToY,AdjacentRoomX-1,PathToY)
End
End
End
End
Return
Lbl Connect
.../Args
Connect(X1,Y1,X2,Y2)
...
If [r1]=[r3]
For(J,0,[r4]-[r2])
0->{[r2]*°FloorWidth+[r1]+Floor+(J*48)}
End
End
If [r2]=[r4]
Fill([r2]*°FloorWidth+[r1]+Floor,[r3]-[r1]+1,0)
End
Return
--- End code ---
In addition, any number greater than 2 in place of "I" will also cause a RAM clear.
Xeda was helping me over on the Cemetech discord, but frankly we are both lost on what the issue could be.
Overview of the current problem: inputting numbers greater than 2 as the offset of the current room causes a RAM clear and executing the code to connect rooms consecutively causes a RAM clear regardless of room "validity". As an example, if I were to change the For loop in ConnectRooms() from
--- Code: ---For(I,0,7)
--- End code ---
to
--- Code: ---For(I,0,1)
--- End code ---
there is no issue. This is because on the seed I'm using to test, there is no 0th room. So it is skipped and instead connects the 1st room. However it crashes once it hits 2 as the doesn't like being executed consecutively. If I were to generate additional floors of the same seed, the first room that is valid can have its connections made, but no further. I've done a lot of different tests but now I need help. Is there something that I overlooked or am not taking into account? I've attached a screenshot to further illustrate.

E37:
@Ki1o
Wow... that's... the most beautifully formatted Axe code I have ever seen. It's not super efficient but who cares for level generation anyway. (and why ruin a work of art?)
I assume by [r1] you mean r1 and not {r1}.

I can't put my finger on the problem without the full source but I do see one thing that might be causing the problem.

In Connect to you do:

--- Code: ---:If [r1]=°Below
:...
:Stuff
:...
:End
:If [r1]=°Right
:...
:Other stuff
:...
:End
--- End code ---
You call subroutines in the first if block which modify r1. By the time you get to :If [r1]=°Right, r1 almost certainly doesn't hold its original value.


Here are a couple wild guesses and observations. They probably aren't right but who knows? Maybe...

The line :If AdjacentRoomY-1-{°RoomY+Room}+{°RoomHeight+Room}>4 bugs me. Do you want :If abs(AdjacentRoomY-1-{°RoomY+Room}+{°RoomHeight+Room})>4 ? I don't know what kind of values you are expecting but if you get -1 it will underflow to 65535 and return true. Values < -4 will act like expected but -1, -2, -3 might be a problem if they can ever happen.

The lines :Rand()^1->P :If P   don't do anything since any number ^1 is 0. I get it is probably for debugging but I thought you might have meant ^2 instead. The optimizer in me compels me to tell you that :If Rand() ^ 1 would be the same as those two lines and wouldn't use a variable. (But again, you probably already know that)

Once, when I was working on random level generation, I came across a bug that had me tearing out my hair for a week. I tracked it down to (usually) a crash when writing to OP1 which is free scrap memory. It moved around quite a bit - making it extra confusing. The crashing code was used many other places and didn't have any attached special conditions. I eventually found out that it was zStart's custom font causing Axe to incorrectly compile my code. I turned off my custom font and everything worked fine. (I had used that font for years by then and all 16 other programs in that project compiled perfectly - making it super weird) If you have a custom font, try disabling it. If Axe's font doesn't screw up and show garbage during compilation then you are fine. (It had done that for that specific program for years at that point so I didn't think anything of it)

I'm not super familiar with Axe's 3 argument For loop because I always use the 1 argument (because I am horny for optimizations) but it looks like in Connect you are filling 1 extra byte in the Fill command compared to the For loop.

If all else fails, try adding code to Connect to check every byte to make sure it is in bounds before writing it. If out of bounds, pause and display variables. Also draw the whole map in pixels to the screen every write (and maybe even slow it down so you don't miss anything) and make sure it is doing what you want.

Ki1o:
@E37
Thanks for the compliment on my formatting and thanks for the reply as usual. I've been trying to track down the problem by commenting out the actual Connect() lines and dumping out what values I was getting for my PathFrom/PathTo and Corridor values. Honestly after hours of checking and changing a few things around and checking again, I never was able to find out what the problem was. Eventually I was just drawing the corridors to the map to see where they were in relation to the rooms and I saw that if the corridor was right next to a room, then that would result in a negative value in the Connect() function and definitely cause a crash. But I couldn't properly debug what those values were because something somewhere was getting corrupted and spitting out garbage values. Because of this, I decided to simply scrap how I was doing room connections and try again from scratch. Which now leads me to a completely different problem that I also don't know how fix let alone what it causing this.

Right now I am starting from the beginning and I am trying to test each value before I move on, but I encountered this:

--- Code: ---For(I,0,7)
If ({°RegionArray+I}=1)
If I^3<2
{°RoomArray+I}->Room
{°RoomY+Room}+1+(rand^({°RoomY+Room}+{°RoomHeight+Room}-{°RoomY+Room}+1))->{°CorridorArray+I}
End
End
End
--- End code ---
So what this is saying is that if the room at the current index exists, then generate choose a value between the top of the room+1 and the bottom of the room-1. This is just the first step so we can start connecting rooms. I'm storing those values to an array so I can dump then to the screen.
The problem is that
--- Code: ---If ({°RegionArray+I}=1)
--- End code ---
seems to be ignored for the 0th room and is producing wrong values for the others. In the screenshot what is shown are the (X,Y) then Width and Height, the value of RegionArray at their index, and finally the value being generated in the above snippet. Rooms without a height or width but have and X and Y are dummy rooms. I'm planning to use those later, so you can ignore those. The first room on this seed is a dummy room. The value of RegionArray+0 is clearly 0, yet there is still a value at CorridorArray+0. What is going on here? I really need all the help I can get at this point because this really shouldn't be an issue yet it is.

Navigation

[0] Message Index

[*] Previous page

Go to full version