I have a grid of tiles each with coordinates such as (-3, 5) or (1, 540) I want to generate a unique seed for each tile but I haven't found a way to do such
You need some kind of "pairing function" - Wiki describes such functions for natural numbers while you need integers including negative ones.
You can enumerate all integer points at coordinate plane in spiral manner
^ OY
|
16 15 14 13 12
17 4 3 2 11
18 5 0 1 10 ==> OX
19 6 7 8 9
20 21 22 23 24
So, for example, point -2,-2 has index 20
To calculate such index from coordinates, you can use simple algorithm (details here)
if y * y >= x * x then begin
p := 4 * y * y - y - x;
if y < x then
p := p - 2 * (y - x)
end
else begin
p := 4 * x * x - y - x;
if y < x then
p := p + 2 *(y - x)
end;
You don't ask for reverse mapping, but it is definitely possible (layer number is (1 + floor(sqrt(p))) / 2 and so on)
To complete: Python function for reverse mapping
def ptoxy(p):
layer = (int(math.sqrt(p)) + 1) // 2 # integer division
topleft = 4*layer*layer
if p <= topleft:
if p <= topleft - 2 * layer:
return [layer, 3*layer + p - topleft]
else:
return [-layer + topleft - p, layer]
else:
if p >= topleft + 2 * layer:
return [p-topleft - 3*layer, -layer]
else:
return [-layer, layer-p + topleft]
and link to quick-made test
If you have a grid of tiles, you may consider that you have a first tile, at the top-left corner and a last tile at the bottom-right corner.
[0] [1] [2]
[3] [4] [5]
[6] [7] [8]
But the [Row:Col] notation is more handy.
[0:0] [0:1] [0:2]
[1:0] [1:1] [1:2]
[2:0] [2:1] [2:2]
So you can access the [Row:Col] element with the formula:
ColumnCount = 3
Element = (Row * ColumnCount) + Col
For example (2:1) offset in your grid will be 2*3+1 which is 7.
[0:0] [0:1] [0:2]
[1:0] [1:1] [1:2]
[2:0] [2:1] [2:2]
--v--
2*3+1 = 7
It's simple and each tile will have a unique identifier.
Related
I want to calculate the length of every full rotation of an Archimedean Spiral given the spacing between each arm and the total length are known. The closest to a solution I've been able to find is here, but this is for finding an unknown length.
I can't interpret math notation so am unable to extrapolate from the info in the link above. The closest I've been able to achieve is:
Distance between each spiral arm:
ArmSpace <- 7
Total length of spiral:
TotalLength <- 399.5238
Create empty df to accommodate TotalLength (note that sum(df[,2]) can be > TotalLength):
df <- data.frame(matrix(NA, nrow=0, ncol=2))
colnames(df) <- c("turn_num", "turn_len_m")
df[1,1] <- 0 # Start location of spiral
df[1,2] <- pi*1/1000
Return length of every turn:
i <- 0
while(i < TotalLength) {
df[nrow(df)+1,1] <- nrow(df) # Add turn number
df[nrow(df),2] <- pi*(df[nrow(df)-1,2] +
(2*df[nrow(df),1])*ArmSpace)/1000
i <- sum(df[,2])
}
An annotated example explaining the steps would be most appreciated.
I used approximation Clackson formula
t = 2 * Pi * Sqrt(2 * s / a)
to get theta angle corresponding to arc length s.
Example in Delphi, I hope idea is clear enough to implement in R
var
i, cx, cy, x, y: Integer;
s, t, a, r : Double;
begin
cx := 0;
cy := 0;
a := 10; //spiral size parameter
Canvas.MoveTo(cx, cy);
for i := 1 to 1000 do begin
s := 0.07 * i; //arc length
t := 2 * Pi * Sqrt(2 * s / a); //theta
r := a * t; //radius
x := Round(cx + r * cos(t)); //rounded coordinates
y := Round(cy + r * sin(t));
Memo1.Lines.Add(Format('len %5.3f theta %5.3f r %5.3f x %d y %d', [s, t, r, x, y]));
Canvas.LineTo(x, y);
if i mod 10 = 1 then //draw some points as small circles
Canvas.Ellipse(x-2, y-2, x+3, y+3);
end;
Some generated points
len 0.070 theta 0.743 r 7.434 x 5 y 5
len 0.140 theta 1.051 r 10.514 x 5 y 9
len 0.210 theta 1.288 r 12.877 x 4 y 12
len 0.280 theta 1.487 r 14.869 x 1 y 15
len 0.350 theta 1.662 r 16.624 x -2 y 17
len 0.420 theta 1.821 r 18.210 x -5 y 18
Link gives exact formula for ac length,
s(t) = 1/(2*a) * (t * Sqrt(1 + t*t) + ln(t + Sqrt(1+t*t)))
but we cannot calculate inverse (t for given s) using simple formula, so one need to apply numerical methods to find theta for arc length value.
Addition: length of k-th turn. Here we can use exact formula. Python code:
import math
def arch_sp_len(a, t):
return a/2 * (t * math.sqrt(1 + t*t) + math.log(t + math.sqrt(1+t*t)))
def arch_sp_turnlen(a, k):
return arch_sp_len(a, k*2*math.pi) - arch_sp_len(a, (k-1)*2*math.pi)
print(arch_sp_turnlen(1, 1))
print(arch_sp_turnlen(1, 2))
print(arch_sp_turnlen(10, 3))
7|8|9
6|5|4
1|2|3
1 -> (1,1)
2 -> (2,1)
3 -> (3,1)
4 -> (3,2)
5 -> (2,2)
6 -> (1,2)
7 -> (1,3)
8 -> (2,3)
9 -> (3,3)
In this grid, the mapping of the numbers to coordinates is shown above.
I'm struggling to come up with a formula where given the number of the grid and the number of rows and columns in the grid, it outputs the coordinates of the grid.
I tried following the logic in this question but in this question, the coordinate system starts from 0 and the rows are not alternating.
If there was no alternating and the numbers were all starting at 0 and not 1, then you could apply Euclidean division directly:
x = n % 3
y = n // 3
where // gives the quotient of the Euclidean division, and % gives the remainder of the Euclidean division.
If there was no alternating, but the numbers all start at 1 instead of 0, then you can fix the above formula by removing 1 from n to make it start at 0, then adding 1 to x and y to make them start at 1:
x = ((n - 1) % 3) + 1
y = ((n - 1) // 3) + 1
Now all we have to change to take the alternating into account is to flip the x values on the right-to-left rows.
y remains unchanged, and x remains unchanged on the left-to-right rows.
The right-to-left rows are the rows with an even y, and you can flip x symmetrically around 2 by removing it from 4:
if y % 2 == 0:
x = 4 - x
Putting it all together in a function and testing it, in python:
def coord(n):
y = ((n-1) // 3) + 1
x = ((n-1) % 3) + 1
if y % 2 == 0: # right-to-left row
x = 4 - x # flip horizontally
return (x, y)
for n in range(1, 9+1):
x, y = coord(n)
print(f'{n} -> ({x},{y})')
Output:
1 -> (1,1)
2 -> (2,1)
3 -> (3,1)
4 -> (3,2)
5 -> (2,2)
6 -> (1,2)
7 -> (1,3)
8 -> (2,3)
9 -> (3,3)
Inverse function
The inverse operation of a Euclidean division is a multiplication and an addition:
if y % 2 == 1:
n = 3 * (y-1) + x
else:
n = 3 * (y-1) + 4 - x
I'm making a hexagon tile based game, which generates a honeycomb arrangement of hexagons in a spiral shape. My goal is to convert a world position (e.g. a mouse click) to a spiral coordinate (index / layer / position around layer). I can't think of how to do this, so instead I've been looking to simplify the problem by converting to/from axial coordinates first. How can this be done?
My configuration is pointy-topped as follows:
And here are the spiral indexes:
Axial Coordinates for reference:
I already have these equations for spiral coordinates:
const Layer = (index: number): number => {
return Math.floor((3 + Math.sqrt(12 * index - 3)) / 6);
}
const Position = (index: number, layer: number): number => {
return index - 3 * layer * (layer - 1) - 1;
}
const Index = (layer: number, position: number): number => {
return 3 * layer * (layer - 1) + 1 + position;
}
You can check the individual cases as follows. Here L is layer, P is position, (x, y) are the axial coordinates; coordinates are in agreement with your images.
From (L, P) to (x, y):
if L == 0:
return (0,0)
otherwise:
k = floor(P/L) mod 6
j = P mod L
k x y z
-------------------
0 j L-j -L
1 L -j j-L
2 L-j -L j
3 -j j-L L
4 -L j L-j
5 j-L L -j
From (x, y) to (L, P):
z = -x-y
L = max(abs(x), abs(y), abs(z))
x y z P
------------------------
>=0 >=0 x
<0 <0 L - y
>=0 >=0 2L + z
<0 <0 3L - x
>=0 >=0 4L + y
<0 <0 5L - z
Disclaimer: I didn't test this.
You may also be able to fold some of the cases by exploiting the symmetry, but coding these directly may be easier, albeit a bit more verbose.
You already coded the functions to go between (L, P) and spiral.
I'm working on a POS software that require a Buy X Get Y For Z discount schema, i.e: Buy 5 Get 2 For 5$, it means if you buy 7 items, 5 items are normal price and 2 items (6th, 7th) are 5$.
This is the spreadsheet for this https://docs.google.com/spreadsheets/d/1ym93Xqnw6wupBEp9ei711wQPpt3s6QONjcqBO4Xc5X4/edit#gid=0
I want to a algorithm to get X and Y (discounted item) when input quantity
i.e: input quantity and it will return X and Y for Buy 5 Get 2
input 7 return X = 5, Y= 2
input 8 return X = 6, Y= 2
..
input 17 return X= 13,Y= 4
I'm trying to find formula for this one but I'm failed. Please help me thanks
x = 5
y = 2
i = input
r = i % (x + y)
n = (i - r) / (x + y)
py = max(0, r - x) + (n * y)
px = i - py
return x = px, y = py
To explain, I'm setting r with the modulus/remainder of input / (x + y). This is the number remaining after completed offers are removed. I am then setting n to be the number of complete offers by subtracting the remainder from the input and dividing by (x + y). The variable py is then set using n * y for the number of items at the discounted price for completed offers and adding r - x if that is > 0. Finally px is the number of items at full price which is simply the input value - py.
In your spreadsheet, you have not implemented this correctly. Change as follows:
G2 =A2-F2
H2 =G2/($L$1+$L$2)
D2 =MAX(0,F2-$L$1)+H2*$L$2
E2 =A2-D2
For the offer "Buy x for $P and get y for $Q" you want to work out how many items can be bought at each price if you are buying q items in total.
The simplest approach is to iterate through each item, and figure out if it is bought at the cheaper price or the more expensive price -
qx = 0
qy = 0
for i = 0 : (q-1)
m = mod(i, x + y)
if m < x
qx = qx + 1
else
qy = qy + 1
end
end
Each item will be counted exactly once, so you are guaranteed that qx + qy = q.
I think it could work like this(for the option of BUY 5 GET 2 discounted, it could be generalized for other options):
int x = (input/7)*5;
int y = (input/7)*2;
if((input % 7) == 6){
x+=5;
y++;
}
else
x += (input % 7);
Where input is your total number of items x is number of full priced items and y of discounted items.
I'm treating the situation of having only one item discounted separately, but there might be way to deal with it easier.
This question already has answers here:
Knight's Shortest Path on Chessboard
(18 answers)
Closed 8 years ago.
Is there a mathematical formula one can use to compute the minimum number of knight moves to get between two points in a infinite 2D grid? I can figure it out using a breadth-first search, but is there a closed-form expression we can use instead?
Thanks!
I dont think there is one formula that generates the minimum distands for all pairs of points.
But for some special points there are.
Let A,B be points on a 2D - Grid with A = (0,0) and B = (x,y) and dist(x,y) the minimum number of knight moves.
First of all, the distance is symmetric:
dist(x,y) = dist(-x,y) = dist(x,-y) = dist(-x,-y) = dist(y,x)
Case: 2x=y -> dist(x,2x) = x
Case: x = 0
Subcase 1: y = 4k (k is a natural number)
-> dist(x,y) = 2k
Subcase 2: y = 4k+1 or y = 4k+3
-> dist(x,y) = 2k + 3
Subcase 3: y = 4k+2
-> dist(x,y) = 2k + 2
Case: x = y
Subcase 1: x = 3k (k is a natural number)
-> dist(x,y) = 2k
Subcase 2: x = 3k+1
-> dist(x,y) = 2k + 2
Subcase 3: y = 3k+2
-> dist(x,y) = 2k + 4
If B (with 0 <= x <= y) fits in no case, you know at least
dist(x,y) <= dist(x-k,y-2k) + dist(k,2k) = dist(0,y-2k) + k
and
dist(x,y) <= dist(x-z,y-z) + dist(z,z) = dist(0,y-z) + dist(z,z)
EDIT:
I have thought about it a little more. I think the following algorithm computs the minimum moves (Maple Code):
dist := proc(x,y)
global d;
local temp;
if x < 0 then x:= -x; fi;
if y < 0 then y:= -y; fi;
if x > y then temp := x; x:= y; y:= temp; fi;
if y = 2*x then return x; fi;
if x = y then
if x mod 3 = 0 then return 2*(x/3); fi;
if x mod 3 = 1 then return 2+2*(x-1)/3 fi;
if x mod 3 = 1 then return 4+2*(x-2)/3 fi;
fi;
if x = 0 then
if y mod 4 = 0 then return y/2; fi;
if y mod 4 = 1 or y mod 4 = 3 then return 3+(y - (y mod 4))/2; fi;
if y mod 4 = 2 then return 2+(y-2)/2; fi;
fi;
if y > 2*x then
return dist(0,y-2*x) + dist(x,2*x);
else
return dist(2*x-y,2*x-y) + dist(y-x,2*(y-x));
fi;
end proc:
NOTE: this is only correct on a infinite 2D grid.
EDIT2: This (recursive) algorithm runs in O(1) (time and space) cause it has a constant number of O(1) operations and calls it self at most one more time.
EDIT3: I thought a littel further and I think this is also correkt on a finite 2D grid, if A or B are at least 1 row/column away from at least one border.