Audamir

part 09

Tiles from small hexagons, or how to make a map that can be repeated

Every game of the original Dice Wars had a different map. The generator of irregular tiles is a short idea and a long contract with the past: saved games, shared links and the daily challenge.

· updated 2 November 2026 · 9 min read

The first version of the game had six regular tilings: triangles, squares, rhombi, bricks, hexagons, octagons. Pretty, clean and boring. The original Dice Wars looked different. According to the JayIsGames review and the source code of the HTML5 version (a grid of 28 × 32 hexagonal cells and at most 31 tiles), the map was made of tiny hexagons, and each tile came from gluing a few of them together at random. The result: irregular tiles and a different map in every game.

The brief was for Principalities[1] to look like this. And right away a question: will the seed still work when there is so much data? The answer comes in two parts. The generator is a short story. The words "the seed works" are a long story.

How a map is made

The generator is the function Grid.build('blob', …). The procedure can be summed up in seven steps (the documentation counts ten):

  1. The shape of the map. A connected shape (an island, an archipelago, a ring or a rectangle) with roughly 7 N hexagons is chosen from small hexagons (side 1), where N is the number of tiles.
  2. The centres of the tiles. They are scattered evenly: a new centre is accepted only if it is far enough from the accepted ones.
  3. Growth. In each round every tile may take one more hexagon, with a probability given by its "speed" (0.55 to 1.45), so both small and large tiles appear. Hexagons that already have more neighbours in the tile weigh more, so the tiles are connected but irregular.
  4. Repair of the small tiles. A tile with fewer than four hexagons gets hexagons from larger neighbours (if the neighbour does not fall apart). If that is not possible, it disappears, which happens in 3% of the maps.
  5. Smoothing of the borders. A hexagon whose neighbours mostly belong to another tile moves over to it. Two rounds remove most of the thin spurs. The average "compactness" (perimeter against size) dropped from 2.32 to 2.16, the ninth decile from 2.65 to 2.36. A circle has about 1.9 to 2.0.
  6. Holes. The outline of a tile must be a single loop. If a split would enclose another tile or a bay, up to six splits are tried. In practice this happens in 1% of the first attempts and a repeat always solves it; the final merge stays as a safety net.
  7. The outline. It is the union of the hexagons of the tile. And the centre of the tile, where the dice are drawn, is the point farthest from the edge.
A map made by the generator of random shapesAbout thirty tiles of irregular shapes made of small hexagons, told apart by colour according to the players, an island map.
One map from the generator: 32 tiles made of small hexagons, the colours mark the players. The circle in each tile is the place for a stack of dice.

A number for comparison: today (192 maps, 9,479 tiles) a tile has on average 7 hexagons (from 4 to 16), almost 4 neighbours on average (3.95), and a map is generated in about 20 ms.

What the seed has to do with the past

The seed is a text ("KOCKY") from which the whole map is made. That is convenient: a map can be shared by a link, the daily challenge is the same for everyone, and a saved game does not have to carry the outlines of the tiles. A saved game carries only the owner and the number of dice of each tile, and the geometry is generated again on restore. A map with outlines takes about 24 kB, a saved game after three rounds about 10 kB including the record.

But a contract with the past follows from this: the generator must not change in a way that changes the map from the same seed, otherwise all saved games, links and records break. Three safeguards:

  • Plain arithmetic. So that the map comes out the same in every browser, the generator uses only addition, subtraction, multiplication, division and the square root (exactly defined in IEEE 754), a Map with insertion order and sorting with a total order. There is not a single call of Math.sin, Math.cos, Math.log or Math.random in the generator file: functions whose result the standard does not prescribe exactly are not used.
  • The golden fingerprint. A test keeps the fingerprint of a map from a fixed seed. If the generator changes by accident, the test fails.
  • **GEN_VERSION.** If the generator is changed on purpose, the version number is raised and the old saved games are thrown away (and the fingerprint is rewritten). The game never restores a game from a foreign version of the generator.

Games with procedural worlds know the same thing. A seed in Minecraft always holds only for the version of the generator in which it was made. Here the contract is written in a test, not in the developer's memory.

What it did to the game

The new shape must not spoil what had been measured (see the earlier article on calibration). The results:

  • Difficulty: the new value of the setting "Random shapes" has 0 points, so it is as easy as triangles (the level-2 AI wins 18.9%, level 3 wins 34.9%; with hexagons 13.3% and 36.7%).
  • The old world did not move. Eighteen control measurements (--verify) came out identical: the generation of the old shapes did not change by a single bit.
  • The order of the players: the advantage of the first move is the same as with hexagons (2 players 93%, 3 players 61%, 4 players 41%, 8 players 16%).
  • The length of a game: a quarter shorter, because there are fewer tiles (8 to 19 rounds instead of 10 to 22).
  • The fingerprints of the usual games: of 172, only four changed, the ones for Principalities. The other 168 are the same.

The daily challenge deliberately has no random shapes. Adding a value to the list from which the shape of the day is chosen would change the setting of all days, even those that have already been played. This sentence is also guarded by a test.

Verification: 37 mutants

The generator, the drawing and the settings were verified by a mutation check: errors (mutants) are put into the code on purpose, and the tests are tried on whether they find them. Of 37 mutants the tests caught 35, three of them only after the tests were extended with the golden fingerprint of several maps, the terrain icon and maps with holes from a single attempt. The remaining two were equivalent: they were redundant checks (the connectivity of a lake, which the ring of neighbours already guaranteed, and a redundant condition of the smoothing). These were removed from the code. A surviving mutant is either a missing test or useless code.

What I take from it

  • The idea is short, the contract is long. The generator has about three hundred lines. The guarantee that the same seed gives the same map forever is more work than the generator itself.
  • Write the contract into a test. A golden fingerprint can say "it changed" even at three in the morning.
  • The player does not see the generator, the player sees the map. The first idea for the centre of a tile was "right" by the algorithm and wrong by the eye. A check is always a look as well.
  • A surviving mutant is a gift. Either a test, or dead code.

Update of 2 November 2026

On 2 November 2026 the HTML5 version of the original was read in full (What is in the source code of the original (forthcoming article no. 42)), and several places in this article need to be made more precise. The original text stays as it was.

  • How the map of the original is made. The introduction says that "each tile came from gluing a few of them together at random". The grid of 28 × 32 and the cap of 31 tiles are right, but tiles are not glued together: they grow one at a time, each from a core of eight cells and a ring of all the free neighbours of the core, and the next one starts at the candidate with the smallest priority; a tile of five cells or fewer is dissolved. A simulation of 5,000 maps from the description gives 30.0 tiles of 20.5 cells (TUNING §44.2).
  • The section "How the map is made" (seven steps) and the numbers under it describe the generator of "random shapes" of 20 October, not the procedure of the original. Nor is it today's map of Principalities: on 29 October they moved to the map called "field", a rectangle in which the tiles take what they take, drawn by eye from pictures of the original (with 7 players 42.0 tiles of 13.0 cells and 4.19 neighbours; TUNING §44.3). The island with about seven cells per tile stayed in free play. The field is not a copy of the procedure of the original.
  • "The brief was for Principalities to look like this." The brief was to imitate the look of the original (irregular tiles made of small hexagons); its procedure was not known at the time. The copy of the procedure is only the game Tribes, which has been in the development branch of the game since 2 November 2026 (Tribes: a copy that can be measured (forthcoming article no. 43)). Principalities were not changed precisely because of the contract with the past in the section about the seed: changing the generator would break saved games, records and links.
  • Sources. The link to the code of the HTML5 version supports only the grid and the cap on tiles, not the making of a tile by gluing.

Sources and notes

  • The original game: the JayIsGames review and the source code of the HTML5 version (the grid and the number of tiles). Decisions and numbers: docs/DESIGN.md §19, the procedure docs/TUNING.md §18. Statistics: node tools/blobs.js (20 October 2026; the map in the article: node tools/blobs.js --svg mapa.svg --seed KOCKY --target 32 --map island).
  • Minecraft: the seed together with the version of the game determines the world; the generator changed between versions. A generally known fact, not from a measurement.

Notes

  1. Until version 0.65.6 of 31 October 2026 it was called Classic. ↩︎