Why try a different shape?
The grid languages in the Funge family use squares, which suits both text and screens. A square cell has four edge neighbors, so the pointer has four directions, and turning is easy to picture: left, right, around. A hexagonal layout asks a natural question. What if each cell had six neighbors instead of four? The answer is that many small things change, and some of them are not obvious until you try.
The best-known language that took this idea to its limit is Hexagony. This article uses it as a main example but the ideas are general to any hexagon-based design.
Six neighbors
On a square grid, a cell touches four others along its edges, and four more at its corners. Languages normally ignore the diagonal ones, which keeps the model simple. On a hexagonal grid, every neighbor shares an edge, and there are six of them. There is no diagonal ambiguity at all, because every neighbor is the same distance from the center.
That tidiness has a price. Square directions line up with “up”, “down”, “left” and “right”, words that are already in our heads. Six directions do not. The usual choices are to name them by compass-like labels, or to draw the grid with the hexagons arranged so that two neighbors are east and west and four are diagonal. Either way, the programmer has to learn a new vocabulary of movement.
Turning is different
On a square grid, the turns are quarter turns, 90 degrees. A reflection off a diagonal mirror sends a pointer moving right to up or down, again 90 degrees. Everything sits on one clean set of angles.
On a hexagonal grid, the natural turn is 60 degrees. A pointer can turn slightly, as if steering a ship, or reverse completely at 180 degrees. Because there are three axes of travel instead of two, a mirror can reflect a pointer in more than one way depending on which of its six approach directions it arrives from. That is the same context-dependence as in square-grid mirror commands, but with more cases to remember.
A practical result is that tracing by hand takes longer. On a square grid you can often follow the path with your finger and a feel for geometry. On a hexagonal grid, the same instinct is less reliable at first.
Counting cells
A common way to lay out source code is as a regular hexagon: one cell in the middle, ringed by six cells, then twelve, and so on. If the side length is n cells, the total number of cells is 3n(n − 1) + 1. For example:
| Side length | Total cells |
|---|---|
| 1 | 1 |
| 2 | 7 |
| 3 | 19 |
| 4 | 37 |
Check the second row: 3 × 2 × 1 + 1 = 7, which is one center cell plus a ring of six. For side length 3, 3 × 3 × 2 + 1 = 19, which is those seven plus a ring of twelve. These totals mean that source code usually has to be padded with no-operation cells to fill out the hexagon, and a program of arbitrary length does not always fit neatly. Hexagony handles this by choosing the smallest hexagon that can hold the text, then filling any remaining cells with no-operations.
What happens at the edges
On a square playfield with wrapping, the rule is simple. Leaving the right edge brings you back on the left, and leaving the bottom brings you back at the top. This produces the toroidal playfield familiar from Befunge.
A hexagon has six sides, and pairing them up is less obvious. The pointer might wrap to the opposite side, but the exact cell it lands on depends on the design, since sides do not line up in rows the way rectangle edges do. Hexagony defines particular rules for how the pointer moves from one edge to another, and some interpreters illustrate these with diagrams. This is one of the places where it pays to read the language specification closely rather than guess.
Memory can be hexagonal too
Hexagony is unusual because it does not stop at the code layout. Its memory model is also built from hexagonal geometry, rather than from a stack or a tape. As a rough picture, memory is a network of cells with a movable pointer, and operations move that pointer to neighbors. The details are specific and take some study, so look to the documentation of the language for them. The relevant point here is that the geometry runs through the whole design, in contrast to Befunge, where the grid holds code and the stack holds data.
Hexagony is also notable for letting more than one instruction pointer exist, with the program switching between them. That design choice is separate from the hexagon itself, but it fits the way six corners offer natural starting points. Compare this with concurrent pointers in Funge-98, where the split instruction creates additional pointers on a square grid.
When a hexagonal grid helps
Hexagons are not simply a more exotic costume. Their qualities suit some tasks.
- Uniform distance. Every neighbor is equally far away, which removes the corner-versus-edge distinction of square grids.
- Compact shapes. A hexagon is closer to a circle than a square, so regular patterns can be tighter.
- Smooth turning. The 60-degree steps allow gentler curves.
And they have costs.
- No natural text layout. Text is written in rows, and a hexagon needs an unusual reading order.
- Harder to edit. Most editors are not designed for hexagonal layouts, so programmers either use special tools or work with an unfamiliar flattened view.
- Fewer shared habits. Mental models from square grids transfer only in part.
Thinking about the design choice
Choosing a grid is a language design decision in the same sense as choosing a stack or a tape. It influences everything downstream: what a loop looks like, how wrapping works, how hard it is to write an interpreter, and who will enjoy using the language. A square grid is easy to implement, since a two-dimensional array stores it directly. A hexagonal grid also fits an array, but you need conversion rules between rows, columns and directions. Many hobbyists find that writing a small interpreter for a hexagonal grid is a good way to understand what the geometry really costs.