Author Topic: Looping Through an Array in Axe  (Read 7199 times)

0 Members and 1 Guest are viewing this topic.

Offline Ki1o

  • LV4 Regular (Next: 200)
  • ****
  • Posts: 119
  • Rating: +5/-2
  • Doing my best...
    • View Profile
Looping Through an Array in Axe
« on: June 25, 2021, 04:49:37 pm »
Hey all,
So I'm current working on a roguelike project but I have hit an annoying stumbling block that I'm not sure how to solve.
I'm implementing a mob system where I can add mobs to various map coordinates and display them on the screen. I'm also using their position to determine whether or not they should be drawn as well as for collision. The array that I've set up works perfectly and I can draw them to the screen, but I am encountering a weird bug(?) when I loop over the array in a for loop to compare values. Here is the full code that I have written so far:
Code: [Select]
.A
./front frames
[FFC1C3E7C33E23FB]→Pic0
[C1C3E7C33E62F3FF]
[FFC1C3E7C37CC4DF]
[C1C3E7C37C46CFFF]
./right frames
[FFC1E1EBA13E22DB]
[C1E1EBE1DF9393E7]
[FFC1E1EBE19F93DB]
[C1E1EBE1BE2223E7]
./left frames
[FF8387D7857C44DB]
[8387D787FBC9C9E7]
[FF8387D787F9C9DB]
[8387D7877D44C4E7]
./back frames
[FF83C3FFA3223BF3]
[83C3FFA3227AF3FF]
[FF83C3FFC544DCCF]
[83C3FFC5445ECFFF]
./slime frames
[FFFFFFC7A3410183]→Pic2
[FFFFC7A3A38383C7]
[FFFFFFC7A3410183]
[FFFFFFFF81600081]
./wall tile, 00
[45FF11FF45FF11FF]→Pic1
./ground tile, 01
[FFFFFFFFFFEFFFFF]
./tile map
[00000000000000000000000000000000000000000000000000000000000000000000000000]→GDB0
[00000000000000000000000000000000000000000000000000000000000000000000000000]
[00000000000000000000000000000000000000000000000000000000000000000000000000]
[00000000000000000000000000000000000000000000000000000000000000000000000000]
[00000000000000000000000000000000000000000000000000000000000000000000000000]
[00000000000000010101010100000000000000000000000000000101010101000000000000]
[00000000000000010101010100000000000000000000000000000101010101000000000000]
[00000000000000010101010100000000000000000000000000000101010101000000000000]
[00000000000000010101010100000000000000000000000000000101010101000000000000]
[00000000000000010101010101010101010101010101010101010101010101000000000000]
[00000000000000000000000000000000000101010101010100000101010101000000000000]
[00000000000000000000000000000000000101010101010100000101010101000000000000]
[00000000000000000000000000000000000101010101010100000101010101000000000000]
[00000000000000000000000000000101010101010101010100000101010101000000000000]
[00000000000000000000000000000100000101010101010100000000010000000000000000]
[00000000000000000000000000000100000000000000000000000000010000000000000000]
[00000000000000000000000000000100000000000000000000000000010000000000000000]
[00000000000000000000000000000100000000000000000000000000010000000000000000]
[00000000000000000000000000000100000000000101010101010101010000000000000000]
[00000000000000000000000000000100000000000101010101010000000000000000000000]
[00000000000000000000000000000101010101010101010101010000000000000000000000]
[00000000000000000000000000000000000001000101010101010000000000000000000000]
[00000000000000000000000000000000000001000101010101010000000000000000000000]
[00000000000000000000000000000000000001000000000100000000000000000000000000]
[00000000000000000000000000000000000001000000000100000000000000000000000000]
[00000000000000000000000000000000000001000000000100000000000000000000000000]
[00000000000000000000000000000000000001000000000100000000000000000000000000]
[00000000000000000000000000000000000001000000000000000000000000000000000000]
[00000000000000010101010101010101000001000000000000000000000000000000000000]
[00000000000000010101010101010101010101000000000000000000000000000000000000]
[00000000000000010101010101010101000000000000000000000000000000000000000000]
[00000000000000010101010101010101000000000000000000000000000000000000000000]
[00000000000000010101010101010101010101010101010101010101010101000000000000]
[00000000000000000000000000000000000000000000000000000000000000000000000000]
[00000000000000000000000000000000000000000000000000000000000000000000000000]
[00000000000000000000000000000000000000000000000000000000000000000000000000]
[00000000000000000000000000000000000000000000000000000000000000000000000000]
0->Q->P→V->H→I→J→F→S→L->K->T
Fix 5
AddMob(1,0)
AddMob(2,2)
AddMob(15,9)
AddMob(2,26)
ClrDraw
Repeat getKey(15)
  ./192 is the offset from the beginning of GDB0
  Q*37+P+192→Z
  If getKey(3) and (I=0) and (J=0) and ({Z+1+GDB0}=1)
    If Z+1≠M
      1→I
      32→S
    End
  End
  If getKey(2) and (I=0) and (J=0) and ({Z-1+GDB0}=1)
    If Z-1≠M
      0-1→I
      64→S
    End
  End
  If getKey(1) and (I=0) and (J=0) and ({Z+37+GDB0}=1)
    If Z+37≠M
      1→J
      0→S
    End
  End
  If getKey(4) and (I=0) and (J=0) and ({Z-37+GDB0}=1)
    If Z-37≠M
      0-1→J
      96→S
    End
  End
  F++
  H+I+I→H
  V+J+J→V
  If (H-8=0) or (H+8=0)
    P+I→P
    0→H→I
  End
  If (V-8=0) or (V+8=0)
    Q+J→Q
    0→V→J
  End
  DrawMap()
  DrawMob()
  Pt-Off(44,28,Pic0+(F/3^4*8)+S)
  ...Text(0,0,Z►Dec)
  For(E,1,L)
    E*4+L₁-4→G
    Text(0,E*6,{G+2}ʳ►Dec)
  End
  ...
  DispGraph
End
ClrDraw
Fix 4
Lbl AddMob
  ./r1 = x, r2 = y
  ./creates an array [x,y,y*37+x+192]
  If L<18
    r₂*37+r₁+192→{r₂→{r₁→{L+1→L*4+L₁-4}+1}+1}ʳ
  End
Return
Lbl DrawMob
  For(E,1,L)
    E*4+L₁-4→G
    {E*4+L₁-2}ʳ→M
    Text(0,0,M►Dec)
    ./If ((M-192≤Z) and (M+192≥Z))
      ./Text(0,E*6,"Drawn")
      {G}-P*8→r₁
      {G+1}-Q*8→r₂
      ./Text(0,0,M►Dec)
      Pt-Off(44+r₁-H,28+r₂-V,Pic2+(F/3^4*8))
      ./Else
      ./Text(0,E*6,"Not Drawn")
    ./End
  End
Return
Lbl DrawMap
  Q*37+P→T
  ClrDraw
  For(B,0,10)
    For(A,0,14)
      A-1*8-4-H→C
      B-1*8-4-V→D
      Pt-On(C,D,{B*37+A+T+GDB0}*8+Pic1)
    End
  End
Return
The problem occurs at the line If (M-192≤Z) and (M+192≥Z) because it is not checking for all values of M, only the last value of M. At first I thought I was doing something incorrectly, so I made a test program that compares a given value with a set of values in a variable length array:
Code: [Select]
.ARRAY
ClrHome
0→L
193→A
AddEntry(1156)
AddEntry(193)
AddEntry(208)
AddEntry(447)
Repeat getKey(15)
  CheckArray()
End
ClrHome
Lbl AddEntry
  r₁→{L+1→L*2+L₁-2}ʳ
Return
Lbl CheckArray
  For(I,1,L)
    {I*2+L₁-2}ʳ→B
    If A=B
      Output(0,0,"EQUAL")
      Pause 1800
      ClrHome
      Else
      Output(0,0,"NOT EQUAL")
      Pause 1800
      ClrHome
    End
  End
Return

This code runs perfectly. I've been commenting out various parts of my original code to see where I am going wrong, but I can't quite solve it on my own. I'm hoping a fresh pair of eyes might give some insight as to why it is not working. Thanks.
Cross-posting from Cemetech to see if anyone here might know.

Offline Xeda112358

  • they/them
  • Moderator
  • LV12 Extreme Poster (Next: 5000)
  • ************
  • Posts: 4704
  • Rating: +719/-6
  • Calc-u-lator, do doo doo do do do.
    • View Profile
Re: Looping Through an Array in Axe
« Reply #1 on: June 25, 2021, 04:57:29 pm »
If M  is less than 192, then M-192 will wrap back around to be >=65344.

Is that possibly the issue ? If so, and if Z is small enough, then you can probably change it to compare M with Z+128 instead.

Offline Ki1o

  • LV4 Regular (Next: 200)
  • ****
  • Posts: 119
  • Rating: +5/-2
  • Doing my best...
    • View Profile
Re: Looping Through an Array in Axe
« Reply #2 on: June 25, 2021, 06:29:50 pm »
Hey Xeda, thanks for replying. Initially I suspected that was the case, so I wrote in the code to display both the values of Z and M, which I commented out later to test other ideas. However the case of Z being ever less than zero should never happen as Z starts at 192 as that corresponds to the player's position at the top leftmost corner of the map, effectively (0,0). Then I thought maybe the method of accessing and checking M was somehow incorrect, so I wrote another test program that should be similar to the conditions of my original program:
Code: [Select]
.ARRAY
ClrHome
0→L
193→A
AddEntry(2,26)
AddEntry(1,0)
AddEntry(15,9)
AddEntry(2,2)
Repeat getKey(15)
  CheckArray()
End
ClrHome
Lbl AddEntry
  r₂*37+[r1]+192→{[r2]->{[r1]->{L+1->L*4+L1-4}+1}+1}ʳ
Return
Lbl CheckArray
  For(I,1,L)
    {I*4+L₁-2}ʳ→B
    If (B-192≤A) and (B+192≥A)
      Output(0,0,"IN BOUNDS")
      Pause 1800
      ClrHome
      Else
      Output(0,0,"OUT OF BOUNDS")
      Pause 1800
      ClrHome
    End
  End
Return
This code also executes without a hitch and perfectly loops through each value and displays whether it is out of bounds or in bounds based on a given value. I'm not entirely sure what I am overlooking at this point. When I was doing some more debugging, it looked like checking the value in the for loop was not playing nicely with drawing to the screen. I'm attaching a screenshot so I can hopefully better explain what is going on.
Funny thing: In the midst of writing this reply, I went to test the code again, this time I have text that shows whether or not a given mob is drawn, and strangely, it works.
Code: [Select]
AddMob(1,0)
AddMob(2,2)
AddMob(15,9)
AddMob(2,26)
AddMob(7,5)
AddMob(8,5)
Lbl DrawMob
  For(E,1,L)
    E*4+L₁-4→G
    {E*4+L₁-2}ʳ→M
    Text(0,0,M►Dec)
  Text(36,0,L►Dec)
  If (M-192≤Z) and (M+192≥Z)
  Text(0,E*6,"Drawn")
    {G}-P*8→r₁
    {G+1}-Q*8→r₂
    Pt-Off(44+r₁-H,28+r₂-V,Pic2+(F/3^4*8))
  Else
  Text(0,E*6,"Not Drawn")
  End
  End
Return
The AddMob code hasn't changed but I added a few more to the map so I can better gauge what's being drawn and should be/what's being drawn and shouldn't be/what's not being drawn and should be, if that makes sense. I added in what mobs are being placed on the map for reference in the screenshot. So the mobs at (1,0),(2,2) and (7,5) are within the bounds of being drawn and therefore should be. I went ahead counted in the map data where a mob should not be drawn based on the character's starting position and lo and behold, the mob at (8,5) should not be drawn and therefore isn't. All the other mobs are also not drawn which is the behavior I desired. Now what doesn't make sense is that this code literally was not working the day before. All I did was rewrite it by hand in a new file which makes this even more confusing. Actually the only difference between the two is this line:
Code: [Select]
If ((M-155≤Z) and (M+155≥Z))became this line:
Code: [Select]
If (M-155≤Z) and (M+155≥Z)In an earlier version of this project instead of "M" I used
Code: [Select]
{G+2}ʳ which I used in my test program to verify that these were in fact the same values and could be used in comparing values, and it still wasn't working in the original program. So, to be honest, I'm quite lost. I'm going to continue onward with the idea that I can use the same for loop in the collision check for each direction and go from there. This has been a weird 24 hours.

Offline E37

  • LV6 Super Member (Next: 500)
  • ******
  • Posts: 358
  • Rating: +23/-0
  • Trial and error is the best teacher
    • View Profile
Re: Looping Through an Array in Axe
« Reply #3 on: June 26, 2021, 07:44:21 pm »
Just looking through your code, I'd like to point out a few things.

I don't have my calc on me but your line r₂*37+r₁+192→{r₂→{r₁→{L+1→L*4+L₁-4}+1}+1}ʳ may not work the way you want it to. Either x->{L1}->x or x->{L1}r->x doesn't return x but instead returns L1. If it is the latter you are fine but you should keep that mechanic in mind so it doesn't get you later.

You can put your data at the end of your program. No need to scroll through all the lines of [FFC1C3E7C33E23FB]→Pic0. A lot of the Axe code examples aren't up to date at all. They are all valid as far as I know but they aren't very efficient.

I assume you starting your comments with ./ is just for you. You don't need the slash.

At the end of your program, you set Fix 4, ClrDraw, run into AddMob and use its return to quit. That is asking for trouble since you don't know the values of r1 and r2 and is is possible you corrupt memory as you exit. Just return before you get to AddMob. Also, the Fix 4 isn't really needed. Yea, it technically best practice but doesn't really matter.

Much of your code is laughably very unoptimized but if you are having trouble with other bugs I won't confuse you more with optimization. Don't worry, my first code was just as bad. (I'm sorry, I just get really excited when I see Axe code to optimize)

If you are still having trouble, (or have any in the future) upload your .8xp and I'll find out what is wrong. (and have a blast in the progress)
I'm still around... kind of.

Offline Ki1o

  • LV4 Regular (Next: 200)
  • ****
  • Posts: 119
  • Rating: +5/-2
  • Doing my best...
    • View Profile
Re: Looping Through an Array in Axe
« Reply #4 on: June 26, 2021, 11:46:45 pm »
Thanks for the reply. To your point about the line r₂*37+r₁+192→{r₂→{r₁→{L+1→L*4+L₁-4}+1}+1}ʳ, it works great, actually. I used Deep Thought's array tutorial to write it. I'm actually storing 3 values at a time but the last one can be a 2-byte value. I wrote a lot of smaller test programs to make sure I was getting the behavior I wanted.
I actually didn't realize how I was quitting the program, so thank you for that. Right now I'm focusing more on readability and functionality so yeah my code is... not very optimized. Planning on doing that sometime in the future, but any help in that regard is always appreciated.
Right now my current problem is the collision check. In my mind, I thought I could simply execute a for loop over the array and check the position of a mob in the same manner that I check collision for tiles, but I realized after trying it that this was not the right approach. The thing is, I actually don't know what the right approach is. Here is a quick snippet:
Code: [Select]
If getKey(3) and (I=0) and (J=0) and ({Z+1+GDB0}=1)
    If CheckRight()
    1→I
    32→S
    End
  End
Lbl CheckRight
  For(K,1,L)
    {K*4+L₁-2}ʳ→N
    Z+1≠N
  End
Return
Except I just walk right through the mobs, even in the case where the only mob is the one right next to me. I'm not entirely sure what reason is for this. In the screenshot, Z=192 and N=193. I verified that this was case using the commented out block
Code: [Select]
...Text(0,0,Z►Dec)
  For(E,1,L)
    E*4+L₁-4→G
    Text(0,E*6,{G+2}ʳ►Dec)
  End
  ...
Z+1 definitely equals 193, so the statement Z+1≠N is false, and I should not be able to move to the right at the start... yet I can. What's the best way to do this?

Offline E37

  • LV6 Super Member (Next: 500)
  • ******
  • Posts: 358
  • Rating: +23/-0
  • Trial and error is the best teacher
    • View Profile
Re: Looping Through an Array in Axe
« Reply #5 on: June 27, 2021, 03:52:56 pm »
Alright, here are a couple guesses.

For(K,1,L) is starting at 1 and not 0. Is that what you want?

Z+1≠N doesn't change any value and so the loop in CheckRight is pointless unless you use the value of N at some point outside the function. Did you mean Return!If Z+1≠N ? If I remember correctly, the For loop will increment at the end and return that value. That means that CheckRight should always return L no matter what data it is given. (I could be wrong but either way there is no way your code is doing what you want it to)

You are also spilling into CheckRight like you did at the end of your main loop. It shouldn't be a problem but does waste time.
I'm still around... kind of.

Offline Ki1o

  • LV4 Regular (Next: 200)
  • ****
  • Posts: 119
  • Rating: +5/-2
  • Doing my best...
    • View Profile
Re: Looping Through an Array in Axe
« Reply #6 on: June 28, 2021, 02:31:34 pm »
@E37 Thank you! Your advice was very helpful in better understanding how Axe works and I was able to get it to work perfectly! I think you were correct in saying that CheckRight was returning L and not the comparison like I assumed it would. Using Return!If inside the for loop is what allowed it to work. This is the result:
Code: [Select]
If getKey(3) and (I=0) and (J=0) and ({Z+1+GDB0}=1)
    If CheckRight()
      1→I
      32→S
    End
  End
  If getKey(2) and (I=0) and (J=0) and ({Z-1+GDB0}=1)
    If CheckLeft()
      0-1→I
      64→S
    End
  End
  If getKey(1) and (I=0) and (J=0) and ({Z+37+GDB0}=1)
    If CheckDown()
      1→J
      0→S
    End
  End
  If getKey(4) and (I=0) and (J=0) and ({Z-37+GDB0}=1)
    If CheckUp()
      0-1→J
      96→S
    End
  End
Lbl CheckRight
  For(K,1,L)
    {K*4+L₁-2}ʳ→N
    Return!If Z+1≠N
  End
Return
Lbl CheckLeft
  For(K,1,L)
    {K*4+L₁-2}ʳ→N
    Return!If Z-1≠N
  End
Return
Lbl CheckDown
  For(K,1,L)
    {K*4+L₁-2}ʳ→N
    Return!If Z+37≠N
  End
Return
Lbl CheckUp
  For(K,1,L)
    {K*4+L₁-2}ʳ→N
    Return!If Z-37≠N
  End
Return
I appreciate the help.

Offline E37

  • LV6 Super Member (Next: 500)
  • ******
  • Posts: 358
  • Rating: +23/-0
  • Trial and error is the best teacher
    • View Profile
Re: Looping Through an Array in Axe
« Reply #7 on: June 28, 2021, 02:44:21 pm »
Nice! I can't believe I guessed that right. That Return!If was a total shot in the dark.
I'm still around... kind of.

Offline Ki1o

  • LV4 Regular (Next: 200)
  • ****
  • Posts: 119
  • Rating: +5/-2
  • Doing my best...
    • View Profile
Re: Looping Through an Array in Axe
« Reply #8 on: December 14, 2021, 11:38:40 pm »
Its been a few months. I've been working on this project on and off and I have come across another issue that I need help with. I'm currently working on the procedural generation and I'm stuck. Currently I'm simply trying to select a starting locations for a set of rooms. The desired behavior I want is this: the first room generated is placed within the bounds of the map and the height and width are chosen so as not to go out of the map bounds. Then the X and Y of the starting location as well as the Xmax and the Ymax of that room is added to an array. Every subsequent starting room location that is generated must be compared to every other room in the array to ensure that the starting location is not going to be inside an already existing room. I've been trying different ways to tackle this problem and I thought I came up with a solution, but after running test after test after, I keep coming across starting locations that fail the check but are still being added to the array as valid rooms.
So, once again, I need some help. I wrote a test program that shows the X, Y, Xmax and Ymax of 9 total rooms. Here is the code:
Code: [Select]
.G
L₄+12→→°XMin
L₄+14→→°XMax
L₄+16→→°YMin
L₄+18→→°YMax
L₄+20→→°Rooms
L₄+22→→°RoomStart
L₄+24→→°RoomWidth
L₄+26→→°RoomHeight
L₄+28→→°RoomX
L₄+30→→°RoomY
L₄+32→→°NewRoomX
L₄+34→→°NewRoomY
Fill(L₁,36,0)
0→Rooms→RoomX→RoomY→RoomHeight→RoomWidth→R
ClrDraw
GenFloor()
CheckFloor()
Main()
Lbl Main
  While 1
    DispGraph
    Input()
  EndIf getKey(15)
Return
Lbl CheckFloor
  For(R,0,Rooms-1)
    R+1*4+L₁-4→Z
    R+1*5-4→Y
    R+1*4+L₁-4→Z
    {Z}→XMin
    {Z+2}→XMax
    {Z+1}→YMin
    {Z+3}→YMax
    DrawText(1,Y,"(")
    DrawInt(4,Y,{Z})
    DrawText(13,Y,",")
    DrawInt(16,Y,{Z+1})
    DrawText(24,Y,")")
    DrawInt(29,Y,XMin)
    DrawInt(38,Y,XMax)
    DrawInt(47,Y,YMin)
    DrawInt(56,Y,YMax)
  End
Return
Lbl GenFloor
  While Rooms<9
    GenRoom()
    PlaceRoom()
    0→R
  End
Return
Lbl GenRoom
  !If Rooms
    GetRoomStart()
    While 1
      GetRoomSide()→RoomWidth
    End!If ChkRoomWidth()
    While 1
      GetRoomSide()→RoomHeight
    End!If ChkRoomHeight()
  Else
    GetRoomStart()
    While R<Rooms-1
      R+1*4+L₁-4→Z
      {Z}→XMin
      {Z+2}→XMax
      {Z+1}→YMin
      {Z+3}→YMax
      If (RoomX≥XMin and RoomX≤XMax) and (RoomY≥YMin and RoomY≤YMax)
        0→R
        GetRoomStart()
      End
      !If (RoomX≥XMin and RoomX≤XMax) and (RoomY≥YMin and RoomY≤YMax)
        R++
      End
    End
    While 1
      GetRoomSide()→RoomWidth
    End!If ChkRoomWidth()
    While 1
      GetRoomSide()→RoomHeight
    End!If ChkRoomHeight()
  End
Return
Lbl PlaceRoom
  If Rooms<9
    RoomY+RoomHeight-1→{RoomX+RoomWidth-1→{RoomY→{RoomX→{Rooms+1→Rooms*4+L₁-4}+1}+1}+1}
  End
Return
Lbl GetRoomStart
  6+(rand^33)→RoomX
  4+(rand^37)→RoomY
Return
Lbl GetRoomSide
  4+(rand^9)
Return
Lbl ChkRoomWidth
  (RoomX+RoomWidth-1>41)
Return
Lbl ChkRoomHeight
  (RoomY+RoomHeight-1>43)
Return
Lbl DrawText
  For(I,0,length(r₃)-1)
    Copy({r₃+I}-32*4+°CharSprites,L₄+50,4)
    Fill(L₄+54,4,0)
    DrawChar()
  End
Return
Lbl DrawInt
  r₃/10+16→{L₅}
  r₃^10+16→{L₅+1}
  For(I,0,1)
    Copy({L₅+I}*4+°CharSprites,L₄+50,4)
    Fill(L₄+54,4,0)
    DrawChar()
  End
Return
Lbl DrawChar
  Pt-On(r₁+(I*((I>0)*4)),r₂,L₄+50)
Return
Lbl Input
  If getKey(9)
    ClrDraw
    0→Rooms
    GenFloor()
    CheckFloor()
  End
Return
[]→°CharSprites
[0000000080800080]
[A0A00000A0E0E0A0]
[60C060C0A060C0A0]
[40A060E040400000]
[4080804040202040]
[A040A0000040E040]
[000040800000E000]
[0000008000204080]
[E0A0A0E0C04040E0]
[E020C0E0E06020E0]
[A0A0E020E08060E0]
[E080E0E0E0204040]
[E0A0E0E0E0A0E020]
[4000400040004080]
[0020402000E000E0]
[00804080E0200040]
[40A0E04060A0E0A0]
[C0E0A0E0E08080E0]
[C0A0A0E0E0C080E0]
[E0C08080E080A0C0]
[A0E0A0A0E04040E0]
[6020A040A0C0A0A0]
[808080E0E0E0A0A0]
[C0A0A0A0C0A0A060]
[C0A0E080E0A0E040]
[C0A0C0A0E08020E0]
[E0404040A0A0A060]
[A0A0A040A0A0E0E0]
[A040A0A0A0A04040]
[E02080E000000000]

I also attached a screenshot. In the screenshot, room (33,19) should not be a valid starting location for a room because of room (28,17). 33 is clearly between 28 and 35, and 19 is also between 17 and 26. Therefore, what should have happened is that GetRoomStart() should have been called and it should have been compared to the other rooms. Instead it was treated like a valid room and added to the array. I've been having weird issues with while loops all week so far as well. Any and all help would be greatly appreciated.

Offline Xeda112358

  • they/them
  • Moderator
  • LV12 Extreme Poster (Next: 5000)
  • ************
  • Posts: 4704
  • Rating: +719/-6
  • Calc-u-lator, do doo doo do do do.
    • View Profile
Re: Looping Through an Array in Axe
« Reply #9 on: December 15, 2021, 08:13:45 am »
I'm thinking it might be an order-of-operations issue since Axe obeys parentheses, but is otherwise left-to-right instead of PEMDAS.

Instead of this:
Code: [Select]
      If (RoomX≥XMin and RoomX≤XMax) and (RoomY≥YMin and RoomY≤YMax)
        0→R
        GetRoomStart()
      End
      !If (RoomX≥XMin and RoomX≤XMax) and (RoomY≥YMin and RoomY≤YMax)
        R++
      End
Try:
Code: [Select]
      If (RoomX≥XMin) and (RoomX≤XMax) and (RoomY≥YMin) and (RoomY≤YMax)
        0→R
        GetRoomStart()
      Else
        R++
      End

Offline E37

  • LV6 Super Member (Next: 500)
  • ******
  • Posts: 358
  • Rating: +23/-0
  • Trial and error is the best teacher
    • View Profile
Re: Looping Through an Array in Axe
« Reply #10 on: December 15, 2021, 07:31:06 pm »
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: [Select]
If (RoomX≥XMin and RoomX≤XMax) and (RoomY≥YMin and RoomY≤YMax)as
Code: [Select]
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
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: [Select]
L₄+12→→°XMin
L₄+14→→°XMax
L₄+16→→°YMin
L₄+18→→°YMax
L₄+20→→°Rooms
can become
Code: [Select]
L₄+12→°XMin+2→°XMax+2→°YMin+2→°YMax+2→°Rooms
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: [Select]
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
I'm still around... kind of.

Offline Ki1o

  • LV4 Regular (Next: 200)
  • ****
  • Posts: 119
  • Rating: +5/-2
  • Doing my best...
    • View Profile
Re: Looping Through an Array in Axe
« Reply #11 on: February 17, 2022, 07:57:52 pm »
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: [Select]
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
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: [Select]
For(I,0,7) to
Code: [Select]
For(I,0,1) 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.

Offline E37

  • LV6 Super Member (Next: 500)
  • ******
  • Posts: 358
  • Rating: +23/-0
  • Trial and error is the best teacher
    • View Profile
Re: Looping Through an Array in Axe
« Reply #12 on: February 19, 2022, 07:20:09 pm »
@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: [Select]
:If [r1]=°Below
:...
:Stuff
:...
:End
:If [r1]=°Right
:...
:Other stuff
:...
:End
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.
I'm still around... kind of.

Offline Ki1o

  • LV4 Regular (Next: 200)
  • ****
  • Posts: 119
  • Rating: +5/-2
  • Doing my best...
    • View Profile
Re: Looping Through an Array in Axe
« Reply #13 on: February 22, 2022, 04:46:01 pm »
@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: [Select]
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
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: [Select]
If ({°RegionArray+I}=1) 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.