Hex rectangular wraparound

 from Red Blob Games
07 May 2018

On the main hex page I have a wraparound system that uses hex grids made of hexes. Someone asked me in email about wraparound for rhombus/rectangular maps. Here are all hexes within a certain distance from a given hex in this wraparound world:

0,01,02,03,04,05,00,11,12,13,14,15,10,21,22,23,24,25,20,31,32,33,34,35,30,41,42,43,44,45,40,51,52,53,54,55,5-3,-6-2,-6-1,-60,-61,-62,-6-3,-5-2,-5-1,-50,-51,-52,-5-3,-4-2,-4-1,-40,-41,-42,-4-3,-3-2,-3-1,-30,-31,-32,-3-3,-2-2,-2-1,-20,-21,-22,-2-3,-1-2,-1-1,-10,-11,-12,-13,-64,-65,-66,-67,-68,-63,-54,-55,-56,-57,-58,-53,-44,-45,-46,-47,-48,-43,-34,-35,-36,-37,-38,-33,-24,-25,-26,-27,-28,-23,-14,-15,-16,-17,-18,-19,-610,-611,-612,-613,-614,-69,-510,-511,-512,-513,-514,-59,-410,-411,-412,-413,-414,-49,-310,-311,-312,-313,-314,-39,-210,-211,-212,-213,-214,-29,-110,-111,-112,-113,-114,-1-6,0-5,0-4,0-3,0-2,0-1,0-6,1-5,1-4,1-3,1-2,1-1,1-6,2-5,2-4,2-3,2-2,2-1,2-6,3-5,3-4,3-3,3-2,3-1,3-6,4-5,4-4,4-3,4-2,4-1,4-6,5-5,5-4,5-3,5-2,5-1,56,07,08,09,010,011,06,17,18,19,110,111,16,27,28,29,210,211,26,37,38,39,310,311,36,47,48,49,410,411,46,57,58,59,510,511,5-9,6-8,6-7,6-6,6-5,6-4,6-9,7-8,7-7,7-6,7-5,7-4,7-9,8-8,8-7,8-6,8-5,8-4,8-9,9-8,9-7,9-6,9-5,9-4,9-9,10-8,10-7,10-6,10-5,10-4,10-9,11-8,11-7,11-6,11-5,11-4,11-3,6-2,6-1,60,61,62,6-3,7-2,7-1,70,71,72,7-3,8-2,8-1,80,81,82,8-3,9-2,9-1,90,91,92,9-3,10-2,10-1,100,101,102,10-3,11-2,11-1,110,111,112,113,64,65,66,67,68,63,74,75,76,77,78,73,84,85,86,87,88,83,94,95,96,97,98,93,104,105,106,107,108,103,114,115,116,117,118,11 Try this:

To calculate the wrapped coordinate range[1] you don't need to calculate distances. Instead, you loop over all nearby hexes, and then wrap them back onto the grid. The wrapping function first looks at how much r changed and then uses that to adjust q. In this particular grid, every time floor(r/8) changes by 1 the q value has to "snap" back by 4.

I also wanted to calculate distances. The simplest thing is to calculate the distance from the original point and each of 8 “mirror” points. Pick the shortest distance to those 9 points. I colored the hexes with the color of the mirror point that was used for the distance. (Note that only 6 of the mirrors, plus the non-mirrored original point, actually get used!)



012321123321234322344333343222332112

Although the mirrors are pretty simple to calculate, I wanted to find a direct approach. I tried using interlaced[2] coordinates (also called double width[3]). The conversion is: x = 2*q + r, y = r. Here are the interlaced coordinates:

0,02,04,06,08,010,01,13,15,17,19,111,12,24,26,28,210,212,23,35,37,39,311,313,34,46,48,410,412,414,45,57,59,511,513,515,5-12,-6-10,-6-8,-6-6,-6-4,-6-2,-6-11,-5-9,-5-7,-5-5,-5-3,-5-1,-5-10,-4-8,-4-6,-4-4,-4-2,-40,-4-9,-3-7,-3-5,-3-3,-3-1,-31,-3-8,-2-6,-2-4,-2-2,-20,-22,-2-7,-1-5,-1-3,-1-1,-11,-13,-10,-62,-64,-66,-68,-610,-61,-53,-55,-57,-59,-511,-52,-44,-46,-48,-410,-412,-43,-35,-37,-39,-311,-313,-34,-26,-28,-210,-212,-214,-25,-17,-19,-111,-113,-115,-112,-614,-616,-618,-620,-622,-613,-515,-517,-519,-521,-523,-514,-416,-418,-420,-422,-424,-415,-317,-319,-321,-323,-325,-316,-218,-220,-222,-224,-226,-217,-119,-121,-123,-125,-127,-1-12,0-10,0-8,0-6,0-4,0-2,0-11,1-9,1-7,1-5,1-3,1-1,1-10,2-8,2-6,2-4,2-2,20,2-9,3-7,3-5,3-3,3-1,31,3-8,4-6,4-4,4-2,40,42,4-7,5-5,5-3,5-1,51,53,512,014,016,018,020,022,013,115,117,119,121,123,114,216,218,220,222,224,215,317,319,321,323,325,316,418,420,422,424,426,417,519,521,523,525,527,5-12,6-10,6-8,6-6,6-4,6-2,6-11,7-9,7-7,7-5,7-3,7-1,7-10,8-8,8-6,8-4,8-2,80,8-9,9-7,9-5,9-3,9-1,91,9-8,10-6,10-4,10-2,100,102,10-7,11-5,11-3,11-1,111,113,110,62,64,66,68,610,61,73,75,77,79,711,72,84,86,88,810,812,83,95,97,99,911,913,94,106,108,1010,1012,1014,105,117,119,1111,1113,1115,1112,614,616,618,620,622,613,715,717,719,721,723,714,816,818,820,822,824,815,917,919,921,923,925,916,1018,1020,1022,1024,1026,1017,1119,1121,1123,1125,1127,11

The wrapped distance can be calculated like this:

    int dx = abs(a.x - b.x) % (2*width);
    int dy = abs(a.y - b.y) % height;
    if (dx > width)    { dx = 2*width - dx; }
    if (dy > height/2) { dy = height-dy; }
    return dy + max(0, (dx-dy)/2);

And here are the distances:

012321123321234322344333343222332112

I think that works!

Email me , or comment here: