Hacker News new | past | comments | ask | show | jobs | submit login
Everything you ever wanted to know about hexagonal grids (redblobgames.com)
462 points by fivedogit on Jan 25, 2015 | hide | past | web | favorite | 39 comments

That's neat. I spend my work days simulating advanced nuclear reactors that have hexagonal fuel assemblies. In my codes I've used a lot of this info. This is an excellent resource that I'll be referring people who come from the more traditional square lattice world.

Tangentially related, I have heard of modelling forest fires with cellular automata.


The grid is usually rectangular, and I've always found this a bit odd: hexagons represent 2-d sphere packing, so they always seemed more natural to me. I once asked researchers in the field about this, around 2006, and they responded that rectangular grids serve just as well. I just found this paper from 2007 where apparently hexagonal grids fare better:


This makes me wonder, for realistic models that are meant to model a notion of neighbour cells, why aren't we always using hexagonal grids in 2d or higher-dimensional analogues? With rectangular grids, you're always faced with the choice of defining whether touching on edges and corners count as neighbours or not, which seems like an unnatural choice. Why, then, does this not seem to matter in the end?

If rotational symmetry is important to the dynamics, you're likely to do much better on coarse grids with a hex layout, because it has a finer rotational symmetry.

Of course, with a small-enough grid rotational symmetry should be restored (or you've chosen a poor discretization!). One might rephrase your statement as: the lattice artifacts / discretization errors vanish faster on a hex grid. Could be.

When I worked on fire-spreading models [0] the grids we used were square. I would wager that this is because it makes thinking significantly easier. In my current field[1], square lattices are chosen because of the underlying supercomputing architecture. The communication mesh in tera- and petascale computers tend to be rectangular [2]. At these scales, having a nice rectangular layout of the local subvolumes simplifies communication algorithms and can provide a dramatic speedup---in this case having fewer neighbors is better.

[0]: In high school I implemented the fact that fires burn faster uphill while working for David Keyes on http://www.cs.cmu.edu/~caliente/

[1]: Lattice QCD codes use a (4D spacetime) rectangular lattice https://usqcd-software.github.io/

[2]: The BlueGene/Q, for example, is a 5-dimensional rectangular torus.

Square grids are more intuitive: they map to our standard cardinal and ordinal directions. As long as you treat the ordinal neighbours (the corners) as being sqrt(2) away from the center (as oppposed to 1 away from the center like the cardinal neighbours, or all of the hexagonal neighbours) then you don't get spatial distortions.

I can provide an intuitive thought picture answer, that if you're doing something that boils down to numerical integration under a curve, a pile of hexagons or other polygons will win over a simple raster array of square pixels at a similar quantity of polygons, but when implemented, if its computationally cheaper to run the rectangular raster array at 10, 100, maybe 1000 times the resolution of the hexagon implementation, then the raster will always win at the overall systemic level at the numerical integration game. Not implying forest fires are simple numerical integration games, but they are similar-ish in trying to discrete-ize a non-discrete analog problem.

If you were talking about EE DSP stuff, you'd call it quantization noise. Theoretically a floating point A/D converter would be nice / interesting if such a thing existed, but in practice you minimizing that noise source by using more fixed bits per sample.

As far as I know the reason why square lattices are preferred over hex lattices is that they can easily generalized to 3D, ... . If you invest lots of time thinking about good, say, FEM or Finite Volume algorithms, you want to have results that can easily generalized afterwards.

Actually there is a simple 3D analog of the hexagonal grid, which occurs in crystal structures. Somewhat interestingly there are two variants, known in crystallography as Face-Centred Cubic and Hexagonal Close Packing. http://en.m.wikipedia.org/wiki/Close-packing_of_equal_sphere...

In higher dimensions there are applications to broadband coding (you want the densest possible constellation).


Though perhaps more relevant to FEM is the tetrahedral mesh...

Both types are important. The math is indeed more complicated for square meshes, but you can use the fact that the basis functions (is this the proper English translation of the German "Basisfunktionen"?) on square elements have more degrees of freedom to sometimes get better approximations.

Disclosure: I heard some advanced lectures about FEM intended for students who intended to write a diploma thesis about this topic.

As a part of my university coursework I modeled forest fires with a grid but mine had varying densities of forests and each tree affected an area around it, not just adjacent cells. It's a really interesting thing to try and model if you get a chance, because tiny adjustments can make a world of difference.

Just a conjecture, but, it may not always be possible/straightforward to map a set of CA rules meant for a rectangular grid to a hex grid.

Fascinating! One of Affirm's old job application puzzles was about a hexagonal grid. I did a write-up[1] of how I solved it, unaware that I was reinventing the wheel. The cube coordinates abstraction would have been killer for being able to explain things to myself.

[1]: http://vincentwoo.com/2013/03/08/above-and-beyond-the-affirm...

That's funny, I brought this exact puzzle up last time this link was posted. Twins! Nice solution.


This was a fantastic article -- examples were concise and clear, and everything was well-written.

Tangentially, I'd love to know the best way to create the visuals for this kind of content. I assume no one's writing all those SVGs by hand, right?

Thanks! (I'm actually in the middle of a major update to the page — I hope to have it published in a few weeks)

I used d3.js for this page (and most of the pages on my site).

For a given shape of map (rectangular, triangular, hexagonal, parallelogram, etc.) I generate a set of cube hex coordinates. I then use d3 to instantiate an SVG shape for each coordinate. D3 will maintain the mapping from the cube coordinate to the SVG shape, so I can set element classes on mouse events, and then I style those with CSS.

For example, in the line drawing example, I have a generic function that creates a hexagonal shaped grid (of hexagons)[1]. On mouseover, I figure out which hex it is, then run the line drawing algorithm to create a set of coordinates from the start point to the hex you're pointing to. I then tell d3 to iterate over all the SVG dom nodes and set the "selected" class if it's in the set returned by the line drawing routine[2]. The color changes with the CSS rule #diagram-line .selected polygon {fill: hsl(200, 50%, 80%); }

I've used canvas for some of the pages but I find svg much easier to work with. I can attach mouse events to the elements, and I can set properties (such as color) easily without redrawing everything. D3 is great for maintaining a mapping from data (such as a set of hex coordinates) to dom nodes (such as a set of svg <polygon>s). D3 also has transitions, but I think most of my needs could be handled with CSS transitions instead of D3's JS transitions.

[1] See http://www.redblobgames.com/grids/hexagons/Grid.hx : hexagonalShape() [2] See http://www.redblobgames.com/grids/hexagons/ui.js : makeLineDrawer()

I've never seen hex described this way, but here's how I envision simplifying their logic in games:

a regular 2d array, but with every-other row logically offset by 50% of the cells width, thus you end up with:

  [  ][  ][  ][  ][  ]
    [  ][  ][  ][  ][  ]
  [  ][  ][  ][  ][  ]
    [  ][  ][  ][  ][  ]
  [  ][  ][  ][  ][  ]
    [  ][  ][  ][  ][  ]
super simple data structure (normal 2d array), and pathfinding isn't difficult (use hex algos). I wonder why nobody ever writes about this....

Edit: ahh, the article kind-of describes this in the "Offset coordinates" section, just no explicit mention of able to use an array for storage.

The offset approach is what most people do. I've used it too. It makes the storage simpler for rectangle shaped maps but the algorithms more complicated (and slower). I wrote this page to present the alternative coordinate systems. The symmetry of the cube system greatly simplifies many of the algorithms, so it's often easier to convert offset or axial to cube, run the algorithm, and then convert the answer back to offset or axial. The main downside of axial is that map storage in an array is a little more complicated; http://www.redblobgames.com/grids/hexagons/#map-storage

Why are we storing in an array at all? Why keep that last vestige of rectangular representation?

How about storing the map directly in cubic coordinates? The storage structure would be a dictionary with a three-value tuple as the key. Iterating along any of the three axes is perfectly simple, and all directions work the same way. Algorithms like A* work directly on a list of neighboring hexes with no coordinate conversion required. Serialization to a savegame format or network communication would look like JSON with key-value pairs of the 3-tuple (key) to the tile data (value).

The advantage of the 2D array structure is only a bit of performance, that the coordinates of each tile are implicitly defined by the array indices. I'd venture to say that our modern languages and platforms don't need that optimization any more. We insert another layer of abstraction in decoupling the tile's coordinates away from its storage location in memory.

Put another way, the only conversion occurring is between the 3-tuple key and the physical location in memory, and that's abstracted away from us in whatever mechanism (hashtable or whatever) that the dictionary uses internally. Everything at the application level works directly with cubic coordinates. By getting rid of the 2D array storage, we get rid of the last remnants of anything rectangularly-related, with never any need at all to convert to the rectangular vestiges of axial or offset coordinates.

Have you actually tried implementing something like A*? The inner loop is very tight, and putting several easily avoided dictionary lookups in there is just silly.

Given how simple it is to write a solid abstraction that implements the coordinate-based lookup with an array storage, and given how much better such an implementation behaves in terms of instruction counts and memory layout (think cache locality), you'd be silly not to use an array.

I understand the concerns, but the same "have you tried implementing" concern applies there too. This is premature optimization, until you do it both ways and profile it and see if the runtime difference matters. Cache locality is a thing, but so is prematurely guessing about cache locality.

Not everything using A* runs millions of pathfinding queries in tight loops. Maybe it's an offline turn-based game that runs A* once per move and saving 10 μs just won't ever matter as compared to the complexity cost of implementing and maintaining the extra abstraction.

While I appreciate your concern about premature optimization, having 2D arrays as fundamental data structures in this kind of thing is so common that it just seems bizarre that you even call it an optimization. The resulting code is just as simple and natural, after all.

Perhaps we need a countering meme about gratuitous de-optimization...

Isn't that precisely what the linked paged calls '"odd-r" horizontal layout' ?

yeah it is (see my edit), but it may not be obvious to would-be implementers that their data structure could be modeled as an array.

Wow. The interactive examples make for one of the most impressive tutorials I've ever come across. Great job, amitp!

I would like to see a game on a Penrose tiling. Obviously you couldn't make it wrap though.


The lack of wrapping would be fine for something like Minecraft, where the world could be generated radially outwards from the starting point :)

That is an amazing resource and I used it when developing my hex game library for PixiJS.


I used it to to build the rule system for my game engine.

I've explored similar questions using a grid of equilateral triangles. Obviously they are very close in spirit. I wonder though, if the triangles are somehow more basic.

The triangular grid is dual to the hexagonal grid -- if you take a hexagonal grid, put a vertex in the center of each hexagonal tile, then form tile edges by connecting each vertex to its six neighboring vertices, you get a triangular grid. Doing the same operation to the triangular grid gives you the hex-grid back again.

It is maybe worth noting that triangles are 2D simplices, so for a non-flat mesh, triangles are a simpler solution. Hexagons won't always be flat. There's a literature of progressive mesh transmission that does fun things with mesh topology. Not sure if it's still a live topic but I remember a paper with nice illustrations from 2001: http://citeseerx.ist.psu.edu/viewdoc/summary?doi=

I wonder what a non-cubic polyhedron-based voxel system would look like, without going all the way to marching cubes/tetrahedrons (where the cubes/tetrahedrons are only part of the algorithm that helps in rendering basically arbitrary voxels).

To wit: http://mathworld.wolfram.com/Space-FillingPolyhedron.html

If you want to get into grid programming, the MOAI framework has pretty good support, and the samples are pretty easy to grok: https://github.com/moai/moai-dev/blob/develop/samples/grid-h...

For anyone who hasn't read it, (and is interested ofc.) this website has one of the best explanations of A* I've ever read.


Wow, I've been trying to make a Settlers of Catan game for fun and the thing I struggle most with is the board algorithms. This a fantastic resource to help with that, thanks.

Very comprehensive. Enjoyed the interactive examples.

This is such a good resource!

brilliant article!

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact