-
-
Save HexDecimal/0c21a64e9a86d25603a4d1ddd2b9c397 to your computer and use it in GitHub Desktop.
# To the extent possible under law, Kyle Stewart has waived all copyright and | |
# related or neighboring rights to this work. | |
# This work is published from: United States. | |
import functools | |
from typing import Any, Tuple | |
import numpy as np # type: ignore | |
@functools.lru_cache | |
def ring(radius: int, offset: int = 0, roll: int = 0) -> Tuple[np.ndarray, np.ndarray]: | |
"""Return an advanced NumPy index of a ring on the array.""" | |
index: Any = [] | |
for x in range(-radius, radius + 1): | |
index.append((x, -radius)) | |
for y in range(-radius + 1, radius + 1): | |
index.append((radius, y)) | |
for x in range(radius - 1, -radius, -1): | |
index.append((x, radius)) | |
for y in range(radius, -radius, -1): | |
index.append((-radius, y)) | |
index = np.transpose(index) | |
index += offset | |
index = np.roll(index, roll, 1) | |
index.flags["WRITEABLE"] = False | |
return index[0], index[1] | |
def rotate45(arr: Any, times: int = 1) -> np.ndarray: | |
"""Return a 2D array rotated by 45 degrees. | |
`arr` is a square array-like object with an odd-numbered size. | |
`times` is the number of times to rotate the array counter-clockwise by | |
45 degrees. | |
""" | |
out = np.copy(arr) | |
assert out.shape[0] == out.shape[1] | |
assert out.shape[0] % 2 != 0 | |
times %= 8 | |
radius = offset = out.shape[0] // 2 | |
for i in range(radius + 1): | |
out[ring(i, offset)] = out[ring(i, offset, i * times)] | |
return out |
You wanted diagonal tiles so you don't need to go full hexagonal anything. The hexagon examples were all using rectangular arrays, and if that's difficult to understand then I'll have a hard time explaining it.
So back to these:
0,0
1,0 0,1
2,0 1,1 0,2
2,1 1,2
2,2
0,0 0,1 0,2
1,0 1,1 1,2
2,0 2,1 2,2
They might look like two different arrays, but that is wrong. They are the same array but with a different way of representing them. The lower representation makes it clear how they're stored as a contiguous array. The above is how you want to display them.
So where X goes SW and Y goes SE:
0,0
x,0 0,y
... x,y ...
To convert the tile index from a grid to where it's displayed you could use a transform function like this basic one:
def grid_to_diamond(x: int, y: int) -> Tuple[int, int]:
"""
Example:
>>> grid_to_diamond(0, 0)
(0, 0)
>>> grid_to_diamond(1, 0) # SW
(-1, 1)
>>> grid_to_diamond(0, 1) # SE
(1, 1)
>>> grid_to_diamond(1, 1) # S
(0, 2)
"""
return y - x, y + x # SW:(-x, x) + SE:(y, y)
This kind of math can be "simplified" if you understand how to use transformation matrices.
>>> import numpy as np
>>> m = np.matrix([[-1, 1], [1, 1]]) # SW:(-x, x) + SE:(y, y)
>>> [1, 1] @ m.A # Same as grid_to_diamond.
array([2, 0])
>>> m.I # Inverted matrix.
matrix([[ 0.5, 0.5],
[-0.5, 0.5]])
>>> [2, 0] @ m.I.A # Transform the display position back into the grid position.
array([1., 1.])
This is stuff I haven't worked with in a while, and when I did work with it I didn't have NumPy at the time. I might be too rusty on this topic to explain it any better. The best advice I can give you is to tell you that your diamond tiles are just a 2D grid that's been tilted, and you should not "tilt" your data when you store it.
Hi there, sorry it took a bit to get back to you.
I am sorry, I am struggling to understand how to change the hexagon example to a rectangular array with code. Do you have any ideas how to implement what you said on the most recent comment you made?