Question about breaking a nested loop

BlitzMax Forums/BlitzMax Beginners Area/Question about breaking a nested loop

Takis76(Posted 2015) [#1]
Hi,

I am trying to break the program flow from a nested loop.


I have one routine which searches whole 2D map to see if there are empty squares on the map and on those empty squares I will put a monster.

When I find the empty square I like to break whole loop . not even search for the next square.

Global Search_map_x:Byte
Global Search_map_y:Byte
Global Search_map_tmp_x:Byte
Global Search_map_tmp_y:Byte
Global Levels:String[51, 42, 42, 5]
Global Monster_creation_not_allowed:Byte

	For Search_map_y = 1 To 37
 		For Search_map_x = 1 To 38
 			If Levels[Current_Level, Search_map_x, Search_map_y, 1] = "00" And Levels[Current_Level, Search_map_x, Search_map_y, 2] = "00" And Levels[Current_Level, Search_map_x, Search_map_y, 3] = "00" And Levels[Current_Level, Search_map_x, Search_map_y, 4] = "00" Then
			Monster_creation_not_allowed = 0
			Search_map_tmp_x = Search_map_x
			Search_map_tmp_y = Search_map_y
			Exit
			EndIf

			If Levels[Current_Level, Search_map_x, Search_map_y, 1] <> "00" And Levels[Current_Level, Search_map_x, Search_map_y, 2] <> "00" And Levels[Current_Level, Search_map_x, Search_map_y, 3] <> "00" And Levels[Current_Level, Search_map_x, Search_map_y, 4] <> "00" Then
			Monster_creation_not_allowed = 1
							
			EndIf

		Next
							
	Next


	If Monster_creation_not_allowed = 1 Then
        'Here is the not allowing monster message
        endif

'The rest code bellow creates the monster at position  Search_map_tmp_x and  Search_map_tmp_y



We assume the map is already filled with walls and other stuff.

I try to check if there is an empty square on the map to put a monster and then before put the monster , I check if there is and another one square empty to put its respawn position.
The "00" are the empty squares and other from "01" to "99" are occupied squares.
The search_map_x and The search_map_x variables , scan the map and when the coordinates of those search_map_x and The search_map_x in levels[] array have an empty square "00" then I would like to interrupt whole loop and go to next code bellow.
It doesn't seems to work.

Any idea how to break any level nested loop. Thank you.


Midimaster(Posted 2015) [#2]
Do you mean something like that:

	Local Found=FALSE

	For Search_map_y = 1 To 37
 		For Search_map_x = 1 To 38
 			If ... Then
				Found=TRUE
			EndIf
			If Found=TRUE Then Exit
			.....
		Next
		If Found=TRUE Then Exit
	Next				

	If Found=TRUE
		Monster_creation_not_allowed = 0
		Search_map_tmp_x = Search_map_x
		Search_map_tmp_y = Search_map_y
	Endif



Xerra(Posted 2015) [#3]
I did a very simple maze game a couple of years back and put the listing into a forum post as it's pretty short. There's an example of how to exit a maze search in that.

http://www.blitzbasic.com/Community/posts.php?topic=101884


col(Posted 2015) [#4]
Hiya,

BRL have already thought of this and BlitzMax can use Exit Labels, documented under
BlitzMax Help->Language->Program Flow->Exit and Continue

Eg:-
Strict

Local x,y

#Leave
For x = 0 Until 20
	For y = 0 Until 15
		If x = 10 And y = 10 Exit Leave
	Next
Next

Print x
Print y


Hope it helps.


AdamStrange(Posted 2015) [#5]
Hi Takis76. Here's another way to look at the code:
'bytes chnged to ints - they are internally anyway?
'lets make these smaller and simpler to view
'Global Search_map_x:Int
'Global Search_map_y:int
'Global Search_map_tmp_x:int
'Global Search_map_tmp_y:int
Global map_x:Int
Global map_y:Int

Global lvl:Int = 0

'changed from string to int as int's are faster ;) and allow for some other optimisations
'I will assume that a result of 0 means thet we can put a monster there - see original = "00".
'I will further assume that there can not be a negative result
Global Levels:int[51, 42, 42, 5]
Global Monster_creation_allowed:int

'version 1 - for loops converted to repeats
Print "Version 1 - does the same as original code"
map_y = 1
Local foundx:Int = -1
Local foundy:Int = -1
Repeat
	map_x = 1
	Repeat
		If Levels[lvl, map_x, map_y, 1] + Levels[lvl, map_x, map_y, 2] + Levels[lvl, map_x, map_y, 3] + Levels[lvl, map_x, map_y, 4] = 0 Then
			foundx = map_x
			foundy = map_y
		End if
		map_x :+ 1
	Until map_x > 38 Or foundx > -1
	map_y :+ 1
Until map_y > 37 Or foundx > -1

If foundx > -1 then
	Print "monster can be placed at "+foundx+" "+foundy
Else
	Print "monster can't be placed"
End If


'version 2
print	
Print "Version 2 - picks random position in a level"
'any repeat should have the additions of a trap - to make sure it doesn't loop indefinately. we'll set the trap to trip at 100 repeats
Local trap:Int = 0
repeat
	map_x = Rand(1, 38)
	map_y = Rand(1, 37)
	If Levels[lvl, map_x, map_y, 1] + Levels[lvl, map_x, map_y, 2] + Levels[lvl, map_x, map_y, 3] + Levels[lvl, map_x, map_y, 4] = 0 Then
		foundx = map_x
		foundy = map_y
	End If
	trap :+ 1
Until foundx > -1 Or trap > 100
If foundx > -1 And trap =< 100 Then
	Print "monster can be placed at "+foundx+" "+foundy
Else
	Print "monster can't be placed"
End If


it looks bigger because there are two different methods for finding what you are wanting. There is also more error checking and print's so you can see what is going on :)

Also because there are no for loops, you won't need to exit in the same way.

Use loops for things you know. Try not to use exits!
While and repeat can give better results :)


Takis76(Posted 2015) [#6]
@col

I am in SuperStrict mode so labels , gotos and gosubs not allowed.

Very interesting code , I will report what I have done when I change my code.
Thank you very much for now.


Brucey(Posted 2015) [#7]
You can use loop labels in SuperStrict, as per the above example.


PhotonTom(Posted 2015) [#8]
Heh, you learn something new everyday, never had any idea that blitz had loop labels :)


Takis76(Posted 2015) [#9]
This code idea worked in my game. (This idea was nice)

       For Search_map_y = 1 To 37
 		For Search_map_x = 1 To 38
 			If ... Then
				Found=TRUE
			EndIf
			If Found=TRUE Then Exit
			.....
		Next
		If Found=TRUE Then Exit
	Next				



Also the idea with repeat of AdamStrange is nice too . but the code is more complicated. As my original code used for loops I used the first idea with exits.

As I understood , I need to put exit in both loops. I was put exit only in one loop.

I fixed my code and now I break whole loop and I check if there are empty squares to put the monster and the monster respawn position. (Each monster needs 2 empty squares , one for the monster position and one for respawn position)

It worked perfectly.

Thank you very much.


coffeedotbean(Posted 2015) [#10]
You could wrap it in a function or method within a type and simply Return from the function or method when your done. If you need return values from the function you can get fancy and use Var

Local found_x:Int
Local found_y:Int

If Found(found_x,found_y) Then Put_Monster(found_x,found_y)

Function Found:Int(x:Int Var, y:Int Var)
        For Search_map_y = 1 To 37
 		For Search_map_x = 1 To 38
 			If ... Then
                                x = Search_map_x
                                y = Search_map_y
				Return True
			EndIf			
			.....
		Next
	Next
        Return False
End Function