A Python library and command-line program for generating centered consecutive zero-sum magic hexagons.
For conventional order n, the board has
3*n*n - 3*n + 1
cells and uses every integer in the centered interval exactly once. Every line in all three hexagonal-grid directions sums to zero.
See the blog post about the discovery of this algorithm: https://gukov.dev/math/2026/08/02/new-magic-hexagons.html.
uv syncRun the test suite:
uv run pytestThe runtime package has no third-party dependencies. Pytest and coverage are development dependencies managed through pyproject.toml.
The command accepts the order, not the geometric radius.
Print an order-28 hexagon in MHX format to stdout:
uv run magic-hexagons 28Write JSON, CSV, plain text, or MHX:
uv run magic-hexagons 40 -o order40.json
uv run magic-hexagons 40 -o order40.csv
uv run magic-hexagons 40 -o order40.txt
uv run magic-hexagons 40 -o order40.mhxThe format is inferred from the output suffix, or selected explicitly:
uv run magic-hexagons 40 --format json > order40.jsonA .gz output suffix enables gzip compression:
uv run magic-hexagons 100 -o order100.mhx.gzDefault behavior is equivalent to:
uv run magic-hexagons ORDER --format mhx --output -Order 1 is the trivial one-cell hexagon. Order 2 has no centered consecutive zero-sum solution. All orders from 3 onward are supported.
from magic_hexagons import generate, verify, dumps_mhx, write
hexagon = generate(order=40)
report = verify(hexagon)
assert report.valid
print(dumps_mhx(hexagon))
write(hexagon, "order40.json")MagicHexagon.values maps cube coordinates (q, r, s), with q + r + s == 0, to integer labels.
center = hexagon[(0, 0, 0)]
rows = hexagon.rows
line_sums = hexagon.line_sums()Public helpers include:
cell_count(order)coordinates(order)row_lengths(order)expected_domain(order)dumps(..., format="mhx" | "json" | "csv" | "txt")loads_mhx(...),loads_json(...)read(...),write(...)verify(...)
Orders 13 and above use one uniform deterministic construction:
- Build the rank circuit field
q_R. It is a sum of associativity circuits, gives diagonal coefficientkat(k,k), and has every off-diagonal coefficient between -3 and 3. - Build the checkerboard circuit field
s_R, also from associativity circuits. - Form
h_R = q_R + 4*s_R. Since 4 dominates the rank-field bound, all off-diagonal coefficients are nonzero. - Use two explicit global forests to absorb the common large part of all diagonal values simultaneously.
- Convert transpose-pair coefficients into differences of consecutive ranks. Repeated gaps use perfect blocks; only linearly many residual gaps remain for a deterministic descending placement.
- Combine the shifted triangle with the all-radius packet splitter and extend by half-turn antisymmetry.
The implementation is O(n²) in time and memory, matching the size of the generated board. It does not use NumPy, SciPy, MILP, Langford sequences, annulus certificates, local diagonal-repair tables, or search.
The two-forest formula starts at radius 12, i.e. order 13. Orders 3–12 therefore use bundled finite witnesses. No witnesses are bundled for order 13 or above.
generate() independently verifies the complete coordinate set, centered label domain, uniqueness, and every line sum by default. Pass verify_result=False to skip that final verification.
The default output begins with metadata:
MHX 1
kind: filled
order: 28
magic: 0
domain: -1134..1134
...
rows:
Rows follow from top to bottom, with entries from left to right.