[ACCEPTED]-Generating triangular/hexagonal coordinates (xyz)-hexagonal-tiles
Not only is x + y + z = 0
, but the absolute values of 4 x, y and z are equal to twice the radius 3 of the ring. This should be sufficient 2 to identify every hexagon on each successive 1 ring:
var radius = 4;
for(var i = 0; i < radius; i++)
{
for(var j = -i; j <= i; j++)
for(var k = -i; k <= i; k++)
for(var l = -i; l <= i; l++)
if(Math.abs(j) + Math.abs(k) + Math.abs(l) == i*2 && j + k + l == 0)
console.log(j + "," + k + "," + l);
console.log("");
}
Another possible solution, that runs in 8 O(radius2), unlike the O(radius4) of tehMick's solution (at the expense of a lot 7 of style) is this:
radius = 4
for r in range(radius):
print "radius %d" % r
x = 0
y = -r
z = +r
print x,y,z
for i in range(r):
x = x+1
z = z-1
print x,y,z
for i in range(r):
y = y+1
z = z-1
print x,y,z
for i in range(r):
x = x-1
y = y+1
print x,y,z
for i in range(r):
x = x-1
z = z+1
print x,y,z
for i in range(r):
y = y-1
z = z+1
print x,y,z
for i in range(r-1):
x = x+1
y = y-1
print x,y,z
or written a little more 6 concisely:
radius = 4
deltas = [[1,0,-1],[0,1,-1],[-1,1,0],[-1,0,1],[0,-1,1],[1,-1,0]]
for r in range(radius):
print "radius %d" % r
x = 0
y = -r
z = +r
print x,y,z
for j in range(6):
if j==5:
num_of_hexas_in_edge = r-1
else:
num_of_hexas_in_edge = r
for i in range(num_of_hexas_in_edge):
x = x+deltas[j][0]
y = y+deltas[j][1]
z = z+deltas[j][2]
print x,y,z
It's inspired by the fact the 5 hexagons are actually on the exterior of 4 a hexagon themselves, so you can find the 3 coordinates of 1 of its points, and then 2 calculate the others by moving on its 6 1 edges.
This was a fun puzzle.
O(radius2) but with (hopefully) a 11 bit more style than Ofri's solution. It occurred to me 10 that coordinates could be generated as though 9 you were "walking" around the 8 ring using a direction (move) vector, and 7 that a turn was equivalent to shifting the 6 zero around the move vector.
This version 5 also has the advantage over Eric's solution in that it 4 never touches on invalid coordinates (Eric's 3 rejects them, but this one never even has 2 to test them).
# enumerate coords in rings 1..n-1; this doesn't work for the origin
for ring in range(1,4):
# start in the upper right corner ...
(x,y,z) = (0,-ring,ring)
# ... moving clockwise (south-east, or +x,-z)
move = [1,0,-1]
# each ring has six more coordinates than the last
for i in range(6*ring):
# print first to get the starting hex for this ring
print "%d/%d: (%d,%d,%d) " % (ring,i,x,y,z)
# then move to the next hex
(x,y,z) = map(sum, zip((x,y,z), move))
# when a coordinate has a zero in it, we're in a corner of
# the ring, so we need to turn right
if 0 in (x,y,z):
# left shift the zero through the move vector for a
# right turn
i = move.index(0)
(move[i-1],move[i]) = (move[i],move[i-1])
print # blank line between rings
Three cheers for python's 1 sequence slicing.
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
ctx.textAlign = "center";
const radius = 20;
const altitude = Math.sqrt(3) * radius;
const total = 3;
for (let x = -total; x <= total; x++) {
let y1 = Math.max(-total, -x-total);
let y2 = Math.min(total, -x+total);
for (let y = y1; y <= y2; y++) {
let xx = x * altitude + Math.cos(1/3*Math.PI) * y * altitude;
let yy = y * radius * 1.5;
xx += canvas.width/2;
yy += canvas.height/2;
drawHex(xx, yy, radius);
ctx.fillText(x+","+y, xx, yy);
}
}
function drawHex(x, y, radius){
ctx.beginPath();
for(let a = 0; a < Math.PI*2; a+=Math.PI/3){
let xx = Math.sin(a) * radius + x;
let yy = Math.cos(a) * radius + y;
if(a == 0) ctx.moveTo(xx, yy);
else ctx.lineTo(xx, yy);
}
ctx.stroke();
}
<canvas id="canvas" width=250 height=250>
0
Ok, after trying both the options I've settled 8 on Ofri's solution as it is a tiny bit faster 7 and made it easy to provide an initial offset 6 value. My code now looks like this:
var xyz = [-2,2,0];
var radius = 16;
var deltas = [[1,0,-1],[0,1,-1],[-1,1,0],[-1,0,1],[0,-1,1],[1,-1,0]];
for(var i = 0; i < radius; i++) {
var x = xyz[0];
var y = xyz[1]-i;
var z = xyz[2]+i;
for(var j = 0; j < 6; j++) {
for(var k = 0; k < i; k++) {
x = x+deltas[j][0]
y = y+deltas[j][1]
z = z+deltas[j][2]
placeTile([x,y,z]);
}
}
}
The 5 "placeTile" method uses cloneNode to copy 4 a predefined svg element and it takes approx 3 0.5ms per tile to execute which is more 2 than good enough. A big thanks to tehMick 1 and Ofri for your help!
JS
More Related questions
We use cookies to improve the performance of the site. By staying on our site, you agree to the terms of use of cookies.