How to calculate the distance in a hexagonal grid?
I tried to use a code found in internet but it does not work or, I’m making a mistake somewhere.
The original
int GetTileDistance(int aX1, int aY1, int aX2, int aY2)
{
int dx = aX2 - aX1; // signed deltas
int dy = aY2 - aY1;
int x = Mathf.Abs(dx); // absolute deltas
int y = Mathf.Abs(dy);
// special case if we start on an odd row or if we move into negative x direction
if ((dx < 0)^((aY1&1)==1))
x = Mathf.Max(0, x - (y + 1) / 2);
else
x = Mathf.Max(0, x - (y) / 2);
return x + y;
}
passed to Xojo
(fromHex and toHex are strings like “3320”, “3522”
[code]Public Function CheckDistance(fromHex as string, toHex as string) as integer
var aX1, aY1, aX2,aY2 as integer
aX1 = fromHex.Right(2).ToInteger
aY1 = fromHex.Left(2).ToInteger
aX2 = tohex.Right(2).ToInteger
aY2 = tohex.Left(2).ToInteger
var dx as integer = aX2 - aX1
var dy as integer = aY2 - aY1
var x as integer = abs(dx)
var y as integer = abs(dy)
if (dx<0 or aY1 mod 2 <> 0) then
x = max(0, x-(y+1)/2)
else
x = Max(0, x-(y)/2)
end if
return x + y
End Function
[/code]

Nobody has an idea on what is wrong? or another approach?
Make us an example for testing. What is your result? And where is the problem?
“^” in C is not an OR operator but an XOR
see https://www.tutorialspoint.com/cprogramming/c_operators.htm
so your tests lines are not right.
It seems clear that the first two digits of fromHex and toHex refer to the column and the last two digits refer to the row, but what is meant by “distance” is not clear. When you refer to distance, are you referring to the distance from the centre of one hexagon to the centre of another one, or from a vertex (or edge) of one hexagon to a vertex (or edge) of another one, etc., and if so, which vertex (or edge)?
This looks like a hexagonal version of taxicab geometry.
[quote=485263:@Robert Weaver]It seems clear that the first two digits of fromHex and toHex refer to the column and the last two digits refer to the row, but what is meant by “distance” is not clear. When you refer to distance, are you referring to the distance from the centre of one hexagon to the centre of another one, or from a vertex (or edge) of one hexagon to a vertex (or edge) of another one, etc., and if so, which vertex (or edge)?
This looks like a hexagonal version of taxicab geometry.[/quote]
Distance in hexes
[quote=485267:@Enric Herrera]Posted a text example
https://www.dropbox.com/s/qbkae746a8tth0s/Grid.zip?dl=0[/quote]
There’s no text example therejust the same image file as in your first post and a Xojo project file.
“Distance in hexes” explains nothing. So tell us, for example, what is:
- Distance between 2917 and 3117?
- Distance between 2917 and 3018?
- Distance between 2917 and 2918?
if (dx<0 or aY1 mod 2 <> 0) then
should be
if ((dx<0) xor ((aY1 mod 2) <> 0)) then
[quote=485269:@Robert Weaver]There’s no text example therejust the same image file as in your first post and a Xojo project file.
“Distance in hexes” explains nothing. So tell us, for example, what is:
- Distance between 2917 and 3117?
- Distance between 2917 and 3018?
- Distance between 2917 and 2918?[/quote]
The link is a .zip that contains the res.xojo_binary_project and the grid.png (I just downloaded myself )
The distance should be:
2917 and 3117 = 2
2917 and 3118 = 2
2917 and 2918 = 1
2917 and 3019 = 2
So, starting on an hexagon count hexes to reach the target.
I think the trouble comes from the different type of layout
"odd-r horizontal layout
even-r horizontal layout
odd-q vertical layout
even-q vertical layout
I’m using even-q vertical layout, ( shoves odd columns down)
[quote=485271:@Jean-Yves Pochez]if (dx<0 or aY1 mod 2 <> 0) then
should be
if ((dx<0) xor ((aY1 mod 2) <> 0)) then
I tried also, but not luck
// if dx<0 or aY1 mod 2 = 0 then
if ((dx<0) Xor (aY1 mod 2 <> 0)) then
x = Max(0, x - floor((y+1)/2))
else
x = Max(0, x - floor(y/2))
end if
Thanks Robert, but in some cases, I think your code do not work.
Checking from 3320 to 3419 or to 3219 gives a range of 1 when it should be 2.

???[quote=485287:@Robert Livingston]q[/quote]
[code]Public Function CheckDistance(fromHex As String, toHex As String) As Integer
Var hexA, hexB As Integer
hexA = fromHex.Val
hexB = toHex.Val
Var colA, colB, rowA, rowB As Integer
colA = hexA \ 100
colB = hexB \ 100
rowA = hexA Mod 100
rowB = hexB Mod 100
Var jump As Integer = 0
Do
If colA = colB And rowA = rowB Then Return jump + 0
If colA = colB Then Return jump + Abs(rowA - rowB)
If rowA = rowB Then Return jump + Abs(colA - colB)
If colA Mod 2 = 0 And rowA = rowB + 1 Then Return jump + Abs(colA - colB)
If colA Mod 2 = 1 And rowA = rowB - 1 Then Return jump + Abs(colA - colB)
jump = jump + 1
If Abs(colA - colB) > Abs(rowA - rowB) Then
// change column
If colA < colB Then colA = colA + 1 Else colA = colA - 1
Else
// change row
If rowA < rowB Then rowA = rowA + 1 Else rowA = rowA - 1
End If
Loop[/code]
Well, its is a little better but still not completely work 
Thanks Robert, it works well only at 2 hexes distance. Has 2 fautls at 3 hexes ,and 6 fautls at 4, so exponentially will fail much more at more distance.
It’s a very complicated algorithm, I though it should be very common because is used a lot in games that use hexagons…
[code]Public Function CheckDistance(fromHex As String, toHex As String) As Integer
Var hexA, hexB As Integer
hexA = fromHex.Val
hexB = toHex.Val
Var colA, colB, rowA, rowB As Integer
colA = hexA \ 100
colB = hexB \ 100
rowA = hexA Mod 100
rowB = hexB Mod 100
Var jump As Integer = 0
Do
If colA = colB And rowA = rowB Then Return jump + 0
If colA = colB Then Return jump + Abs(rowA - rowB)
If rowA = rowB Then Return jump + Abs(colA - colB)
If colA Mod 2 = 0 And rowA = rowB + 1 Then Return jump + Abs(colA - colB)
If colA Mod 2 = 1 And rowA = rowB - 1 Then Return jump + Abs(colA - colB)
jump = jump + 1
If colA Mod 2 = 0 And rowA > rowB And colA > colB Then
rowA = rowA - 1
colA = colA - 1
Continue
End If
If colA Mod 2 = 0 And rowA > rowB And colA < colB Then
rowA = rowA - 1
colA = colA + 1
Continue
End If
If colA Mod 2 = 1 And rowA < rowB And colA < colB Then
rowA = rowA + 1
colA = colA + 1
Continue
End If
If colA Mod 2 = 1 And rowA < rowB And colA > colB Then
rowA = rowA + 1
colA = colA - 1
Continue
End If
If Abs(colA - colB) > Abs(rowA - rowB) Then
// change column
If colA < colB Then colA = colA + 1 Else colA = colA - 1
Else
// change row
If rowA < rowB Then rowA = rowA + 1 Else rowA = rowA - 1
End If
Loop[/code]
This does better
Oh Robert, the last code seems to work very fine. I really appreciate your time (and your wisdom), I spent two completed days trying to find a way to calculate this. Really, thank you.
The code is pretty fast as is. But it could be a little more efficient. I reversed the most logical approach in one segment. As originally posted:
If Abs(colA - colB) > Abs(rowA - rowB) Then
// change column
If colA < colB Then colA = colA + 1 Else colA = colA - 1
Else
// change row
If rowA < rowB Then rowA = rowA + 1 Else rowA = rowA - 1
End If
It makes more sense to do the below:
If Abs(colA - colB) > Abs(rowA - rowB) Then
// change row
If rowA < rowB Then rowA = rowA + 1 Else rowA = rowA - 1
Else
// change column
If colA < colB Then colA = colA + 1 Else colA = colA - 1
End If