for loops

  • Thread starter Thread starter Crirus
  • Start date Start date
C

Crirus

I have this situation

25 26 ........
9 10 11 12 13
24 1 2 3 15
23 8 x 4 15
22 7 6 5 16
21 20 19 18 17


I need a way to iterate through that grid in spiral order strating from 1
 
You allways come up with the interesting ones. What exactly are you trying
to do ? are you like trying to go 1,10,9,24,23,8,x,2,11 ( and then where ? )
Or when you say starting from 1 do you mean 9 ?
 
None of this
I want to pick up element 1 first, then 2 the 3 and so on...
When one of this fit a particular condition, I want to break out the loops

In fact, what I do is this (is about the game I work on)

I have a tile in my map(512x512) called X(i,j)
I need to test for closer tile to this one that is unoccupied by
something...like if a player send a unit right on a tree, I correct the
target to a tile right next to that tree

Got the ideea? So I need a spiral loop starting from the point and wrapping
around it wider and wider
 
Crirus,

Is your array and number of elements always the same size? If so, my poor
solution would be to create a func that pulls that exact element from the
array X(1,2) in your case for 1, X(2,2) for 2, X(3,2) for 3, X(3,3) for 4
and so on. Bad solution, I know, but I haven't had my coffee yet.

Aiax
 
I dont have time to debug this properly, its almost there.

Private Enum Direction

Right

Down

Left

Up

End Enum

'--------------------------------------------------------------------------

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button1.Click

Const UBOUNDX As Integer = 4

Const UBOUNDY As Integer = 4

Dim STARTX As Integer = (CType(UBOUNDX / 2, Integer)) - 1

Dim STARTY As Integer = (CType(UBOUNDY / 2, Integer)) - 1

Dim Xwidth As Integer = 2

Dim YDepth As Integer = 2

Dim iX As Integer = STARTX

Dim iY As Integer = STARTY

Dim AddX, AddY As Integer

Dim d As Integer



Dim Grid(,) As Integer = {{24, 9, 11, 10, 12}, {23, 1, 2, 3, 14}, {22, 8, 0,
4, 14}, {21, 7, 6, 5, 15}, {20, 19, 18, 17, 16}}

While (iX <= UBOUNDX And iY < UBOUNDY)



'Use the Data In the Grid

Debug.WriteLine(Grid(iY + AddY, iX + AddX).ToString())

'Check For Direction Change

Select Case d

Case Direction.Right

AddX += 1

If AddX > Xwidth Then

d = Direction.Down

AddX = Xwidth

AddY += 1

End If

Case Direction.Down

AddY += 1

If AddY > YDepth Then

d = Direction.Left

AddY = YDepth

AddX -= 1

'Use the Data In the Grid

End If

Case Direction.Left

AddX -= 1

If AddX < 0 Then

d = Direction.Up

AddX = 0

AddY -= 1

'Use the Data In the Grid

End If

Case Direction.Up

AddY -= 1

If AddY < 0 Then

d = Direction.Right

iX -= 1

iY -= 1

AddY = 0

AddX = 0

'We need to increase size of Width and Depth

Xwidth += 2

YDepth += 2

'Use the Data In the Grid

End If

End Select



End While



End Sub
 
If you just wanted the closest empty slot in the array, assuming empty = 0,
and x, y is the starting point..

Public Function test2(ByVal array As Integer(,), ByVal x As Integer, ByVal y
As Integer, ByVal offset As Integer) As Point

For ix As Integer = Math.Max(0, x - offset) To
Math.Min(UBound(array, 1), x + offset)
For iy As Integer = Math.Max(0, y - offset) To
Math.Min(UBound(array, 2), y + offset)
If iy = y And ix = x Then
Else
If array(ix, iy) = 0 Then
Return New Point(ix, iy)
End If
End If
Next
Next

If x - offset <= 0 And x + offset >= UBound(array, 1) And y - offset
<= 0 And y + offset >= UBound(array, 2) Then
Return Nothing
End If

Return test2(array, x, y, offset + 1)

End Function

you'll have to test for nothing in case there is not one found..
and it doesn't quite do it in your circular order

Caution.. I haven't tested this so it might be complete b*****ks

HTH
 
I need it in exact that order because that way I can select closest point
free

I think I may do it using a loop to increase the range to next level and 4
loops to extract each side of the square

So first time range is 1 and I search within inner square
next I increase range by 1 and looping accordingly on second square border
around my spot

so first loop extract 123
second loop extract 6 7 5
now on columns
third loop will extract 8
forth loop will extract 4

increase radius by 1
reenter the 4 loops and extract 9, 10, 11,12 ,13 etc.

It may work, but still need to figure out the loops :)

-
 
Caution.. I haven't tested this so it might be complete b*****ks

ROTFLMAO

Regards - OHM
 
The routine should return the closest point, just not in strictly
1,2,3,4,5,6,7,8,9 order.. more like
1,2,3,8,4,7,6,5,9,10,11,12,13,24,14,23,15,22,16,21,20,19,18,17

but it should work... also it may be quite slow if the offset becomes
large..

even if it doesn't work at least I gave OHM a good laugh :-)

Crirus said:
I need it in exact that order because that way I can select closest point
free

I think I may do it using a loop to increase the range to next level and 4
loops to extract each side of the square

So first time range is 1 and I search within inner square
next I increase range by 1 and looping accordingly on second square border
around my spot

so first loop extract 123
second loop extract 6 7 5
now on columns
third loop will extract 8
forth loop will extract 4

increase radius by 1
reenter the 4 loops and extract 9, 10, 11,12 ,13 etc.

It may work, but still need to figure out the loops :)

-

--
Cheers,
Crirus

------------------------------
If work were a good thing, the boss would take it all from you

------------------------------

Rigga said:
If you just wanted the closest empty slot in the array, assuming empty = 0,
and x, y is the starting point..

Public Function test2(ByVal array As Integer(,), ByVal x As Integer,
ByVal
y
As Integer, ByVal offset As Integer) As Point

For ix As Integer = Math.Max(0, x - offset) To
Math.Min(UBound(array, 1), x + offset)
For iy As Integer = Math.Max(0, y - offset) To
Math.Min(UBound(array, 2), y + offset)
If iy = y And ix = x Then
Else
If array(ix, iy) = 0 Then
Return New Point(ix, iy)
End If
End If
Next
Next

If x - offset <= 0 And x + offset >= UBound(array, 1) And y - offset
<= 0 And y + offset >= UBound(array, 2) Then
Return Nothing
End If

Return test2(array, x, y, offset + 1)

End Function

you'll have to test for nothing in case there is not one found..
and it doesn't quite do it in your circular order

Caution.. I haven't tested this so it might be complete b*****ks

HTH

Crirus said:
None of this
I want to pick up element 1 first, then 2 the 3 and so on...
When one of this fit a particular condition, I want to break out the loops

In fact, what I do is this (is about the game I work on)

I have a tile in my map(512x512) called X(i,j)
I need to test for closer tile to this one that is unoccupied by
something...like if a player send a unit right on a tree, I correct the
target to a tile right next to that tree

Got the ideea? So I need a spiral loop starting from the point and wrapping
around it wider and wider

--
Cheers,
Crirus

------------------------------
If work were a good thing, the boss would take it all from you

------------------------------

"One Handed Man [ OHM# ]" <O_H_M{at}BTInternet{dot}com> wrote in message
You allways come up with the interesting ones. What exactly are you trying
to do ? are you like trying to go 1,10,9,24,23,8,x,2,11 ( and then where
? )
Or when you say starting from 1 do you mean 9 ?






Crirus wrote:
I have this situation

25 26 ........
9 10 11 12 13
24 1 2 3 15
23 8 x 4 15
22 7 6 5 16
21 20 19 18 17


I need a way to iterate through that grid in spiral order strating
from 1
 
In fact, what I do is this (is about the game I work on)

I have a tile in my map(512x512) called X(i,j)
I need to test for closer tile to this one that is unoccupied by
something...like if a player send a unit right on a tree, I correct the
target to a tile right next to that tree

It sounds like you're trying to work out the pathfinding AI for a RTS game.
I assume the X in the middle of your sample array is the tree?

Anyway, here is a link to game related resources. Click the link for
pathfinding at the bottom to see several articles.

http://www.gameai.com/

Also try this link:

http://www.gamedev.net/

HTH
 
Cirrus, I have now had a chance to test this and I have debugged it (
Hopefully ) . It seems to work OK.

At Class Level
Private Enum Direction
Right
Down
Left
Up
End Enum


Private Sub Spiral()

Const UBOUNDX As Integer = 4
Const UBOUNDY As Integer = 4
Dim STARTX As Integer = (CType(UBOUNDX / 2, Integer)) - 1
Dim STARTY As Integer = (CType(UBOUNDY / 2, Integer)) - 1
Dim Xwidth As Integer = 2
Dim YDepth As Integer = 2
Dim iX As Integer = STARTX
Dim iY As Integer = STARTY
Dim AddX, AddY As Integer
Dim d As Integer
Dim FirstRight As Integer = 0

'Test Grid With Some Test Data As Per Your Sample. ( With
corrections to your sample as nums were out of sequence
Dim Grid(,) As Integer = {{9, 10, 11, 12, 13}, {24, 1, 2, 3, 14},
{23, 8, 0, 4, 15}, {22, 7, 6, 5, 16}, {21, 20, 19, 18, 17}}

While (iX >= 0 And iY >= 0)


'Use the Data In the Grid
Debug.WriteLine(Grid(iY + AddY, iX + AddX).ToString())

'Check For Direction Change
Select Case d
Case Direction.Right
AddX += 1
If AddX > Xwidth Then
d = Direction.Down
AddX = Xwidth
AddY += 1
End If

Case Direction.Down
AddY += 1
If AddY > YDepth Then
d = Direction.Left
AddY = YDepth
AddX -= 1
'Use the Data In the Grid

End If
Case Direction.Left
AddX -= 1
If AddX = 0 Then
d = Direction.Up
AddX = 0
AddY -= 1
'Use the Data In the Grid

End If
Case Direction.Up
AddY -= 1
If AddY = 0 Then
d = Direction.Right
iX -= FirstRight
iY -= 1
AddY = 0
AddX = 0
'We need to increase size of Width and Depth
Xwidth += 1
YDepth += 2
'Use the Data In the Grid

End If
End Select
FirstRight = 1

End While

End Sub
 
I allready implemented pathfinding and I'm very happy with it
Just need some tricks when a player try to send a unit in a spot
inaccesible... I will choose a range about 5 tiles around that spot and if I
can find a good spot in that range I change the initial target to that tile
 
Thanks for you effort, but.. how about this?

Private Function GetGoodTarget(ByVal target As Point) As Point
'search on 5 tiles radius
If CanPass(target.X, target.Y) Then Return target
For i As Integer = 1 To 5
'horizontal up
For k As Integer = target.X - i To target.X + i
'Console.Write(New Point(k, target.Y - i).ToString + vbCrLf)
If CanPass(k, target.Y - i) Then
Return New Point(k, target.Y - i)
End If
Next
'horizontal down
For k As Integer = target.X - i To target.X + i
'Console.Write(New Point(k, target.Y + i).ToString + vbCrLf)
If CanPass(k, target.Y + i) Then
Return New Point(k, target.Y + i)
End If
Next
'vertical left
For k As Integer = target.Y - i + 1 To target.Y + i - 1
'Console.Write(New Point(target.X - i, k).ToString + vbCrLf)
If CanPass(target.X - i, k) Then
Return New Point(target.X - i, k)
End If
Next
'vertical right
For k As Integer = target.Y - i + 1 To target.Y + i - 1
'Console.Write(New Point(target.X + i, k).ToString + vbCrLf)
If CanPass(target.X + i, k) Then
Return New Point(target.X + i, k)
End If
Next
Next
End Function
 
Thats not what you asked for explicitly is it, to be fair, it would have
prevented me wasting my time if you had been.

OHM
 
I dont want you to fill hurt about posting my solution back to the group...
I just wanted closer points to X considered first.. your solution may work
as well, I just wrote mine before reading yours, so is not about bragging
here

Appologise if I offended you
 
My issue is not about feeling hurt or any sh*t like that. Had you asked for
a function to scan five tiles then the effort would have been in a different
direction. What your OP said was you wanted a sprial and you gave an example
of that. This is what I provided whereas your solution is not only
restricted to five tiles, but is a function

I'm not offended, at all so dont worry about that, its just that I prefer my
effort to at least be in the right direction thats all.

OHM
I dont want you to fill hurt about posting my solution back to the
group... I just wanted closer points to X considered first.. your
solution may work as well, I just wrote mine before reading yours, so
is not about bragging here

Appologise if I offended you


One Handed Man said:
Thats not what you asked for explicitly is it, to be fair, it would
have prevented me wasting my time if you had been.

OHM


Thanks for you effort, but.. how about this?

Private Function GetGoodTarget(ByVal target As Point) As Point
'search on 5 tiles radius
If CanPass(target.X, target.Y) Then Return target
For i As Integer = 1 To 5
'horizontal up
For k As Integer = target.X - i To target.X + i
'Console.Write(New Point(k, target.Y - i).ToString +
vbCrLf) If CanPass(k, target.Y - i) Then
Return New Point(k, target.Y - i)
End If
Next
'horizontal down
For k As Integer = target.X - i To target.X + i
'Console.Write(New Point(k, target.Y + i).ToString +
vbCrLf) If CanPass(k, target.Y + i) Then
Return New Point(k, target.Y + i)
End If
Next
'vertical left
For k As Integer = target.Y - i + 1 To target.Y + i - 1
'Console.Write(New Point(target.X - i, k).ToString +
vbCrLf) If CanPass(target.X - i, k) Then
Return New Point(target.X - i, k)
End If
Next
'vertical right
For k As Integer = target.Y - i + 1 To target.Y + i - 1
'Console.Write(New Point(target.X + i, k).ToString +
vbCrLf) If CanPass(target.X + i, k) Then
Return New Point(target.X + i, k)
End If
Next
Next
End Function


"One Handed Man [ OHM# ]" <O_H_M{at}BTInternet{dot}com> wrote in
message Cirrus, I have now had a chance to test this and I have debugged
it ( Hopefully ) . It seems to work OK.

At Class Level
Private Enum Direction
Right
Down
Left
Up
End Enum


Private Sub Spiral()

Const UBOUNDX As Integer = 4
Const UBOUNDY As Integer = 4
Dim STARTX As Integer = (CType(UBOUNDX / 2, Integer)) - 1
Dim STARTY As Integer = (CType(UBOUNDY / 2, Integer)) - 1
Dim Xwidth As Integer = 2
Dim YDepth As Integer = 2
Dim iX As Integer = STARTX
Dim iY As Integer = STARTY
Dim AddX, AddY As Integer
Dim d As Integer
Dim FirstRight As Integer = 0

'Test Grid With Some Test Data As Per Your Sample. ( With
corrections to your sample as nums were out of sequence
Dim Grid(,) As Integer = {{9, 10, 11, 12, 13}, {24, 1, 2,
3, 14}, {23, 8, 0, 4, 15}, {22, 7, 6, 5, 16}, {21, 20, 19, 18, 17}}

While (iX >= 0 And iY >= 0)


'Use the Data In the Grid
Debug.WriteLine(Grid(iY + AddY, iX + AddX).ToString())

'Check For Direction Change
Select Case d
Case Direction.Right
AddX += 1
If AddX > Xwidth Then
d = Direction.Down
AddX = Xwidth
AddY += 1
End If

Case Direction.Down
AddY += 1
If AddY > YDepth Then
d = Direction.Left
AddY = YDepth
AddX -= 1
'Use the Data In the Grid

End If
Case Direction.Left
AddX -= 1
If AddX = 0 Then
d = Direction.Up
AddX = 0
AddY -= 1
'Use the Data In the Grid

End If
Case Direction.Up
AddY -= 1
If AddY = 0 Then
d = Direction.Right
iX -= FirstRight
iY -= 1
AddY = 0
AddX = 0
'We need to increase size of Width and
Depth Xwidth += 1
YDepth += 2
'Use the Data In the Grid

End If
End Select
FirstRight = 1

End While

End Sub


Crirus wrote:
I have this situation

25 26 ........
9 10 11 12 13
24 1 2 3 15
23 8 x 4 15
22 7 6 5 16
21 20 19 18 17


I need a way to iterate through that grid in spiral order strating
from 1
 
I posted few replyes to correct the direction I want
Read back a few and you will see that

My implementation actually read first line, then I can move a loop up to
read right column, then read bottom line in reverse order and modify next
loop to step in reverse order so I read left column from bottom to top

That's a spiral as I asked

Next, I can change that 5 radius to what ever so is not really fixed to 5
and the fact that is function have no really importance
:)

--
Cheers,
Crirus

------------------------------
If work were a good thing, the boss would take it all from you

------------------------------

One Handed Man said:
My issue is not about feeling hurt or any sh*t like that. Had you asked for
a function to scan five tiles then the effort would have been in a different
direction. What your OP said was you wanted a sprial and you gave an example
of that. This is what I provided whereas your solution is not only
restricted to five tiles, but is a function

I'm not offended, at all so dont worry about that, its just that I prefer my
effort to at least be in the right direction thats all.

OHM
I dont want you to fill hurt about posting my solution back to the
group... I just wanted closer points to X considered first.. your
solution may work as well, I just wrote mine before reading yours, so
is not about bragging here

Appologise if I offended you


One Handed Man said:
Thats not what you asked for explicitly is it, to be fair, it would
have prevented me wasting my time if you had been.

OHM



Crirus wrote:
Thanks for you effort, but.. how about this?

Private Function GetGoodTarget(ByVal target As Point) As Point
'search on 5 tiles radius
If CanPass(target.X, target.Y) Then Return target
For i As Integer = 1 To 5
'horizontal up
For k As Integer = target.X - i To target.X + i
'Console.Write(New Point(k, target.Y - i).ToString +
vbCrLf) If CanPass(k, target.Y - i) Then
Return New Point(k, target.Y - i)
End If
Next
'horizontal down
For k As Integer = target.X - i To target.X + i
'Console.Write(New Point(k, target.Y + i).ToString +
vbCrLf) If CanPass(k, target.Y + i) Then
Return New Point(k, target.Y + i)
End If
Next
'vertical left
For k As Integer = target.Y - i + 1 To target.Y + i - 1
'Console.Write(New Point(target.X - i, k).ToString +
vbCrLf) If CanPass(target.X - i, k) Then
Return New Point(target.X - i, k)
End If
Next
'vertical right
For k As Integer = target.Y - i + 1 To target.Y + i - 1
'Console.Write(New Point(target.X + i, k).ToString +
vbCrLf) If CanPass(target.X + i, k) Then
Return New Point(target.X + i, k)
End If
Next
Next
End Function


"One Handed Man [ OHM# ]" <O_H_M{at}BTInternet{dot}com> wrote in
message Cirrus, I have now had a chance to test this and I have debugged
it ( Hopefully ) . It seems to work OK.

At Class Level
Private Enum Direction
Right
Down
Left
Up
End Enum


Private Sub Spiral()

Const UBOUNDX As Integer = 4
Const UBOUNDY As Integer = 4
Dim STARTX As Integer = (CType(UBOUNDX / 2, Integer)) - 1
Dim STARTY As Integer = (CType(UBOUNDY / 2, Integer)) - 1
Dim Xwidth As Integer = 2
Dim YDepth As Integer = 2
Dim iX As Integer = STARTX
Dim iY As Integer = STARTY
Dim AddX, AddY As Integer
Dim d As Integer
Dim FirstRight As Integer = 0

'Test Grid With Some Test Data As Per Your Sample. ( With
corrections to your sample as nums were out of sequence
Dim Grid(,) As Integer = {{9, 10, 11, 12, 13}, {24, 1, 2,
3, 14}, {23, 8, 0, 4, 15}, {22, 7, 6, 5, 16}, {21, 20, 19, 18, 17}}

While (iX >= 0 And iY >= 0)


'Use the Data In the Grid
Debug.WriteLine(Grid(iY + AddY, iX + AddX).ToString())

'Check For Direction Change
Select Case d
Case Direction.Right
AddX += 1
If AddX > Xwidth Then
d = Direction.Down
AddX = Xwidth
AddY += 1
End If

Case Direction.Down
AddY += 1
If AddY > YDepth Then
d = Direction.Left
AddY = YDepth
AddX -= 1
'Use the Data In the Grid

End If
Case Direction.Left
AddX -= 1
If AddX = 0 Then
d = Direction.Up
AddX = 0
AddY -= 1
'Use the Data In the Grid

End If
Case Direction.Up
AddY -= 1
If AddY = 0 Then
d = Direction.Right
iX -= FirstRight
iY -= 1
AddY = 0
AddX = 0
'We need to increase size of Width and
Depth Xwidth += 1
YDepth += 2
'Use the Data In the Grid

End If
End Select
FirstRight = 1

End While

End Sub


Crirus wrote:
I have this situation

25 26 ........
9 10 11 12 13
24 1 2 3 15
23 8 x 4 15
22 7 6 5 16
21 20 19 18 17


I need a way to iterate through that grid in spiral order strating
from 1
 
Hello, Crirus:

I see you have solved the problem by now but, anyway, here is what I wrote last night (in Spain):

'\\\
Private Sub GetCoordArrayAtDistance(ByVal Radius As Integer, ByRef PointsReturned() As Point, ByRef NumberOfPointsReturned As Integer)
Dim Index As Integer 'Where in PointsReturned() to save the actual point.
Dim n As Integer 'For use in loops.
If Radius = 0 Then
NumberOfPointsReturned = 1
ReDim PointsReturned(NumberOfPointsReturned - 1)
PointsReturned(0) = New Point(0, 0)
Else
NumberOfPointsReturned = 8 * Radius
ReDim PointsReturned(NumberOfPointsReturned - 1) 'A static array would have better performance.
'Upper row:
For n = -Radius To Radius
PointsReturned(Index) = New Point(n, -Radius)
Index += 1
Next
'Right column:
For n = -Radius + 1 To Radius
PointsReturned(Index) = New Point(Radius, n)
Index += 1
Next
'Lower row:
For n = Radius - 1 To -Radius Step -1
PointsReturned(Index) = New Point(n, Radius)
Index += 1
Next
'Left column:
For n = Radius - 1 To -Radius + 1 Step -1
PointsReturned(Index) = New Point(-Radius, n)
Index += 1
Next
End If 'Radius=0
End Sub

Private Sub butDistancia_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles butDistancia.Click
Dim RGen As New Random()
Dim StartRadius As Integer = RGen.Next(0, 6)
Dim EndRadius As Integer = StartRadius + RGen.Next(0, 6)
Dim PointArray() As Point
Dim NumberOfPoints As Integer
Dim n, s, Counter As Integer
Dim g As Graphics = Me.CreateGraphics

g.Clear(SystemColors.Control)
For n = StartRadius To EndRadius
Call GetCoordArrayAtDistance(n, PointArray, NumberOfPoints)
For s = 0 To NumberOfPoints - 1
Counter += 1
g.DrawString(Counter.ToString, _
Me.Font, _
Brushes.Black, _
Me.ClientSize.Width / 2.0F + PointArray(s).X * 25, _
Me.ClientSize.Height / 2.0F + PointArray(s).Y * 25)
Next
Next
End Sub
'///

You can see that it's essentially the same solution as yours (it can't be other way), but the function only returns the array of points in a "ring" at a given distance.

Regards.


"Crirus" <[email protected]> escribió en el mensaje | I have this situation
|
| 25 26 ........
| 9 10 11 12 13
| 24 1 2 3 15
| 23 8 x 4 15
| 22 7 6 5 16
| 21 20 19 18 17
|
|
| I need a way to iterate through that grid in spiral order strating from 1
|
|
|
|
| --
| Cheers,
| Crirus
|
| ------------------------------
| If work were a good thing, the boss would take it all from you
|
| ------------------------------
 
Back
Top