diff --git a/CMakeLists.txt b/CMakeLists.txt index 37c0f54..9d4af5d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ include(cmake/setup.cmake) add_library(common combi.c divvy.c drawing.c dsf.c findloop.c grid.c latin.c - laydomino.c loopgen.c malloc.c matching.c midend.c misc.c penrose.c + laydomino.c loopgen.c malloc.c matching.c midend.c misc.c penrose.c hat.c ps.c random.c sort.c tdq.c tree234.c version.c ${platform_common_sources}) @@ -264,12 +264,14 @@ puzzle(untangle OBJECTIVE "Reposition the points so that the lines do not cross.") add_subdirectory(unfinished) +add_subdirectory(aux) cliprogram(obfusc obfusc.c) cliprogram(latincheck latin.c COMPILE_DEFINITIONS STANDALONE_LATIN_TEST) cliprogram(matching matching.c COMPILE_DEFINITIONS STANDALONE_MATCHING_TEST) cliprogram(combi combi.c COMPILE_DEFINITIONS STANDALONE_COMBI_TEST) cliprogram(divvy divvy.c COMPILE_DEFINITIONS TESTMODE) +cliprogram(hat-test hat.c COMPILE_DEFINITIONS TEST_HAT) cliprogram(penrose-test penrose.c COMPILE_DEFINITIONS TEST_PENROSE) cliprogram(penrose-vector-test penrose.c COMPILE_DEFINITIONS TEST_VECTORS) cliprogram(sort-test sort.c COMPILE_DEFINITIONS SORT_TEST) diff --git a/aux/CMakeLists.txt b/aux/CMakeLists.txt new file mode 100644 index 0000000..82e8c82 --- /dev/null +++ b/aux/CMakeLists.txt @@ -0,0 +1 @@ +cliprogram(hatgen hatgen.c COMPILE_DEFINITIONS TEST_HAT) diff --git a/aux/doc/arrow.svg b/aux/doc/arrow.svg new file mode 100644 index 0000000..1804e19 --- /dev/null +++ b/aux/doc/arrow.svg @@ -0,0 +1,4 @@ + + + + diff --git a/aux/doc/expanded-F.svg b/aux/doc/expanded-F.svg new file mode 100644 index 0000000..71a1b2b --- /dev/null +++ b/aux/doc/expanded-F.svg @@ -0,0 +1,84 @@ + + + + +0 + + +1 + + +2 + + +3 + +4 + +5 + +6 + +7 + +8 + +9 + +10 + diff --git a/aux/doc/expanded-H.svg b/aux/doc/expanded-H.svg new file mode 100644 index 0000000..2ccc4d4 --- /dev/null +++ b/aux/doc/expanded-H.svg @@ -0,0 +1,99 @@ + + + + +0 + + +1 + + +2 + + +3 + + +4 + + +5 + + +6 + +7 + +8 + +9 + +10 + +11 + +12 + diff --git a/aux/doc/expanded-P.svg b/aux/doc/expanded-P.svg new file mode 100644 index 0000000..e688525 --- /dev/null +++ b/aux/doc/expanded-P.svg @@ -0,0 +1,84 @@ + + + + +0 + + +1 + + +2 + + +3 + + +4 + +5 + +6 + +7 + +8 + +9 + +10 + diff --git a/aux/doc/expanded-T.svg b/aux/doc/expanded-T.svg new file mode 100644 index 0000000..c39b59a --- /dev/null +++ b/aux/doc/expanded-T.svg @@ -0,0 +1,54 @@ + + + + +0 + + +1 + + +2 + + +3 + +4 + +5 + +6 + diff --git a/aux/doc/hat-kites.svg b/aux/doc/hat-kites.svg new file mode 100644 index 0000000..a8fadbc --- /dev/null +++ b/aux/doc/hat-kites.svg @@ -0,0 +1,33 @@ + + + + + + + + + + +0 +1 +2 +3 +4 +5 +6 +7 + diff --git a/aux/doc/hatmaps.html b/aux/doc/hatmaps.html new file mode 100644 index 0000000..92d26c3 --- /dev/null +++ b/aux/doc/hatmaps.html @@ -0,0 +1,62 @@ + + + +Kitemaps and metamaps for the hat tiling generator + + + +

Kitemaps and metamaps for the hat tiling generator

+

See hats.html for the full explanation.

+

Here's the full set of kitemaps and metamaps for all the tile + types:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Tile nameOriginal tileFirst-order expansionKitemapMetamap
H
T
P
F
+ + diff --git a/aux/doc/hats-single-F.svg b/aux/doc/hats-single-F.svg new file mode 100644 index 0000000..bac6010 --- /dev/null +++ b/aux/doc/hats-single-F.svg @@ -0,0 +1,35 @@ + + + +0 + +1 + diff --git a/aux/doc/hats-single-H.svg b/aux/doc/hats-single-H.svg new file mode 100644 index 0000000..f7017ea --- /dev/null +++ b/aux/doc/hats-single-H.svg @@ -0,0 +1,67 @@ + + + +0 + +1 + +2 + +3 + diff --git a/aux/doc/hats-single-P.svg b/aux/doc/hats-single-P.svg new file mode 100644 index 0000000..83b147e --- /dev/null +++ b/aux/doc/hats-single-P.svg @@ -0,0 +1,35 @@ + + + +0 + +1 + diff --git a/aux/doc/hats-single-T.svg b/aux/doc/hats-single-T.svg new file mode 100644 index 0000000..146788e --- /dev/null +++ b/aux/doc/hats-single-T.svg @@ -0,0 +1,19 @@ + + + +0 + diff --git a/aux/doc/hats.html b/aux/doc/hats.html new file mode 100644 index 0000000..ab73ccc --- /dev/null +++ b/aux/doc/hats.html @@ -0,0 +1,258 @@ + + + +Generating hat tilings for Loopy + + + +

Generating hat tilings for Loopy

+

The original paper + describes a method for generating hat tilings from a system of four + 'metatiles'. You can start with any one of the four tiles, and then + recursively apply a set of expansion rules that turn each tile into + a collection of smaller tiles from the same set.

+

This table shows the four tiles, with their one-letter names as + given in the paper, and how each one is expanded.

+

All the tiles have a significant orientation. The H, T and P + tiles are marked with arrows to indicate the orientation. The F tile + is asymmetric, so no arrow is needed.

+

I've assigned each tile in each expansion a number, which Loopy + will use for its coordinate system.

+ + + + + + + + + + + + + + + + + + + + + + + + + +
Tile nameSingle tileExpansion
H
T
P
F
+

Note that these expansions overlap. When two + adjacent metatiles are expanded, the outer layer of P and F tiles in + their expansions must be placed so that they overlap each other. The + original paper suggests a set of tiles to remove from these + expansions so that each metatile expands to a disjoint set + of smaller tiles. In our implementation, however, we prefer to keep + the overlap, because our coordinate system will use it.

+

Once you've generated a large enough patch of metatiles for your + needs, the final step is to convert it into the actual hat tiles. + The expansion of each metatile into hats is shown here. Again, I've + assigned numbers to each hat for coordinate-system purposes:

+ + + + + + + + + + + + + + + + + + + + + + + + +
Tile nameConversion into hats
H
T
P
F
+

(The hat in the middle of the H is shaded to indicate that it's + one of the rare reflected ones. All the other hats are rotations of + each other.)

+

Given all of this, an obvious approach to generating a random + patch of hat tiling would be to start with a single metatile, + iterate the expansion process a few times until you have a tiled + area much larger than you need, and then pick a subrectangle of + it at random.

+

Loopy's algorithm for generating Penrose tilings (which admit a + similar, though less complicated, expansion system) works in exactly + this way.

+

One problem with that algorithm is that it spends a lot of effort + on generating huge areas of tiles that aren't actually needed. So + you'd prefer to adjust the algorithm so that at every stage of + expansion it spots tiles completely outside the target rectangle, + and throws them away before spending 5 iterations on + exponentially expanding them into huge amounts of detail that will + only be thrown away anyway later.

+

That works well for Penrose tilings, because there, the expansion + procedure is geometrically precise: coordinates in the expanded + tiling are scaled up by an exact factor from coordinates in the + original tiling. So at every stage it's easy to know exactly where + your target rectangle is, and discard things that don't + overlap it.

+

But the metatiles shown here don't have that property. The tiles + distort slightly as they expand. The topological properties + of the expanded tiling match the original (which expanded tiles + connect to each other), but the geometry (precise distances) is + different. So it would be harder to implement the pruning for this + tiling. The target rectangle might not even be rectangular in every + iteration!

+

Instead, I came up with a completely different mechanism, by + devising a coordinate system to track our position within multiple + layers of tile expansion. This allows us to generate precisely the + area of tiling we need, and waste no effort at all on anything + outside the target region.

+

We begin by assigning an integer index to each kite making up an + individual hat:

+ +

(For a reflected hat, these indices work in mirror image, so that + for example 5 is still the kite in the middle.)

+

Together with the indices we've assigned to hats within each + metatile, and to metatiles in the expansion of another metatile, + this gives us a coordinate system that can identify an individual + kite in an n-times-expanded metatile. For each large metatile + expansion, you can give the index of the smaller metatile selected + from its expansion; when we reach the last layer of metatiles and + expand them into hats, we can give the index of the hat in that + metatile; finally we can index the kite in that hat.

+

But note that a kite can have multiple + coordinates, because of the overlap between the expansions + of adjacent metatiles. This will be useful!

+

Our next step is to unambiguously name the four directions in + which you can move from one kite to an adjacent kite. The directions + should be independent of the orientation of the kite. I've chosen to + name them from the viewpoint of someone standing at the pointy end + of the kite and looking towards the blunt end:

+
+
Left
+
Rotate 60° anticlockwise about the pointy end of the kite. For + example, in the above hat, going 'left' from kite 5 takes you to + kite 4.
+
Right
+
Rotate 60° clockwise about the pointy end. From kite 5, this + would take you to kite 6.
+
Forward left
+
Head forwards and slightly left, to the kite sharing the + left-hand one of this kite's short edges (as seen from the + centre). Equivalently, rotate 120° clockwise about the + blunt end. From kite 5, this takes you to kite 2.
+
Forward right
+
Head forwards and slightly right. Or rotate 120° anticlockwise + about the blunt end, if you prefer to think of it that way. From + kite 5, this takes you to kite 1.
+
+

The idea is that if we know how to transform the coordinates of a + single kite into the coordinates of each of those four adjacent + kites, then we can iterate that over a whole area and determine the + coordinates of every kite in the whole tiling.

+

Having done that, it's easy to identify each individual kite, by + several different methods. For example, you could iterate over edges + of the tiling to see whether the kites on each side have coordinates + differing only in the kite index; if so, they're part of the same + hat, and if not, not. Or a completely different approach (in fact + the one Loopy actually uses) would be to trace round the boundary of + each hat by starting from its kite #0 and just knowing what shape a + hat is.

+

So now we have to come up with an algorithm that lets us + transform a kite coordinate by making one of the four permitted + moves. To do this, we use two multilevel types of map.

+

The kitemap for a given metatile type is made by + expanding the metatile once into more metatiles, and then into hats. + For example, the T tile:

+ + + + + + + + +
+

In each kite, we show a three-part coordinate, in little-endian + fashion (because that matches the order the coordinates are stored + in an array in the code that actually generates the tilings). For + example, 7.3.0 means kite 7 in hat 3 of metatile 0 of the + expansion.

+

This map can be converted into a lookup table, indexed by those + three-part coordinates and also the four move directions, which + allows you to look up that (for example) going Left from kite 7.3.0 + goes to 0.0.0, or going Forward Left from 7.3.0 goes to 3.1.3.

+

But if you're at the very edge of the kitemap, this isn't enough. + For example, kite 0.0.4 right at the top can go Left to 1.0.4, but + if it wants to go in any of the other three directions, this map + doesn't help at all.

+

This is where the overlap between the metatile expansions comes + in. If you're in kite 0.0.4, then in particular, you're in the F + tile numbered 4 in the expansion of a larger T metatile. And that F + tile is also part of the expansion of at least one other + second-order metatile – maybe two of them – which means that there + are other equivalent coordinates describing the same kite, which + will place it in a different kitemap where it isn't right + on the edge,

+

In order to find those equivalent coordinates, we create a second + map for each metatile type, called the metamap. + This one arises from expanding the metatile twice into other + metatiles, instead of into hats:

+ + + + + + + + +
+

Again, the coordinates are little-end first, so that 7.4 means + the 7th smallest-size tile expanded from the 4th medium-sized tile + expanded from the original single large tile.

+

Unlike the kitemap, the metamap is not used for moving + around the tiling to a different kite. It's used for rewriting + the coordinates of the current kite into equivalent forms. So each + the small tile in the metamap that's part of the expansion + of more than one medium-sized tile has more than one + coordinate pair. For example, tile 5.2 is also tile 5.4, and tile + 7.0 is also 8.3 and also 4.5 (because it's where three + medium-tile expansions meet).

+

Using both of these maps (converted into appropriate lookup + tables in the code), you can always eventually find a valid + coordinate representation of whichever kite you like adjacent to + your current one. If the kitemap corresponding to the current + coordinates doesn't tell you the coordinates of the next kite, then + you can try rewriting the two least-significant metatile indices + (using the metamap corresponding to the type of the next-larger + metatile still) and then see if that gives you a new kitemap that + works. If even that doesn't work, you can move another level up, and + try a metamap rewrite on the 2nd and 3rd smallest metatile levels, + or the 3rd and 4th, etc. And eventually, you find something you can + do.

+

The full set of kitemaps and metamaps for all the tile + types is in hatmaps.html.

+ + diff --git a/aux/doc/kitemap-F.svg b/aux/doc/kitemap-F.svg new file mode 100644 index 0000000..5b448ab --- /dev/null +++ b/aux/doc/kitemap-F.svg @@ -0,0 +1,783 @@ + + + + + + + + + + +0.0.0 +1.0.0 +2.0.0 +3.0.0 +4.0.0 +5.0.0 +6.0.0 +7.0.0 + + + + + + + + +0.1.0 +1.1.0 +2.1.0 +3.1.0 +4.1.0 +5.1.0 +6.1.0 +7.1.0 + + + + + + + + +0.2.0 +1.2.0 +2.2.0 +3.2.0 +4.2.0 +5.2.0 +6.2.0 +7.2.0 + + + + + + + + +0.3.0 +1.3.0 +2.3.0 +3.3.0 +4.3.0 +5.3.0 +6.3.0 +7.3.0 + + + + + + + + +0.0.1 +1.0.1 +2.0.1 +3.0.1 +4.0.1 +5.0.1 +6.0.1 +7.0.1 + + + + + + + + +0.1.1 +1.1.1 +2.1.1 +3.1.1 +4.1.1 +5.1.1 +6.1.1 +7.1.1 + + + + + + + + +0.2.1 +1.2.1 +2.2.1 +3.2.1 +4.2.1 +5.2.1 +6.2.1 +7.2.1 + + + + + + + + +0.3.1 +1.3.1 +2.3.1 +3.3.1 +4.3.1 +5.3.1 +6.3.1 +7.3.1 + + + + + + + + +0.0.2 +1.0.2 +2.0.2 +3.0.2 +4.0.2 +5.0.2 +6.0.2 +7.0.2 + + + + + + + + +0.1.2 +1.1.2 +2.1.2 +3.1.2 +4.1.2 +5.1.2 +6.1.2 +7.1.2 + + + + + + + + +0.0.3 +1.0.3 +2.0.3 +3.0.3 +4.0.3 +5.0.3 +6.0.3 +7.0.3 + + + + + + + + +0.1.3 +1.1.3 +2.1.3 +3.1.3 +4.1.3 +5.1.3 +6.1.3 +7.1.3 + + + + + + + + +0.0.4 +1.0.4 +2.0.4 +3.0.4 +4.0.4 +5.0.4 +6.0.4 +7.0.4 + + + + + + + + +0.1.4 +1.1.4 +2.1.4 +3.1.4 +4.1.4 +5.1.4 +6.1.4 +7.1.4 + + + + + + + + +0.0.5 +1.0.5 +2.0.5 +3.0.5 +4.0.5 +5.0.5 +6.0.5 +7.0.5 + + + + + + + + +0.1.5 +1.1.5 +2.1.5 +3.1.5 +4.1.5 +5.1.5 +6.1.5 +7.1.5 + + + + + + + + +0.0.6 +1.0.6 +2.0.6 +3.0.6 +4.0.6 +5.0.6 +6.0.6 +7.0.6 + + + + + + + + +0.1.6 +1.1.6 +2.1.6 +3.1.6 +4.1.6 +5.1.6 +6.1.6 +7.1.6 + + + + + + + + +0.0.7 +1.0.7 +2.0.7 +3.0.7 +4.0.7 +5.0.7 +6.0.7 +7.0.7 + + + + + + + + +0.1.7 +1.1.7 +2.1.7 +3.1.7 +4.1.7 +5.1.7 +6.1.7 +7.1.7 + + + + + + + + +0.0.8 +1.0.8 +2.0.8 +3.0.8 +4.0.8 +5.0.8 +6.0.8 +7.0.8 + + + + + + + + +0.1.8 +1.1.8 +2.1.8 +3.1.8 +4.1.8 +5.1.8 +6.1.8 +7.1.8 + + + + + + + + +0.0.9 +1.0.9 +2.0.9 +3.0.9 +4.0.9 +5.0.9 +6.0.9 +7.0.9 + + + + + + + + +0.1.9 +1.1.9 +2.1.9 +3.1.9 +4.1.9 +5.1.9 +6.1.9 +7.1.9 + + + + + + + + +0.0.10 +1.0.10 +2.0.10 +3.0.10 +4.0.10 +5.0.10 +6.0.10 +7.0.10 + + + + + + + + +0.1.10 +1.1.10 +2.1.10 +3.1.10 +4.1.10 +5.1.10 +6.1.10 +7.1.10 + diff --git a/aux/doc/kitemap-H.svg b/aux/doc/kitemap-H.svg new file mode 100644 index 0000000..16750fb --- /dev/null +++ b/aux/doc/kitemap-H.svg @@ -0,0 +1,933 @@ + + + + + + + + + + +0.0.0 +1.0.0 +2.0.0 +3.0.0 +4.0.0 +5.0.0 +6.0.0 +7.0.0 + + + + + + + + +0.1.0 +1.1.0 +2.1.0 +3.1.0 +4.1.0 +5.1.0 +6.1.0 +7.1.0 + + + + + + + + +0.2.0 +1.2.0 +2.2.0 +3.2.0 +4.2.0 +5.2.0 +6.2.0 +7.2.0 + + + + + + + + +0.3.0 +1.3.0 +2.3.0 +3.3.0 +4.3.0 +5.3.0 +6.3.0 +7.3.0 + + + + + + + + +0.0.1 +1.0.1 +2.0.1 +3.0.1 +4.0.1 +5.0.1 +6.0.1 +7.0.1 + + + + + + + + +0.1.1 +1.1.1 +2.1.1 +3.1.1 +4.1.1 +5.1.1 +6.1.1 +7.1.1 + + + + + + + + +0.2.1 +1.2.1 +2.2.1 +3.2.1 +4.2.1 +5.2.1 +6.2.1 +7.2.1 + + + + + + + + +0.3.1 +1.3.1 +2.3.1 +3.3.1 +4.3.1 +5.3.1 +6.3.1 +7.3.1 + + + + + + + + +0.0.2 +1.0.2 +2.0.2 +3.0.2 +4.0.2 +5.0.2 +6.0.2 +7.0.2 + + + + + + + + +0.1.2 +1.1.2 +2.1.2 +3.1.2 +4.1.2 +5.1.2 +6.1.2 +7.1.2 + + + + + + + + +0.2.2 +1.2.2 +2.2.2 +3.2.2 +4.2.2 +5.2.2 +6.2.2 +7.2.2 + + + + + + + + +0.3.2 +1.3.2 +2.3.2 +3.3.2 +4.3.2 +5.3.2 +6.3.2 +7.3.2 + + + + + + + + +0.0.3 +1.0.3 +2.0.3 +3.0.3 +4.0.3 +5.0.3 +6.0.3 +7.0.3 + + + + + + + + +0.0.4 +1.0.4 +2.0.4 +3.0.4 +4.0.4 +5.0.4 +6.0.4 +7.0.4 + + + + + + + + +0.1.4 +1.1.4 +2.1.4 +3.1.4 +4.1.4 +5.1.4 +6.1.4 +7.1.4 + + + + + + + + +0.0.5 +1.0.5 +2.0.5 +3.0.5 +4.0.5 +5.0.5 +6.0.5 +7.0.5 + + + + + + + + +0.1.5 +1.1.5 +2.1.5 +3.1.5 +4.1.5 +5.1.5 +6.1.5 +7.1.5 + + + + + + + + +0.0.6 +1.0.6 +2.0.6 +3.0.6 +4.0.6 +5.0.6 +6.0.6 +7.0.6 + + + + + + + + +0.1.6 +1.1.6 +2.1.6 +3.1.6 +4.1.6 +5.1.6 +6.1.6 +7.1.6 + + + + + + + + +0.0.7 +1.0.7 +2.0.7 +3.0.7 +4.0.7 +5.0.7 +6.0.7 +7.0.7 + + + + + + + + +0.1.7 +1.1.7 +2.1.7 +3.1.7 +4.1.7 +5.1.7 +6.1.7 +7.1.7 + + + + + + + + +0.0.8 +1.0.8 +2.0.8 +3.0.8 +4.0.8 +5.0.8 +6.0.8 +7.0.8 + + + + + + + + +0.1.8 +1.1.8 +2.1.8 +3.1.8 +4.1.8 +5.1.8 +6.1.8 +7.1.8 + + + + + + + + +0.0.9 +1.0.9 +2.0.9 +3.0.9 +4.0.9 +5.0.9 +6.0.9 +7.0.9 + + + + + + + + +0.1.9 +1.1.9 +2.1.9 +3.1.9 +4.1.9 +5.1.9 +6.1.9 +7.1.9 + + + + + + + + +0.0.10 +1.0.10 +2.0.10 +3.0.10 +4.0.10 +5.0.10 +6.0.10 +7.0.10 + + + + + + + + +0.1.10 +1.1.10 +2.1.10 +3.1.10 +4.1.10 +5.1.10 +6.1.10 +7.1.10 + + + + + + + + +0.0.11 +1.0.11 +2.0.11 +3.0.11 +4.0.11 +5.0.11 +6.0.11 +7.0.11 + + + + + + + + +0.1.11 +1.1.11 +2.1.11 +3.1.11 +4.1.11 +5.1.11 +6.1.11 +7.1.11 + + + + + + + + +0.0.12 +1.0.12 +2.0.12 +3.0.12 +4.0.12 +5.0.12 +6.0.12 +7.0.12 + + + + + + + + +0.1.12 +1.1.12 +2.1.12 +3.1.12 +4.1.12 +5.1.12 +6.1.12 +7.1.12 + diff --git a/aux/doc/kitemap-P.svg b/aux/doc/kitemap-P.svg new file mode 100644 index 0000000..bd3fffb --- /dev/null +++ b/aux/doc/kitemap-P.svg @@ -0,0 +1,783 @@ + + + + + + + + + + +0.0.0 +1.0.0 +2.0.0 +3.0.0 +4.0.0 +5.0.0 +6.0.0 +7.0.0 + + + + + + + + +0.1.0 +1.1.0 +2.1.0 +3.1.0 +4.1.0 +5.1.0 +6.1.0 +7.1.0 + + + + + + + + +0.2.0 +1.2.0 +2.2.0 +3.2.0 +4.2.0 +5.2.0 +6.2.0 +7.2.0 + + + + + + + + +0.3.0 +1.3.0 +2.3.0 +3.3.0 +4.3.0 +5.3.0 +6.3.0 +7.3.0 + + + + + + + + +0.0.1 +1.0.1 +2.0.1 +3.0.1 +4.0.1 +5.0.1 +6.0.1 +7.0.1 + + + + + + + + +0.1.1 +1.1.1 +2.1.1 +3.1.1 +4.1.1 +5.1.1 +6.1.1 +7.1.1 + + + + + + + + +0.2.1 +1.2.1 +2.2.1 +3.2.1 +4.2.1 +5.2.1 +6.2.1 +7.2.1 + + + + + + + + +0.3.1 +1.3.1 +2.3.1 +3.3.1 +4.3.1 +5.3.1 +6.3.1 +7.3.1 + + + + + + + + +0.0.2 +1.0.2 +2.0.2 +3.0.2 +4.0.2 +5.0.2 +6.0.2 +7.0.2 + + + + + + + + +0.1.2 +1.1.2 +2.1.2 +3.1.2 +4.1.2 +5.1.2 +6.1.2 +7.1.2 + + + + + + + + +0.0.3 +1.0.3 +2.0.3 +3.0.3 +4.0.3 +5.0.3 +6.0.3 +7.0.3 + + + + + + + + +0.1.3 +1.1.3 +2.1.3 +3.1.3 +4.1.3 +5.1.3 +6.1.3 +7.1.3 + + + + + + + + +0.0.4 +1.0.4 +2.0.4 +3.0.4 +4.0.4 +5.0.4 +6.0.4 +7.0.4 + + + + + + + + +0.1.4 +1.1.4 +2.1.4 +3.1.4 +4.1.4 +5.1.4 +6.1.4 +7.1.4 + + + + + + + + +0.0.5 +1.0.5 +2.0.5 +3.0.5 +4.0.5 +5.0.5 +6.0.5 +7.0.5 + + + + + + + + +0.1.5 +1.1.5 +2.1.5 +3.1.5 +4.1.5 +5.1.5 +6.1.5 +7.1.5 + + + + + + + + +0.0.6 +1.0.6 +2.0.6 +3.0.6 +4.0.6 +5.0.6 +6.0.6 +7.0.6 + + + + + + + + +0.1.6 +1.1.6 +2.1.6 +3.1.6 +4.1.6 +5.1.6 +6.1.6 +7.1.6 + + + + + + + + +0.0.7 +1.0.7 +2.0.7 +3.0.7 +4.0.7 +5.0.7 +6.0.7 +7.0.7 + + + + + + + + +0.1.7 +1.1.7 +2.1.7 +3.1.7 +4.1.7 +5.1.7 +6.1.7 +7.1.7 + + + + + + + + +0.0.8 +1.0.8 +2.0.8 +3.0.8 +4.0.8 +5.0.8 +6.0.8 +7.0.8 + + + + + + + + +0.1.8 +1.1.8 +2.1.8 +3.1.8 +4.1.8 +5.1.8 +6.1.8 +7.1.8 + + + + + + + + +0.0.9 +1.0.9 +2.0.9 +3.0.9 +4.0.9 +5.0.9 +6.0.9 +7.0.9 + + + + + + + + +0.1.9 +1.1.9 +2.1.9 +3.1.9 +4.1.9 +5.1.9 +6.1.9 +7.1.9 + + + + + + + + +0.0.10 +1.0.10 +2.0.10 +3.0.10 +4.0.10 +5.0.10 +6.0.10 +7.0.10 + + + + + + + + +0.1.10 +1.1.10 +2.1.10 +3.1.10 +4.1.10 +5.1.10 +6.1.10 +7.1.10 + diff --git a/aux/doc/kitemap-T.svg b/aux/doc/kitemap-T.svg new file mode 100644 index 0000000..6be1ddc --- /dev/null +++ b/aux/doc/kitemap-T.svg @@ -0,0 +1,483 @@ + + + + + + + + + + +0.0.0 +1.0.0 +2.0.0 +3.0.0 +4.0.0 +5.0.0 +6.0.0 +7.0.0 + + + + + + + + +0.1.0 +1.1.0 +2.1.0 +3.1.0 +4.1.0 +5.1.0 +6.1.0 +7.1.0 + + + + + + + + +0.2.0 +1.2.0 +2.2.0 +3.2.0 +4.2.0 +5.2.0 +6.2.0 +7.2.0 + + + + + + + + +0.3.0 +1.3.0 +2.3.0 +3.3.0 +4.3.0 +5.3.0 +6.3.0 +7.3.0 + + + + + + + + +0.0.1 +1.0.1 +2.0.1 +3.0.1 +4.0.1 +5.0.1 +6.0.1 +7.0.1 + + + + + + + + +0.1.1 +1.1.1 +2.1.1 +3.1.1 +4.1.1 +5.1.1 +6.1.1 +7.1.1 + + + + + + + + +0.0.2 +1.0.2 +2.0.2 +3.0.2 +4.0.2 +5.0.2 +6.0.2 +7.0.2 + + + + + + + + +0.1.2 +1.1.2 +2.1.2 +3.1.2 +4.1.2 +5.1.2 +6.1.2 +7.1.2 + + + + + + + + +0.0.3 +1.0.3 +2.0.3 +3.0.3 +4.0.3 +5.0.3 +6.0.3 +7.0.3 + + + + + + + + +0.1.3 +1.1.3 +2.1.3 +3.1.3 +4.1.3 +5.1.3 +6.1.3 +7.1.3 + + + + + + + + +0.0.4 +1.0.4 +2.0.4 +3.0.4 +4.0.4 +5.0.4 +6.0.4 +7.0.4 + + + + + + + + +0.1.4 +1.1.4 +2.1.4 +3.1.4 +4.1.4 +5.1.4 +6.1.4 +7.1.4 + + + + + + + + +0.0.5 +1.0.5 +2.0.5 +3.0.5 +4.0.5 +5.0.5 +6.0.5 +7.0.5 + + + + + + + + +0.1.5 +1.1.5 +2.1.5 +3.1.5 +4.1.5 +5.1.5 +6.1.5 +7.1.5 + + + + + + + + +0.0.6 +1.0.6 +2.0.6 +3.0.6 +4.0.6 +5.0.6 +6.0.6 +7.0.6 + + + + + + + + +0.1.6 +1.1.6 +2.1.6 +3.1.6 +4.1.6 +5.1.6 +6.1.6 +7.1.6 + diff --git a/aux/doc/metamap-F.svg b/aux/doc/metamap-F.svg new file mode 100644 index 0000000..4b2805c --- /dev/null +++ b/aux/doc/metamap-F.svg @@ -0,0 +1,714 @@ + + + + +1.5 + + +0.5 + + +1.4 + + +0.4 + + +0.6 + + +2.0 + + +1.6 + + +2.1 + + +0.0 + + +0.8 + + +0.3 + + +1.8 + + +1.7 + + +0.1 + + +1.3 + + +1.0 + + +0.7 + + +0.10 + + +1.1 + + +0.2 + + +1.10 + + +1.2 + + +0.9 + + +1.9 + + +3.0 + + +3.1 + + +3.5 + + +2.5 + + +3.4 + + +5.0 +2.4 + + +5.1 +2.6 + + +2.8 + + +3.6 + + +4.0 +3.3 + + +3.8 + + +4.3 + + +3.7 + + +6.0 +2.2 + + +2.7 + + +4.1 +2.10 + + +2.3 +6.1 + + +3.2 + + +3.10 + + +4.2 + + +2.9 + + +3.9 + +6.4 + +10.5 + +7.4 + +9.5 + +8.5 +4.6 + +5.6 + +10.4 +7.5 + +8.0 +9.4 + +5.4 + +8.8 +4.4 + +6.6 + +7.0 +8.3 +6.5 + +7.6 + +5.3 +5.5 + +4.5 +11.1 +8.6 + +6.3 +12.1 + +8.1 +9.6 + +10.7 + +10.6 +7.7 + +7.1 +8.10 +6.7 + +11.0 +4.8 +8.4 + +5.2 +5.8 + +9.8 + +10.8 + +9.7 + +12.0 +6.2 + +9.0 +9.3 + +10.0 +4.9 +7.2 + +10.3 +5.9 + +7.8 + +7.3 +6.9 +10.1 + +8.2 +6.8 + +4.10 +5.7 + +5.10 + +9.1 +9.10 + +7.9 +10.10 + +9.2 + +4.7 + +8.9 +10.2 + +8.7 + +9.9 + +7.10 + +10.9 + +6.10 + diff --git a/aux/doc/metamap-H.svg b/aux/doc/metamap-H.svg new file mode 100644 index 0000000..127df3d --- /dev/null +++ b/aux/doc/metamap-H.svg @@ -0,0 +1,819 @@ + + + + +0.7 + + +1.7 + + +0.4 + + +1.8 + + +1.4 + + +0.0 + + +0.9 + + +1.0 + + +0.8 + + +1.9 + + +0.1 + + +2.0 + + +1.1 + + +0.3 + + +1.10 + + +2.1 + + +0.10 + + +1.2 + + +1.5 + + +1.6 + + +0.5 + + +0.6 + + +0.2 + + +2.2 + + +0.12 + + +1.12 + + +0.11 + + +1.11 + + +3.0 + + +3.1 + + +3.2 + + +2.7 + + +3.7 + + +2.4 + + +4.0 +3.4 + + +4.4 + + +3.8 + + +4.1 +2.9 + + +5.0 +2.8 + + +3.9 + + +6.0 +3.3 + + +5.1 +2.3 + + +6.1 +2.6 + + +2.5 + + +3.10 + + +1.3 +6.2 + + +2.10 + + +4.5 + + +4.6 + + +4.2 +3.5 + + +3.6 + + +5.2 +2.12 + + +3.12 + + +2.11 + + +3.11 + +8.7 + +4.7 + +5.4 +5.7 + +9.7 + +10.7 + +6.4 + +7.4 +4.9 + +5.9 + +10.8 +7.7 + +7.8 + +6.8 + +6.9 + +7.0 +8.4 +6.7 + +8.0 +9.8 + +7.9 + +9.0 +9.4 + +7.1 +10.4 +8.9 + +10.0 +8.1 +6.3 + +9.1 +9.9 + +10.10 + +10.9 +7.10 + +10.1 +6.10 +7.6 + +5.8 + +9.10 + +7.5 +4.8 + +11.0 +10.5 +8.8 + +12.0 +5.3 +10.2 + +9.2 +9.5 + +11.1 +4.3 +12.2 + +5.10 +10.6 + +9.6 + +12.1 +6.6 + +11.2 +5.6 +8.12 + +4.10 + +8.10 + +6.5 + +4.11 + +5.5 +5.11 + +7.2 +8.5 +6.11 + +8.6 +4.12 + +5.12 + +8.2 +9.12 + +10.12 +7.11 + +8.11 + +9.11 + +7.12 + +10.11 + +6.12 + diff --git a/aux/doc/metamap-P.svg b/aux/doc/metamap-P.svg new file mode 100644 index 0000000..d5a6f4f --- /dev/null +++ b/aux/doc/metamap-P.svg @@ -0,0 +1,708 @@ + + + + +1.6 + + +0.6 + + +1.5 + + +0.5 + + +0.2 + + +2.0 + + +1.2 + + +2.1 + + +0.0 + + +0.8 + + +1.7 + + +0.4 + + +1.8 + + +0.7 + + +0.1 + + +1.4 + + +1.0 + + +0.10 + + +1.1 + + +0.3 + + +1.10 + + +1.3 + + +0.9 + + +1.9 + + +3.0 + + +3.1 + + +3.6 + + +2.6 + + +3.5 + + +2.2 + + +5.0 +2.5 + + +5.1 +3.2 + + +2.8 + + +4.2 + + +4.0 +3.4 + + +3.8 + + +3.7 + + +4.4 + + +2.7 + + +6.0 +2.3 + + +4.1 +2.10 + + +2.4 +6.1 + + +3.3 + + +3.10 + + +4.3 + + +2.9 + + +3.9 + +6.5 + +10.6 + +7.5 + +9.6 + +8.6 +5.2 + +6.2 + +10.5 +7.6 + +8.0 +9.5 + +5.5 + +8.8 +4.5 + +7.2 +6.7 + +7.0 +8.4 +6.6 + +7.7 + +5.4 +5.6 + +4.6 +11.1 +8.2 + +6.4 +12.1 + +8.1 +9.2 + +10.7 + +9.7 + +10.2 +5.7 + +7.1 +8.10 +4.7 + +11.0 +4.8 +8.5 + +5.3 +5.8 + +9.8 + +10.8 + +12.0 +6.3 + +9.0 +9.4 + +10.0 +4.9 +7.3 + +10.4 +5.9 + +7.8 + +7.4 +6.9 +10.1 + +8.3 +6.8 + +4.10 +8.7 + +5.10 + +9.1 +9.10 + +7.9 +10.10 + +9.3 + +8.9 +10.3 + +9.9 + +7.10 + +10.9 + +6.10 + diff --git a/aux/doc/metamap-T.svg b/aux/doc/metamap-T.svg new file mode 100644 index 0000000..c65fc83 --- /dev/null +++ b/aux/doc/metamap-T.svg @@ -0,0 +1,459 @@ + + + + +1.4 + + +0.4 + + +0.1 + + +1.1 + + +2.0 + + +1.5 + + +0.2 + + +0.5 + + +0.0 + + +1.2 + + +0.3 + + +1.0 + + +1.3 + + +0.6 + + +1.6 + + +3.0 + + +3.4 + + +2.4 + + +2.1 + + +5.0 +3.1 + + +4.1 + + +3.2 + + +3.5 + + +4.2 + + +2.5 + + +4.0 +3.3 + + +6.0 +2.2 + + +4.3 + + +2.6 + + +3.6 + + +2.3 + +10.4 + +9.4 + +8.4 +5.1 + +6.1 + +7.4 + +7.1 +6.5 + +8.2 +6.4 + +7.5 + +5.2 +5.4 + +11.0 +4.4 +8.1 + +12.0 +6.2 + +8.0 +9.1 + +10.5 + +9.5 + +10.1 +5.5 + +7.0 +8.3 +4.5 + +9.2 + +8.6 +10.2 + +10.0 +4.6 +7.2 + +5.3 +8.5 + +6.3 + +9.0 +9.3 + +10.3 +5.6 + +9.6 + +7.3 +6.6 + +7.6 + +10.6 + diff --git a/aux/doc/single-F.svg b/aux/doc/single-F.svg new file mode 100644 index 0000000..1e3c4d3 --- /dev/null +++ b/aux/doc/single-F.svg @@ -0,0 +1,9 @@ + + + + diff --git a/aux/doc/single-H.svg b/aux/doc/single-H.svg new file mode 100644 index 0000000..e3919dc --- /dev/null +++ b/aux/doc/single-H.svg @@ -0,0 +1,11 @@ + + + + + diff --git a/aux/doc/single-P.svg b/aux/doc/single-P.svg new file mode 100644 index 0000000..2b7159a --- /dev/null +++ b/aux/doc/single-P.svg @@ -0,0 +1,9 @@ + + + + + diff --git a/aux/doc/single-T.svg b/aux/doc/single-T.svg new file mode 100644 index 0000000..68919bb --- /dev/null +++ b/aux/doc/single-T.svg @@ -0,0 +1,8 @@ + + + + + diff --git a/aux/hatgen-images.sh b/aux/hatgen-images.sh new file mode 100755 index 0000000..f3cec4b --- /dev/null +++ b/aux/hatgen-images.sh @@ -0,0 +1,23 @@ +#!/bin/sh + +# Regenerate all the SVG images in the aux/doc directory for hats.html +# and hatmap.html. + +set -e + +hatgen=$1 + +if ! test -x "$hatgen"; then + echo "Provide pathname to hatgen as an argument" >&2 + exit 1 +fi + +for tile in H T P F; do + "$hatgen" "$tile" > single-"$tile".svg + "$hatgen" c"$tile" > expanded-"$tile".svg + "$hatgen" h"$tile" > hats-single-"$tile".svg + "$hatgen" H"$tile" > kitemap-"$tile".svg + "$hatgen" C"$tile" > metamap-"$tile".svg +done + +"$hatgen" --hat > hat-kites.svg diff --git a/aux/hatgen.c b/aux/hatgen.c new file mode 100644 index 0000000..11fb262 --- /dev/null +++ b/aux/hatgen.c @@ -0,0 +1,1713 @@ +/* + * Generate patches of tiling by the 'hat' aperiodic monotile + * discovered in 2023. + * + * This implementation of hat-tiling generation was intended to be the + * basis for generating hat grids for Loopy. However, it turned out + * that I found a better strategy, so this source file isn't used by + * the main puzzle system. I've kept it anyway because I ended up + * adapting it to generate the file hat-tables.h containing the lookup + * tables for the algorithm I _did_ end up using. It also generates + * diagrams that are useful for understanding that algorithm, and for + * debugging it if anything still turns out to be wrong with it. + * + * Discoverers' website: https://cs.uwaterloo.ca/~csk/hat/ + * Preprint of paper: https://arxiv.org/abs/2303.10798 + */ + +#include +#include +#include +#include +#include +#include + +#include "puzzles.h" +#include "tree234.h" +#include "hat.h" + +/* + * General strategy: + * + * We construct the hat tiling by means of a substitution system of + * 'metatiles' which come in four types, called H,T,P,F. A (valid) + * tiling of these metatiles can be expanded to a larger one by a set + * of recursive subdivision rules. Once we have a large enough patch + * of metatiles, we apply a final transformation that converts each + * metatile into 1, 2 or 4 instances of the aperiodically tiling + * 'hat'. + * + * Unlike the similar substitution system for Penrose tilings, the + * expansion rules are not geometrically precise: the larger versions + * of each metatile fit together combinatorially in the same way, but + * their shapes are distorted slightly. So we must construct our + * expanded meta-tiling by breadth-first search out from a starting + * metatile, because we won't quite know the coordinates of the + * expanded version of each metatile until we know one of the ones + * next to it. + */ + +/* + * Coordinate system: + * + * Everything in this code lives on the tiling known to grid.c as + * 'Kites', which can be viewed as a tiling of hexagons each of which + * is subdivided into six kites sharing their pointy vertex, or + * (equivalently) a tiling of equilateral triangles each subdivided + * into three kits sharing their blunt vertex. + * + * We express coordinates in this system relative to the basis (1, r) + * where r = (1 + sqrt(3)i) / 2 is a primitive 6th root of unity. This + * gives us a system in which two integer coordinates can address any + * grid point, provided we scale up so that the side length of the + * equilateral triangles in the tiling is 6. + */ + +typedef struct Point { + int x, y; /* represents x + yr */ +} Point; + +static inline Point left6(Point p) +{ + /* r satisfies the equation r^2 = r-1. Hence, multiplying by r + * (achieving a rotation anticlockwise by 1/6 turn) transforms + * x+yr into xr+yr^2 = xr+y(r-1) = (-y) + (x+y)r. + * + * It's easy to check that iterating this transformation six times + * gives you back the same coordinates you started with. */ + Point q = { -p.y, p.x + p.y }; + return q; +} + +static inline Point right6(Point p) +{ + /* Conversely, 1/r = 1 - r, so dividing by r turns x+yr into x/r+y + * = x(1-r) + y = (x+y) + (-x)r. */ + Point q = { p.x + p.y, -p.x }; + return q; +} + +typedef enum MetatileType { MT_H, MT_T, MT_P, MT_F } MetatileType; +typedef struct Metatile Metatile; +typedef struct MetaCoord { + Metatile *parent; + int index; +} MetaCoord; + +struct Metatile { + /* Data fields describing the metatile and its position. */ + MetatileType type; + Point start, orientation; + + MetaCoord coords[4]; + size_t ncoords; + + /* Auxiliary fields used to store the progress of the expansion + * algorithm. */ + bool queued; + Metatile *qnext; +}; + +#define MT_MAXVERT 6 /* largest number of vertices of any metatile */ +#define MT_MAXVDEGREE 3 /* largest degree of any vertex of a meta-tiling */ +#define MT_MAXEXPAND 13 /* largest number of metatiles in any expansion */ +#define MT_MAXHAT 4 /* largest number of hats in a metatile */ +#define HAT_NVERT 14 /* vertices of a single hat (counting the straight one) */ +#define HAT_NKITE 8 /* kites in a single hat */ + +static int metatile_cmp(void *av, void *bv) +{ + Metatile *a = (Metatile *)av, *b = (Metatile *)bv; + if (a->type < b->type) return -1; + if (a->type > b->type) return +1; + if (a->start.x < b->start.x) return -1; + if (a->start.x > b->start.x) return +1; + if (a->start.y < b->start.y) return -1; + if (a->start.y > b->start.y) return +1; + if (a->orientation.x < b->orientation.x) return -1; + if (a->orientation.x > b->orientation.x) return +1; + if (a->orientation.y < b->orientation.y) return -1; + if (a->orientation.y > b->orientation.y) return +1; + return 0; +} + +/* + * Return the coordinates of the vertices of a metatile, given the + * coordinates of the vertex we deem to be distinguished, and a vector + * of Euclidean length 1 showing its direction. + * + * If 'expanded' is true, we instead return the coordinates of the + * corresponding vertices of the expanded version of the same + * metatile. + */ +static size_t metatile_vertices(Metatile m, Point *out, bool expanded) +{ + static const Point vertices_H[] = { + {0, 0}, {4, -2}, {12, 6}, {10, 10}, {-6, 18}, {-8, 16}, + }; + static const Point vertices_T[] = { + {0, 0}, {6, 6}, {-6, 12}, + }; + static const Point vertices_P[] = { + {0, 0}, {4, 4}, {-4, 20}, {-8, 16}, + }; + static const Point vertices_F[] = { + {0, 0}, {4, -2}, {6, 0}, {-2, 16}, {-6, 12}, + }; + + static const Point expanded_H[] = { + {0, 0}, {12, -6}, {30, 12}, {24, 24}, {-12, 42}, {-18, 36}, + }; + static const Point expanded_T[] = { + {0, 0}, {12, 12}, {-12, 24}, + }; + static const Point expanded_P[] = { + {0, 0}, {14, 8}, {-4, 44}, {-18, 36}, + }; + static const Point expanded_F[] = { + {0, 0}, {14, -4}, {18, 6}, {0, 42}, {-14, 34}, + }; + + const Point *vertices; + size_t nvertices; + size_t i; + + switch (m.type) { + case MT_H: + vertices = expanded ? expanded_H : vertices_H; + nvertices = lenof(vertices_H); + break; + case MT_T: + vertices = expanded ? expanded_T : vertices_T; + nvertices = lenof(vertices_T); + break; + case MT_P: + vertices = expanded ? expanded_P : vertices_P; + nvertices = lenof(vertices_P); + break; + default /* case MT_F */: + vertices = expanded ? expanded_F : vertices_F; + nvertices = lenof(vertices_F); + break; + } + assert(nvertices <= MT_MAXVERT); + + Point orientation_r = left6(m.orientation); + for (i = 0; i < nvertices; i++) { + Point v = vertices[i]; + out[i].x = m.start.x + v.x * m.orientation.x + v.y * orientation_r.x; + out[i].y = m.start.y + v.x * m.orientation.y + v.y * orientation_r.y; + } + return nvertices; +} + +/* + * Return a list of metatiles that arise from expanding a given tile. + */ +static size_t metatile_expand(Metatile m, Metatile *out) +{ + static const Metatile tiles_H[] = { + {MT_H, {-4, 20}, {1, 0}}, + {MT_H, {2, 2}, {1, 0}}, + {MT_H, {8, 26}, {0, -1}}, + {MT_T, {6, 24}, {-1, 0}}, + {MT_P, {-8, 16}, {1, 0}}, + {MT_P, {4, 34}, {0, -1}}, + {MT_P, {6, 0}, {1, -1}}, + {MT_F, {-10, 38}, {-1, 1}}, + {MT_F, {-10, 44}, {0, -1}}, + {MT_F, {-4, 2}, {1, 0}}, + {MT_F, {2, 2}, {0, -1}}, + {MT_F, {26, 14}, {1, 0}}, + {MT_F, {32, 8}, {-1, 1}}, + }; + static const Metatile tiles_T[] = { + {MT_H, {10, 10}, {-1, 1}}, + {MT_P, {-6, 0}, {1, 0}}, + {MT_P, {8, 14}, {0, 1}}, + {MT_P, {18, 6}, {-1, 1}}, + {MT_F, {-14, 34}, {-1, 0}}, + {MT_F, {-8, -2}, {1, -1}}, + {MT_F, {22, 4}, {0, 1}}, + }; + static const Metatile tiles_P[] = { + {MT_H, {4, 22}, {0, 1}}, + {MT_H, {10, 10}, {-1, 1}}, + {MT_P, {-6, 0}, {1, 0}}, + {MT_P, {6, 24}, {1, 0}}, + {MT_P, {8, 14}, {0, 1}}, + {MT_F, {-20, 40}, {1, -1}}, + {MT_F, {-14, 34}, {-1, 0}}, + {MT_F, {-8, -2}, {1, -1}}, + {MT_F, {4, 46}, {-1, 1}}, + {MT_F, {10, 10}, {1, 0}}, + {MT_F, {16, 4}, {-1, 1}}, + }; + static const Metatile tiles_F[] = { + {MT_H, {8, 20}, {0, 1}}, + {MT_H, {14, 8}, {-1, 1}}, + {MT_P, {10, 22}, {1, 0}}, + {MT_P, {12, 12}, {0, 1}}, + {MT_F, {-16, 38}, {1, -1}}, + {MT_F, {-10, 32}, {-1, 0}}, + {MT_F, {-4, 2}, {1, 0}}, + {MT_F, {2, 2}, {0, -1}}, + {MT_F, {8, 44}, {-1, 1}}, + {MT_F, {14, 8}, {1, 0}}, + {MT_F, {20, 2}, {-1, 1}}, + }; + + const Metatile *tiles; + size_t ntiles; + size_t i; + + switch (m.type) { + case MT_H: + tiles = tiles_H; + ntiles = lenof(tiles_H); + break; + case MT_T: + tiles = tiles_T; + ntiles = lenof(tiles_T); + break; + case MT_P: + tiles = tiles_P; + ntiles = lenof(tiles_P); + break; + default /* case MT_F */: + tiles = tiles_F; + ntiles = lenof(tiles_F); + break; + } + assert(ntiles <= MT_MAXEXPAND); + + Point orientation_r = left6(m.orientation); + for (i = 0; i < ntiles; i++) { + Metatile t = tiles[i]; + out[i].type = t.type; + out[i].start.x = (m.start.x + t.start.x * m.orientation.x + + t.start.y * orientation_r.x); + out[i].start.y = (m.start.y + t.start.x * m.orientation.y + + t.start.y * orientation_r.y); + out[i].orientation.x = (t.orientation.x * m.orientation.x + + t.orientation.y * orientation_r.x); + out[i].orientation.y = (t.orientation.x * m.orientation.y + + t.orientation.y * orientation_r.y); + } + return ntiles; +} + +/* Store data about each vertex during an expansion. */ +typedef struct VertexMapping { + Point in; + + /* Metatiles sharing this vertex */ + Metatile *tiles[MT_MAXVDEGREE]; + size_t ntiles; + + /* The expanded coordinates of this vertex, if known */ + bool mapped; + Point out; +} VertexMapping; + +static int vertexmapping_cmp(void *av, void *bv) +{ + VertexMapping *a = (VertexMapping *)av, *b = (VertexMapping *)bv; + if (a->in.x < b->in.x) return -1; + if (a->in.x > b->in.x) return +1; + if (a->in.y < b->in.y) return -1; + if (a->in.y > b->in.y) return +1; + return 0; +} + +static int vertexmapping_find(void *av, void *bv) +{ + Point *a = (Point *)av; + VertexMapping *b = (VertexMapping *)bv; + if (a->x < b->in.x) return -1; + if (a->x > b->in.x) return +1; + if (a->y < b->in.y) return -1; + if (a->y > b->in.y) return +1; + return 0; +} + +typedef struct MetatileSet { + /* The tiles in the set */ + tree234 *tiles; + + /* + * Bounding box of a rectangular region within the original single + * tile this set was expanded from. We need this in order to pick + * a random chunk out of the tiling to return to our client: this + * box is the limit of where we might select our chunk from. + * + * The box is obtained by starting from the two obtuse vertices of + * the starting P metatile, and then mapping those two vertices + * through each expansion pass. This wouldn't work for the _other_ + * two vertices of the P metatile, which end up in the middle of + * another metatile after the first expansion, so that the next + * expansion wouldn't find that point in its VertexMapping. But + * luckily the two inner P vertices do continue working: they + * alternate in subsequent expansions between vertex 1 and vertex + * 4 of an F metatile. And those are the ones we need to define a + * reliable bounding box - phew! + */ + Point vertices[2]; + size_t nvertices; +} MetatileSet; + +static MetatileSet *metatile_initial_set(MetatileType type) +{ + MetatileSet *s; + Metatile *m; + Point vertices[MT_MAXVERT]; + size_t nv; + + s = snew(MetatileSet); + s->tiles = newtree234(metatile_cmp); + + m = snew(Metatile); + m->type = type; + m->start.x = 0; + m->start.y = 0; + m->orientation.x = 1; + m->orientation.y = 0; + m->ncoords = 0; + add234(s->tiles, m); + + if (type == MT_P) { + nv = metatile_vertices(*m, vertices, false); + assert(nv == 4); + s->vertices[0] = vertices[1]; + s->vertices[1] = vertices[3]; + s->nvertices = 2; + } else { + s->nvertices = 0; + } + + return s; +} + +static void metatile_free_set(MetatileSet *s) +{ + Metatile *m; + + while ((m = delpos234(s->tiles, 0)) != NULL) + sfree(m); + freetree234(s->tiles); + sfree(s); +} + +typedef struct Queue { + Metatile *head, *tail; +} Queue; + +static void map_vertex(VertexMapping *vm, Point out, Queue *queue) +{ + size_t i; + + debug(("map_vertex %d,%d -> %d,%d", vm->in.x, vm->in.y, out.x, out.y)); + if (vm->mapped) { + debug((" (already done)\n")); + return; + } + debug(("\n")); + + vm->mapped = true; + vm->out = out; + + for (i = 0; i < vm->ntiles; i++) { + Metatile *t = vm->tiles[i]; + if (!t->queued) { + t->queued = true; + t->qnext = NULL; + if (queue->tail) + queue->tail->qnext = t; + else + queue->head = t; + queue->tail = t; + debug(("queued %c @ %d,%d d=%d,%d\n", "HTPF"[t->type], t->start.x, + t->start.y, t->orientation.x, t->orientation.y)); + } + } +} + +/* + * Expand a set of metatiles into its next-generation set. Returns the + * new set. The old set is not freed, but the auxiliary fields of its + * Metatile structures will be used as intermediate storage. + */ +static MetatileSet *metatile_set_expand(MetatileSet *si) +{ + tree234 *vmap; + VertexMapping *vm; + Metatile *m; + Queue queue = { NULL, NULL }; + size_t i, j; + MetatileSet *so = snew(MetatileSet); + + so->tiles = newtree234(metatile_cmp); + + /* + * Enumerate all the vertices in our tiling, and store the set of + * tiles they belong to. + */ + vmap = newtree234(vertexmapping_cmp); + for (i = 0; (m = index234(si->tiles, i)) != NULL; i++) { + Point vertices[MT_MAXVERT]; + size_t nv = metatile_vertices(*m, vertices, false); + + for (j = 0; j < nv; j++) { + VertexMapping *newvm = snew(VertexMapping); + newvm->in = vertices[j]; + newvm->ntiles = 0; + newvm->mapped = false; + + vm = add234(vmap, newvm); + if (vm != newvm) + sfree(newvm); + + assert(vm->ntiles < MT_MAXVDEGREE); + vm->tiles[vm->ntiles++] = m; + } + + m->queued = false; + } + + for (i = 0; (vm = index234(vmap, i)) != NULL; i++) { + debug(("vertex @ %d,%d {", vm->in.x, vm->in.y)); + for (j = 0; j < vm->ntiles; j++) { + m = vm->tiles[j]; + debug(("%s%c @ %d,%d d=%d,%d", j?", ":"", "HTPF"[m->type], + m->start.x, m->start.y, m->orientation.x, + m->orientation.y)); + } + debug(("}\n")); + } + + /* + * Initialise an arbitrary vertex to a known location. + */ + { + Point p = {0, 0}; + m = index234(si->tiles, 0); + vm = find234(vmap, &m->start, vertexmapping_find); + map_vertex(vm, p, &queue); + } + + /* + * Now process the queue of tiles to be expanded. + */ + debug(("-- start\n")); + while (queue.head) { + Metatile *m, m_moved; + Metatile t[MT_MAXEXPAND]; + Point vi[MT_MAXVERT], vo[MT_MAXVERT]; + size_t nv, nt; + + m = queue.head; + queue.head = queue.head->qnext; + if (!queue.head) + queue.tail = NULL; + + debug(("unqueued %c @ %d,%d d=%d,%d\n", "HTPF"[m->type], + m->start.x, m->start.y, m->orientation.x, m->orientation.y)); + + nv = metatile_vertices(*m, vi, false); + metatile_vertices(*m, vo, true); + + /* Find a vertex of this tile that's already mapped, and use + * it to determine the placement. */ + int dx, dy; + for (i = 0; i < nv; i++) { + vm = find234(vmap, &vi[i], vertexmapping_find); + assert(vm); + if (vm->mapped) { + dx = vm->out.x - vo[i].x; + dy = vm->out.y - vo[i].y; + debug(("found mapped vertex %d,%d -> %d,%d: " + "offset=%d,%d\n", + vm->in.x, vm->in.y, vm->out.x, vm->out.y, dx, dy)); + break; + } + } + assert(i < nv && "Why was this tile queued without a mapped vertex?"); + + /* Now map all the rest of the vertices of the tile. */ + for (i = 0; i < nv; i++) { + vm = find234(vmap, &vi[i], vertexmapping_find); + vo[i].x += dx; + vo[i].y += dy; + map_vertex(vm, vo[i], &queue); + } + + /* And expand it, substituting in its new starting coordinate. */ + m_moved = *m; /* structure copy */ + m_moved.start = vo[0]; + nt = metatile_expand(m_moved, t); + for (i = 0; i < nt; i++) { + Metatile *newmt = snew(Metatile); + *newmt = t[i]; /* structure copy */ + newmt->ncoords = 0; + debug(("expanded %c @ %d,%d d=%d,%d\n", "HTPF"[newmt->type], + newmt->start.x, newmt->start.y, newmt->orientation.x, + newmt->orientation.y)); + + Metatile *added = add234(so->tiles, newmt); + if (added != newmt) + sfree(newmt); + assert(added->ncoords < lenof(added->coords)); + added->coords[added->ncoords].parent = m; + added->coords[added->ncoords].index = i; + added->ncoords++; + } + } + + for (i = 0; (m = index234(si->tiles, i)) != NULL; i++) { + if (!m->queued) + debug(("OMITTED %c @ %d,%d d=%d,%d\n", "HTPF"[m->type], + m->start.x, m->start.y, m->orientation.x, + m->orientation.y)); + } + + /* + * Write out the remapped versions of the tile set's bounding + * vertices. + */ + for (i = 0; i < si->nvertices; i++) { + vm = find234(vmap, &si->vertices[i], vertexmapping_find); + so->vertices[i] = vm->out; + } + so->nvertices = si->nvertices; + + while ((vm = delpos234(vmap, 0)) != NULL) + sfree(vm); + freetree234(vmap); + + return so; +} + +typedef struct Hat { + Point start, orientation; + bool reversed; + const Metatile *parent; + int index; +} Hat; + +static size_t metatile_hats(const Metatile *m, Hat *out) +{ + static const Hat hats_H[] = { + {{6, 0}, {1, 0}, false}, + {{6, 6}, {0, -1}, false}, + {{0, 12}, {1, 0}, false}, + {{0, 6}, {-1, 0}, true}, + }; + static const Hat hats_T[] = { + {{-2, 10}, {-1, 1}, false}, + }; + static const Hat hats_P[] = { + {{-2, 10}, {-1, 1}, false}, + {{-2, 16}, {0, 1}, false}, + }; + static const Hat hats_F[] = { + {{0, 6}, {-1, 1}, false}, + {{0, 12}, {0, 1}, false}, + }; + + const Hat *hats; + size_t nhats; + size_t i; + + switch (m->type) { + case MT_H: + hats = hats_H; + nhats = lenof(hats_H); + break; + case MT_T: + hats = hats_T; + nhats = lenof(hats_T); + break; + case MT_P: + hats = hats_P; + nhats = lenof(hats_P); + break; + default /* case MT_F */: + hats = hats_F; + nhats = lenof(hats_F); + break; + } + assert(nhats <= MT_MAXHAT); + + Point orientation_r = left6(m->orientation); + for (i = 0; i < nhats; i++) { + Hat h = hats[i]; + out[i].parent = m; + out[i].index = i; + out[i].start.x = (m->start.x + h.start.x * m->orientation.x + + h.start.y * orientation_r.x); + out[i].start.y = (m->start.y + h.start.x * m->orientation.y + + h.start.y * orientation_r.y); + out[i].orientation.x = (h.orientation.x * m->orientation.x + + h.orientation.y * orientation_r.x); + out[i].orientation.y = (h.orientation.x * m->orientation.y + + h.orientation.y * orientation_r.y); + out[i].reversed = h.reversed; + } + return nhats; +} + +static size_t hat_vertices(Hat h, Point *out) +{ + static const Point reference_hat[] = { + {0, 0}, {3, 0}, {2, 2}, {0, 3}, {-2, 4}, {-3, 3}, {-6, 6}, {-9, 6}, + {-8, 4}, {-6, 3}, {-6, 0}, {-3, -3}, {-2, -2}, {0, -3}, + }; + + size_t i; + + Point orientation_r; + if (h.reversed) + orientation_r = right6(h.orientation); + else + orientation_r = left6(h.orientation); + assert(lenof(reference_hat) == HAT_NVERT); + + for (i = 0; i < lenof(reference_hat); i++) { + Point v = reference_hat[h.reversed ? HAT_NVERT-1-i : i]; + out[i].x = h.start.x + v.x * h.orientation.x + v.y * orientation_r.x; + out[i].y = h.start.y + v.x * h.orientation.y + v.y * orientation_r.y; + } + return lenof(reference_hat); +} + +typedef struct BoundingBox { + Point bl, tr; +} BoundingBox; + +static bool point_in_bbox(Point p, const BoundingBox *bbox) +{ + int xl, xr, x; + + if (!bbox) + return true; + + /* + * Bounding boxes have vertical edges, not aligned with our basis + * vector r. So the 'true' x coordinate of (x,y) is proportional + * to 2x+y. + */ + if (p.y < bbox->bl.y || p.y > bbox->tr.y) + return false; + + xl = 2*bbox->bl.x + bbox->bl.y; + xr = 2*bbox->tr.x + bbox->tr.y; + x = 2*p.x + p.y; + + if (x < xl || x > xr) + return false; + + return true; +} + +static bool hat_in_bbox(Hat h, const BoundingBox *bbox) +{ + Point p[HAT_NVERT]; + size_t i, np; + + if (!bbox) + return true; + + np = hat_vertices(h, p); + for (i = 0; i < np; i++) + if (!point_in_bbox(p[i], bbox)) + return false; + + return true; +} + +static Hat *metatile_set_to_hats(MetatileSet *s, size_t *nhats, + const BoundingBox *bbox) +{ + Metatile *m; + size_t i, j, k, n; + Hat *h; + + n = 0; + for (i = 0; (m = index234(s->tiles, i)) != NULL; i++) { + Hat htmp[MT_MAXHAT]; + size_t nthis = metatile_hats(m, htmp); + for (k = 0; k < nthis; k++) + if (hat_in_bbox(htmp[k], bbox)) + n++; + } + + *nhats = n; + h = snewn(n, Hat); + + j = 0; + for (i = 0; (m = index234(s->tiles, i)) != NULL; i++) { + Hat htmp[MT_MAXHAT]; + size_t nthis = metatile_hats(m, htmp); + for (k = 0; k < nthis; k++) { + if (hat_in_bbox(htmp[k], bbox)) { + assert(j < n); + h[j++] = htmp[k]; /* structure copy */ + } + } + } + + assert(j == n); + return h; +} + +#if 0 +void hat_tiling_randomise(struct HatPatchParams *params, random_state *rs) +{ + MetatileSet *s, *s2; + int x0, x1, y0, y1; + + /* + * Iterate until we have a good-sized patch to select a rectangle + * from. + */ + s = metatile_initial_set(MT_P); + params->iterations = 0; + + while (true) { + x0 = 2 * s->vertices[0].x + s->vertices[0].y; + x1 = 2 * s->vertices[1].x + s->vertices[1].y; + if (x1 < x0) { + int t = x1; + x1 = x0; + x0 = t; + } + y0 = s->vertices[0].y; + y1 = s->vertices[1].y; + if (y1 < y0) { + int t = y1; + y1 = y0; + y0 = t; + } + + if (50*params->w <= x1-x0 && 50*params->h <= y1-y0) + break; + + params->iterations++; + s2 = metatile_set_expand(s); + metatile_free_set(s); + s = s2; + } + + /* + * Now select that rectangle. + */ + params->x = x0 + random_upto(rs, x1 - x0 - params->w + 1); + params->y = y0 + random_upto(rs, y1 - y0 - params->h + 1); +} + +void hat_tiling_generate(struct HatPatchParams *params, + hat_tile_callback_fn cb, void *cbctx) +{ + MetatileSet *s, *s2; + unsigned i; + size_t j, nh; + BoundingBox bbox; + Hat *hats; + + s = metatile_initial_set(MT_P); + for (i = 0; i < params->iterations; i++) { + s2 = metatile_set_expand(s); + metatile_free_set(s); + s = s2; + } + + bbox.bl.x = (params->x - params->y) / 2; + bbox.tr.x = ((params->x + params->w) - (params->y + params->h)) / 2; + bbox.bl.y = params->y; + bbox.tr.y = params->y + params->h; + hats = metatile_set_to_hats(s, &nh, &bbox); + for (j = 0; j < nh; j++) { + Point vertices[HAT_NVERT]; + size_t nv = hat_vertices(hats[j], vertices); + int out[2 * HAT_NVERT]; + size_t k; + + for (k = 0; k < nv; k++) { + out[2*k] = 2 * vertices[k].x + vertices[k].y; + out[2*k+1] = vertices[k].y; + } + + cb(cbctx, nv, out); + } + sfree(hats); + + metatile_free_set(s); +} + +#endif + +#ifdef TEST_HAT + +/* + * Assortment of test modes that output Postscript diagrams. + */ + +static size_t hat_kite_centres(Hat h, Point *out) +{ + static const Point reference_hat[] = { + {-7,5},{-5,4},{-5,1},{-4,-1},{-1,-1},{-2,1},{-1,2},{1,1}, + }; + + size_t i; + + Point orientation_r; + if (h.reversed) + orientation_r = right6(h.orientation); + else + orientation_r = left6(h.orientation); + assert(lenof(reference_hat) == HAT_NKITE); + + for (i = 0; i < lenof(reference_hat); i++) { + Point v = reference_hat[i]; + out[i].x = h.start.x + v.x * h.orientation.x + v.y * orientation_r.x; + out[i].y = h.start.y + v.x * h.orientation.y + v.y * orientation_r.y; + } + return lenof(reference_hat); +} + +static inline int round6(int x) +{ + int sign = x<0 ? -1 : +1; + x *= sign; + x += 3; + x /= 6; + x *= 6; + x *= sign; + return x; +} + +static inline Point kite_left(Point k) +{ + Point centre = { round6(k.x), round6(k.y) }; + Point offset = { k.x - centre.x, k.y - centre.y }; + offset = left6(offset); + Point r = { centre.x + offset.x, centre.y + offset.y }; + return r; +} + +static inline Point kite_right(Point k) +{ + Point centre = { round6(k.x), round6(k.y) }; + Point offset = { k.x - centre.x, k.y - centre.y }; + offset = right6(offset); + Point r = { centre.x + offset.x, centre.y + offset.y }; + return r; +} + +static inline Point kite_forward_left(Point k) +{ + Point centre = { round6(k.x), round6(k.y) }; + Point offset = { k.x - centre.x, k.y - centre.y }; + Point rotate = left6(offset); + Point r = { k.x + rotate.x + offset.x, k.y + rotate.y + offset.y }; + return r; +} + +static inline Point kite_forward_right(Point k) +{ + Point centre = { round6(k.x), round6(k.y) }; + Point offset = { k.x - centre.x, k.y - centre.y }; + Point rotate = right6(offset); + Point r = { k.x + rotate.x + offset.x, k.y + rotate.y + offset.y }; + return r; +} + +typedef struct pspoint { + float x, y; +} pspoint; + +static inline pspoint pscoords(Point p) +{ + pspoint q = { p.x + p.y / 2.0F, p.y * sqrt(0.75) }; + return q; +} + +typedef struct psbbox { + bool started; + pspoint bl, tr; +} psbbox; + +static inline void psbbox_add(psbbox *bbox, pspoint p) +{ + if (!bbox->started || bbox->bl.x > p.x) + bbox->bl.x = p.x; + if (!bbox->started || bbox->tr.x < p.x) + bbox->tr.x = p.x; + if (!bbox->started || bbox->bl.y > p.y) + bbox->bl.y = p.y; + if (!bbox->started || bbox->tr.y < p.y) + bbox->tr.y = p.y; + bbox->started = true; +} + +static void draw_metatiles_svg(const Metatile *tiles, size_t n, + const Point *bounds, bool coords) +{ + size_t i, j; + psbbox bbox = { false }; + + for (i = 0; i < n; i++) { + Point vertices[MT_MAXVERT]; + size_t nv = metatile_vertices(tiles[i], vertices, false); + for (j = 0; j < nv; j++) + psbbox_add(&bbox, pscoords(vertices[j])); + } + + float ascale = 10, xscale = ascale, yscale = -ascale; + float border = 0.2 * ascale; /* leave room for strokes at the edges */ + float ox = -xscale * bbox.bl.x + border; + float oy = -yscale * bbox.tr.y + border; + + printf("\n"); + printf("\n", + ceil(ox + xscale * bbox.tr.x + 2*border), + ceil(oy + yscale * bbox.bl.y + 2*border)); + + for (i = 0; i < n; i++) { + Point vertices[MT_MAXVERT]; + size_t nv = metatile_vertices(tiles[i], vertices, false); + pspoint pp[MT_MAXVERT]; + + for (j = 0; j < nv; j++) { + pp[j] = pscoords(vertices[j]); + pp[j].x = ox + xscale * pp[j].x; + pp[j].y = oy + yscale * pp[j].y; + } + + printf("\n"); + + if (tiles[i].type != MT_F) { + /* + * Mark arrows on three of the metatile types (H, T, P), + * following the diagrams in the paper. (The metatile + * shapes other than F each have some symmetry, but their + * roles in the metatile substitution system are not + * similarly symmetric, so for diagnostic diagrams you + * want to mark their orientation.) + */ + pspoint lstart, lend; + pspoint astart, aend, aforward, aleft; + double d; + + /* + * Determine endpoints of a line crossing the polygon in + * the appropriate direction, by case analysis on the + * individual tile types. + */ + switch (tiles[i].type) { + case MT_H: + lstart.x = (pp[4].x + pp[5].x) / 2; + lstart.y = (pp[4].y + pp[5].y) / 2; + lend.x = (pp[1].x + pp[2].x) / 2; + lend.y = (pp[1].y + pp[2].y) / 2; + break; + case MT_T: + lstart = pp[0]; + lend.x = (pp[1].x + pp[2].x) / 2; + lend.y = (pp[1].y + pp[2].y) / 2; + break; + default /* case MT_P */: + lstart.x = (5*pp[3].x + 3*pp[0].x) / 8; + lstart.y = (5*pp[3].y + 3*pp[0].y) / 8; + lend.x = (5*pp[1].x + 3*pp[2].x) / 8; + lend.y = (5*pp[1].y + 3*pp[2].y) / 8; + break; + } + + /* + * Now shorten that line a little and give it an arrowhead. + */ + astart.x = (4 * lstart.x + lend.x) / 5; + astart.y = (4 * lstart.y + lend.y) / 5; + aend.x = (lstart.x + 4 * lend.x) / 5; + aend.y = (lstart.y + 4 * lend.y) / 5; + aforward.x = aend.x - astart.x; + aforward.y = aend.y - astart.y; + d = sqrt(aforward.x*aforward.x + aforward.y*aforward.y); + aforward.x /= d; + aforward.y /= d; + aleft.x = -aforward.y; + aleft.y = +aforward.x; + + printf("\n"); + } + + if (coords) { + /* + * Print each tile's coordinates. + */ + pspoint centre; + size_t j; + + switch (tiles[i].type) { + case MT_H: + centre.x = (pp[0].x + pp[2].x + pp[4].x) / 3; + centre.y = (pp[0].y + pp[2].y + pp[4].y) / 3; + break; + case MT_T: + centre.x = (pp[0].x + pp[1].x + pp[2].x) / 3; + centre.y = (pp[0].y + pp[1].y + pp[2].y) / 3; + break; + case MT_P: + centre.x = (pp[0].x + pp[2].x) / 2; + centre.y = (pp[0].y + pp[2].y) / 2; + break; + default /* case MT_F */: + centre.x = (pp[2].x + pp[4].x) / 2; + centre.y = (pp[2].y + pp[4].y) / 2; + break; + } + + double lineheight = ascale * 1.5; + double charheight = lineheight * 0.6; /* close enough */ + double allheight = lineheight * (tiles[i].ncoords-1) + charheight; + + for (j = 0; j < tiles[i].ncoords; j++) { + const Metatile *it; + unsigned cindex; + + printf("", lineheight, + centre.x, + centre.y - allheight/2 + charheight + lineheight*j); + + it = &tiles[i]; + cindex = j; + while (cindex < it->ncoords) { + if (it != &tiles[i]) + printf("."); + printf("%d", (int)it->coords[cindex].index); + + it = it->coords[cindex].parent; + cindex = 0; /* BODGING AHOY */ + } + + printf("\n"); + } + } + + } + + printf("\n"); +} + +static void draw_metatile_set_svg( + MetatileSet *tiles, const Point *bounds, bool coords) +{ + /* + * Slurp the tree234 of tiles into an array for display. + * Tedious, but this test code doesn't have to be particularly + * efficient. + */ + size_t nt = count234(tiles->tiles); + Metatile *t = snewn(nt, Metatile); + size_t i; + for (i = 0; i < nt; i++) { + Metatile *m = index234(tiles->tiles, i); + t[i] = *m; /* structure copy */ + } + draw_metatiles_svg(t, nt, bounds, coords); + sfree(t); +} + +static void draw_hats_svg(const Hat *hats, size_t n, + const Point *bounds, bool kites, char coordtype) +{ + size_t i, j; + psbbox bbox = { false }; + + for (i = 0; i < n; i++) { + Point vertices[HAT_NVERT]; + size_t nv = hat_vertices(hats[i], vertices); + for (j = 0; j < nv; j++) + psbbox_add(&bbox, pscoords(vertices[j])); + } + + float ascale = (coordtype == 'k' || coordtype == 'K' ? 20 : 10); + float xscale = ascale, yscale = -ascale; + float border = 0.2 * ascale; /* leave room for strokes at the edges */ + float ox = -xscale * bbox.bl.x + border; + float oy = -yscale * bbox.tr.y + border; + + printf("\n"); + printf("\n", + ceil(ox + xscale * bbox.tr.x + 2*border), + ceil(oy + yscale * bbox.bl.y + 2*border)); + + for (i = 0; i < n; i++) { + Point vertices[HAT_NVERT]; + pspoint psvs[HAT_NVERT]; + size_t nv = hat_vertices(hats[i], vertices); + int is = hats[i].reversed ? -1 : +1; + int io = hats[i].reversed ? 13 : 0; + + printf("\n"); + + if (kites) { + /* + * Draw internal lines within each hat dividing it into + * kites. This is done in a rather bodgy way, sorry. + */ + const char *fmt = "\n"; + float strokewidth = 0.1 * ascale; + + printf(fmt, strokewidth, + ox + xscale * psvs[io+is*0].x, + oy + yscale * psvs[io+is*0].y, + ox + xscale * psvs[io+is*3].x, + oy + yscale * psvs[io+is*3].y); + + printf(fmt, strokewidth, + ox + xscale * psvs[io+is*0].x, + oy + yscale * psvs[io+is*0].y, + ox + xscale * psvs[io+is*5].x, + oy + yscale * psvs[io+is*5].y); + + printf(fmt, strokewidth, + ox + xscale * psvs[io+is*6].x, + oy + yscale * psvs[io+is*6].y, + ox + xscale * psvs[io+is*9].x, + oy + yscale * psvs[io+is*9].y); + + printf(fmt, strokewidth, + ox + xscale * psvs[io+is*0].x, + oy + yscale * psvs[io+is*0].y, + ox + xscale * psvs[io+is*10].x, + oy + yscale * psvs[io+is*10].y); + + printf(fmt, strokewidth, + ox + xscale * psvs[io+is*9].x, + oy + yscale * psvs[io+is*9].y, + ox + xscale * (psvs[io+is*6].x + psvs[io+is*12].x) / 2, + oy + yscale * (psvs[io+is*6].y + psvs[io+is*12].y) / 2); + + printf(fmt, strokewidth, + ox + xscale * psvs[io+is*5].x, + oy + yscale * psvs[io+is*5].y, + ox + xscale * (psvs[io+is*6].x + psvs[io+is*12].x) / 2, + oy + yscale * (psvs[io+is*6].y + psvs[io+is*12].y) / 2); + + printf(fmt, strokewidth, + ox + xscale * psvs[io+is*12].x, + oy + yscale * psvs[io+is*12].y, + ox + xscale * (psvs[io+is*6].x + psvs[io+is*12].x) / 2, + oy + yscale * (psvs[io+is*6].y + psvs[io+is*12].y) / 2); + } + + if (coordtype == 'h') { + double lineheight = ascale * 2; + double charheight = lineheight * 0.6; /* close enough */ + + printf("", lineheight, + ox + xscale * (psvs[io+is*0].x + psvs[io+is*10].x) / 2, + oy + yscale * (psvs[io+is*0].y + psvs[io+is*10].y) / 2 + + charheight/2); + printf("%d", (int)i); + printf("\n"); + } else if (coordtype == 'k') { + Point kites[HAT_NKITE]; + size_t nk = hat_kite_centres(hats[i], kites); + + double lineheight = ascale * 0.5; + double charheight = lineheight * 0.6; /* close enough */ + + for (j = 0; j < nk; j++) { + pspoint p = pscoords(kites[j]); + + printf("", lineheight, + ox + xscale * p.x, + oy + yscale * p.y + charheight/2); + + printf("%d.%d.%d", (int)j, hats[i].index, + hats[i].parent->coords[0].index); + + printf("\n"); + } + } else if (coordtype == 'K') { + Point kites[HAT_NKITE]; + size_t nk = hat_kite_centres(hats[i], kites); + + double lineheight = ascale * 1.1; + double charheight = lineheight * 0.6; /* close enough */ + + for (j = 0; j < nk; j++) { + pspoint p = pscoords(kites[j]); + + printf("", lineheight, + ox + xscale * p.x, + oy + yscale * p.y + charheight/2); + printf("%d", (int)j); + printf("\n"); + } + } + } + + printf("\n"); +} + +typedef enum KiteStep { KS_LEFT, KS_RIGHT, KS_F_LEFT, KS_F_RIGHT } KiteStep; + +static inline Point kite_step(Point k, KiteStep step) +{ + switch (step) { + case KS_LEFT: return kite_left(k); + case KS_RIGHT: return kite_right(k); + case KS_F_LEFT: return kite_forward_left(k); + default /* case KS_F_RIGHT */: return kite_forward_right(k); + } +} + +int main(int argc, char **argv) +{ + if (argc <= 1) { + printf("usage: hat-test \n"); + printf("modes: H,T,P,F display a single unexpanded tile\n"); + printf(" xH,xT,xP,xF display the expansion of one tile\n"); + printf(" cH,cT,cP,cF display expansion with tile coords\n"); + printf(" CH,CT,CP,CF display double expansion with coords\n"); + printf(" hH,hT,hP,hF display the hats from one tile\n"); + printf(" HH,HT,HP,HF hats from an expansion, with coords\n"); + printf(" m1, m2, ... nth expansion of one H metatile\n"); + printf(" M1, M2, ... nth expansion turned into real hats\n"); + printf(" --hat show the kites in a single hat\n"); + printf(" --tables generate hat-tables.h for hat.c\n"); + return 0; + } + + if (!strcmp(argv[1], "H") || !strcmp(argv[1], "T") || + !strcmp(argv[1], "P") || !strcmp(argv[1], "F")) { + MetatileType type = (argv[1][0] == 'H' ? MT_H : + argv[1][0] == 'T' ? MT_T : + argv[1][0] == 'P' ? MT_P : MT_F); + Metatile m = {type, {0, 0}, {1, 0}}; + draw_metatiles_svg(&m, 1, NULL, false); + return 0; + } + + if (!strcmp(argv[1], "xH") || !strcmp(argv[1], "xT") || + !strcmp(argv[1], "xP") || !strcmp(argv[1], "xF")) { + MetatileType type = (argv[1][1] == 'H' ? MT_H : + argv[1][1] == 'T' ? MT_T : + argv[1][1] == 'P' ? MT_P : MT_F); + Metatile m = {type, {0, 0}, {1, 0}}; + Metatile t[MT_MAXEXPAND]; + size_t nt = metatile_expand(m, t); + draw_metatiles_svg(t, nt, NULL, false); + return 0; + } + + if (argv[1][0] && argv[1][1] && + strchr("cC", argv[1][0]) && strchr("HTPF", argv[1][1])) { + MetatileType type = (argv[1][1] == 'H' ? MT_H : + argv[1][1] == 'T' ? MT_T : + argv[1][1] == 'P' ? MT_P : MT_F); + MetatileSet *t[3]; + int nsets = (argv[1][0] == 'c' ? 2 : 3); + int i; + + t[0] = metatile_initial_set(type); + for (i = 1; i < nsets; i++) + t[i] = metatile_set_expand(t[i-1]); + draw_metatile_set_svg(t[nsets-1], NULL, true); + for (i = 0; i < nsets; i++) + metatile_free_set(t[i]); + return 0; + } + + if (!strcmp(argv[1], "hH") || !strcmp(argv[1], "hT") || + !strcmp(argv[1], "hP") || !strcmp(argv[1], "hF")) { + MetatileType type = ( + !strcmp(argv[1], "hH") ? MT_H : + !strcmp(argv[1], "hT") ? MT_T : + !strcmp(argv[1], "hP") ? MT_P : MT_F); + Metatile m = {type, {0, 0}, {1, 0}}; + Hat h[MT_MAXHAT]; + size_t nh = metatile_hats(&m, h); + draw_hats_svg(h, nh, NULL, false, 'h'); + return 0; + } + + if (!strcmp(argv[1], "--hat")) { + Hat h = { { 0, 0 }, { 1, 0 }, false, NULL, 0 }; + draw_hats_svg(&h, 1, NULL, true, 'K'); + return 0; + } + + if (argv[1][0] == 'H' && argv[1][1] && strchr("HTPF", argv[1][1])) { + MetatileType type = (argv[1][1] == 'H' ? MT_H : + argv[1][1] == 'T' ? MT_T : + argv[1][1] == 'P' ? MT_P : MT_F); + MetatileSet *t[2]; + size_t i, nh; + + t[0] = metatile_initial_set(type); + t[1] = metatile_set_expand(t[0]); + Hat *h = metatile_set_to_hats(t[1], &nh, NULL); + draw_hats_svg(h, nh, NULL, true, 'k'); + sfree(h); + for (i = 0; i < 2; i++) + metatile_free_set(t[i]); + return 0; + } + + if (argv[1][0] == 'm' || argv[1][0] == 'M') { + int niter = atoi(argv[1] + 1); + MetatileSet *tiles = metatile_initial_set(MT_P); + + while (niter-- > 0) { + MetatileSet *t2 = metatile_set_expand(tiles); + metatile_free_set(tiles); + tiles = t2; + } + + if (argv[1][0] == 'M') { + size_t nh; + Hat *h = metatile_set_to_hats(tiles, &nh, NULL); + draw_hats_svg(h, nh, tiles->vertices, false, 0); + sfree(h); + } else { + draw_metatile_set_svg(tiles, tiles->vertices, false); + } + + metatile_free_set(tiles); + + return 0; + } + + if (!strcmp(argv[1], "--tables")) { + size_t i, j, k; + + printf("/*\n" + " * Header file autogenerated by aux/hatgen.c\n" + " *\n" + " * To regenerate, run 'hatgen --tables > hat-tables.h'\n" + " */\n\n"); + + static const char HTPF[] = "HTPF"; + + printf("static const unsigned hats_in_metatile[] = {"); + for (i = 0; i < 4; i++) { + Metatile m = {i, {0, 0}, {1, 0}}; + Hat h[MT_MAXHAT]; + size_t nh = metatile_hats(&m, h); + printf(" %zu,", nh); + } + printf(" };\n\n"); + + { + struct Parent { + MetatileType t; + unsigned index; + } parents[4][4*MT_MAXEXPAND]; + size_t psizes[4] = {0, 0, 0, 0}; + size_t csizes[4] = {0, 0, 0, 0}; + + for (i = 0; i < 4; i++) { + Metatile m = {i, {0, 0}, {1, 0}}; + Metatile t[MT_MAXEXPAND]; + size_t nt = metatile_expand(m, t); + + printf("static const TileType children_%c[] = {\n" + " ", HTPF[i]); + for (j = 0; j < nt; j++) { + MetatileType c = t[j].type; + parents[c][psizes[c]].t = i; + parents[c][psizes[c]].index = j; + psizes[c]++; + csizes[i]++; + printf(" TT_%c,", HTPF[c]); + } + printf("\n};\n"); + } + + printf("static const TileType *const children[] = {\n"); + for (i = 0; i < 4; i++) + printf(" children_%c,\n", HTPF[i]); + printf("};\n"); + printf("static const size_t nchildren[] = {\n"); + for (i = 0; i < 4; i++) + printf(" %u,\n", (unsigned)csizes[i]); + printf("};\n\n"); + + for (i = 0; i < 4; i++) { + printf("static const MetatilePossibleParent " + "permitted_parents_%c[] = {\n", HTPF[i]); + for (j = 0; j < psizes[i]; j++) + printf(" { TT_%c, %u },\n", HTPF[parents[i][j].t], + parents[i][j].index); + printf("};\n"); + } + + printf("static const MetatilePossibleParent *const " + "permitted_parents[] = {\n"); + for (i = 0; i < 4; i++) + printf(" permitted_parents_%c,\n", HTPF[i]); + printf("};\n"); + + printf("static const size_t n_permitted_parents[] = {\n"); + for (i = 0; i < 4; i++) + printf(" %u,\n", (unsigned)psizes[i]); + printf("};\n\n"); + } + + { + for (i = 0; i < 4; i++) { + MetatileSet *t[2]; + size_t j, k, nh, nmeta, ti; + struct list { + Point kite; + unsigned ik, ih, im; + } list[8*MT_MAXHAT*MT_MAXEXPAND]; + size_t len = 0; + + t[0] = metatile_initial_set(i); + t[1] = metatile_set_expand(t[0]); + Hat *h = metatile_set_to_hats(t[1], &nh, NULL); + + printf("static const KitemapEntry kitemap_%c[] = {\n", + HTPF[i]); + + Point origin = h[0].start; + for (j = 0; j < nh; j++) { + Point kites[HAT_NKITE]; + size_t nk = hat_kite_centres(h[j], kites); + for (k = 0; k < nk; k++) { + struct list *le = &list[len++]; + le->kite.x = kites[k].x - origin.x; + le->kite.y = kites[k].y - origin.y; + le->ik = k; + le->ih = h[j].index; + le->im = h[j].parent->coords[0].index; +#if 0 + printf("// %d,%d = %u.%u.%u\n", le->kite.x, le->kite.y, le->ik, le->ih, le->im); +#endif + } + } + + nmeta = count234(t[1]->tiles); + for (ti = 0; ti < 8 * 4 * nmeta; ti++) { + unsigned ik = ti % 8; + unsigned ih = ti / 8 % 4; + unsigned im = ti / (8*4); + struct list *src = NULL, *dst = NULL; + int istep; + + for (j = 0; j < len; j++) { + struct list *tmp = &list[j]; + if (tmp->ik == ik && tmp->ih == ih && tmp->im == im) { + src = tmp; + break; + } + } + if (ik == 0) { + printf(" /* hat #%u in metatile #%u (type %c)", + ih, im, HTPF[((Metatile *)index234( + t[1]->tiles, im))->type]); + if (!src) + printf(" does not exist"); + printf(" */\n"); + } +#if 0 + if (src) + printf(" // src=%d,%d\n", src->kite.x, src->kite.y); +#endif + printf(" "); + + for (istep = 0; istep < 4; istep++) { + KiteStep step = istep; + dst = NULL; + if (src) { + Point pdst = kite_step(src->kite, step); +#if 0 + printf(" /* dst=%d,%d */", pdst.x, pdst.y); +#endif + for (k = 0; k < len; k++) { + struct list *tmp = &list[k]; + if (tmp->kite.x == pdst.x && + tmp->kite.y == pdst.y) { + dst = tmp; + break; + } + } + } + if (!dst) { + printf(" {-1,-1,-1},"); + } else { + printf(" {%u,%u,%u},", dst->ik, dst->ih, dst->im); + } + } + printf("\n"); + } + printf("};\n"); + + sfree(h); + for (j = 0; j < 2; j++) + metatile_free_set(t[j]); + } + + printf("static const KitemapEntry *const " + "kitemap[] = {\n"); + for (i = 0; i < 4; i++) + printf(" kitemap_%c,\n", HTPF[i]); + printf("};\n\n"); + + } + + { + for (i = 0; i < 4; i++) { + MetatileSet *t[3]; + Metatile *m; + int map[MT_MAXEXPAND * MT_MAXEXPAND]; + size_t maplen; + + for (j = 0; j < lenof(map); j++) + map[j] = -1; + + t[0] = metatile_initial_set(i); + for (j = 1; j < 3; j++) + t[j] = metatile_set_expand(t[j-1]); + + for (j = 0; (m = index234(t[2]->tiles, j)) != NULL; j++) { + unsigned coords[4]; + size_t ncoords = 0; + int cindex; + +#if 0 + printf("// ***\n"); +#endif + for (cindex = 0; cindex < m->ncoords; cindex++) { +#if 0 + printf("// %d.%d\n", (int)m->coords[cindex].index, + (int)m->coords[cindex].parent->coords[0].index); +#endif + coords[ncoords++] = ( + m->coords[cindex].index + MT_MAXEXPAND * + m->coords[cindex].parent->coords[0].index); + } + + unsigned prev = ncoords-1; + for (k = 0; k < ncoords; k++) { + map[coords[prev]] = coords[k]; + prev = k; + } + } + + printf("static const MetamapEntry metamap_%c[] = {\n", + HTPF[i]); + maplen = MT_MAXEXPAND * count234(t[1]->tiles); + for (j = 0; j < maplen; j++) { + printf(" /* %u, %u -> */ ", + (unsigned)(j % MT_MAXEXPAND), + (unsigned)(j / MT_MAXEXPAND)); + if (map[j] == -1) { + printf("{-1,-1}, /* does not exist */\n"); + } else { + printf("{%u, %u},", + (unsigned)(map[j] % MT_MAXEXPAND), + (unsigned)(map[j] / MT_MAXEXPAND)); + if (map[j] == j) + printf(" /* no alternatives */"); + printf("\n"); + } + } + printf("};\n"); + + for (j = 0; j < 3; j++) + metatile_free_set(t[j]); + } + + printf("static const MetamapEntry *const " + "metamap[] = {\n"); + for (i = 0; i < 4; i++) + printf(" metamap_%c,\n", HTPF[i]); + printf("};\n"); + } + + return 0; + } + + fprintf(stderr, "unknown test mode '%s'\n", argv[1]); + return 1; +} +#endif diff --git a/grid.c b/grid.c index 21353ba..bac8be8 100644 --- a/grid.c +++ b/grid.c @@ -19,6 +19,7 @@ #include "tree234.h" #include "grid.h" #include "penrose.h" +#include "hat.h" /* Debugging options */ @@ -3401,6 +3402,159 @@ static grid *grid_new_penrose_p3_thick(int width, int height, const char *desc) return grid_new_penrose(width, height, PENROSE_P3, desc); } +#define HATS_TILESIZE 32 +#define HATS_XSQUARELEN 4 +#define HATS_YSQUARELEN 6 +#define HATS_XUNIT 14 +#define HATS_YUNIT 8 + +static const char *grid_validate_params_hats( + int width, int height) +{ + int l = HATS_TILESIZE; + + if (width > INT_MAX / l || /* xextent */ + height > INT_MAX / l || /* yextent */ + width > INT_MAX / (6 * height)) /* max_dots */ + return "Grid must not be unreasonably large"; + return NULL; +} + +static void grid_size_hats(int width, int height, + int *tilesize, int *xextent, int *yextent) +{ + *tilesize = HATS_TILESIZE; + *xextent = width * HATS_XUNIT * HATS_XSQUARELEN; + *yextent = height * HATS_YUNIT * HATS_YSQUARELEN; +} + +static char *grid_new_desc_hats( + grid_type type, int width, int height, random_state *rs) +{ + char *buf, *p; + size_t bufmax, i; + struct HatPatchParams hp; + + hat_tiling_randomise(&hp, width, height, rs); + + bufmax = 3 * hp.ncoords + 2; + buf = snewn(bufmax, char); + p = buf; + for (i = 0; i < hp.ncoords; i++) { + assert(hp.coords[i] < 100); /* at most 2 digits */ + assert(p - buf <= bufmax-4); /* room for 2 digits, comma and NUL */ + p += sprintf(p, "%d,", (int)hp.coords[i]); + } + assert(p - buf <= bufmax-2); /* room for final letter and NUL */ + p[0] = hp.final_metatile; + p[1] = '\0'; + + sfree(hp.coords); + return buf; +} + +/* Shared code between validating and reading grid descs. + * Always allocates hp->coords, whether or not it returns an error. */ +static const char *grid_desc_to_hat_params( + const char *desc, struct HatPatchParams *hp) +{ + size_t maxcoords; + const char *p = desc; + + maxcoords = (strlen(desc) + 1) / 2; + hp->coords = snewn(maxcoords, unsigned char); + hp->ncoords = 0; + + while (isdigit((unsigned char)*p)) { + const char *p_orig = p; + int n = atoi(p); + while (*p && isdigit((unsigned char)*p)) p++; + if (*p != ',') + return "expected ',' in grid description"; + if (p - p_orig > 2 || n > 0xFF) + return "too-large coordinate in grid description"; + p++; /* eat the comma */ + + /* This assert should be guaranteed by the way we calculated + * maxcoords, so a failure of this check is a bug in this + * function, not an indication of an invalid input string */ + assert(hp->ncoords < maxcoords); + hp->coords[hp->ncoords++] = n; + } + + if (*p == 'H' || *p == 'T' || *p == 'P' || *p == 'F') + hp->final_metatile = *p; + else + return "invalid character in grid description"; + + return NULL; +} + +static const char *grid_validate_desc_hats( + grid_type type, int width, int height, const char *desc) +{ + struct HatPatchParams hp; + const char *error = NULL; + + error = grid_desc_to_hat_params(desc, &hp); + if (!error) + error = hat_tiling_params_invalid(&hp); + + sfree(hp.coords); + return error; +} + +struct hatcontext { + grid *g; + tree234 *points; +}; + +static void grid_hats_callback(void *vctx, size_t nvertices, int *coords) +{ + struct hatcontext *ctx = (struct hatcontext *)vctx; + size_t i; + + grid_face_add_new(ctx->g, nvertices); + for (i = 0; i < nvertices; i++) { + grid_dot *d = grid_get_dot( + ctx->g, ctx->points, + coords[2*i] * HATS_XUNIT, + coords[2*i+1] * HATS_YUNIT); + grid_face_set_dot(ctx->g, d, i); + } +} + +static grid *grid_new_hats(int width, int height, const char *desc) +{ + struct HatPatchParams hp; + const char *error = NULL; + + error = grid_desc_to_hat_params(desc, &hp); + assert(error == NULL && "grid_validate_desc_hats should have failed"); + + /* Upper bounds - don't have to be exact */ + int max_faces = (width * height * 6 + 7) / 8; + int max_dots = width * height * 6 + width * 2 + height * 2 + 1; + + struct hatcontext ctx[1]; + + ctx->g = grid_empty(); + ctx->g->tilesize = HATS_TILESIZE; + ctx->g->faces = snewn(max_faces, grid_face); + ctx->g->dots = snewn(max_dots, grid_dot); + + ctx->points = newtree234(grid_point_cmp_fn); + + hat_tiling_generate(&hp, width, height, grid_hats_callback, ctx); + + freetree234(ctx->points); + sfree(hp.coords); + + grid_trim_vigorously(ctx->g); + grid_make_consistent(ctx->g); + return ctx->g; +} + /* ----------- End of grid generators ------------- */ #define FNVAL(upper,lower) &grid_validate_params_ ## lower, @@ -3425,6 +3579,8 @@ char *grid_new_desc(grid_type type, int width, int height, random_state *rs) { if (type == GRID_PENROSE_P2 || type == GRID_PENROSE_P3) { return grid_new_desc_penrose(type, width, height, rs); + } else if (type == GRID_HATS) { + return grid_new_desc_hats(type, width, height, rs); } else if (type == GRID_TRIANGULAR) { return dupstr("0"); /* up-to-date version of triangular grid */ } else { @@ -3437,6 +3593,8 @@ const char *grid_validate_desc(grid_type type, int width, int height, { if (type == GRID_PENROSE_P2 || type == GRID_PENROSE_P3) { return grid_validate_desc_penrose(type, width, height, desc); + } else if (type == GRID_HATS) { + return grid_validate_desc_hats(type, width, height, desc); } else if (type == GRID_TRIANGULAR) { return grid_validate_desc_triangular(type, width, height, desc); } else { diff --git a/grid.h b/grid.h index 69108d4..c0246c1 100644 --- a/grid.h +++ b/grid.h @@ -109,7 +109,9 @@ typedef struct grid { A(GREATGREATDODECAGONAL,greatgreatdodecagonal) \ A(COMPASSDODECAGONAL,compassdodecagonal) \ A(PENROSE_P2,penrose_p2_kite) \ - A(PENROSE_P3,penrose_p3_thick) + A(PENROSE_P3,penrose_p3_thick) \ + A(HATS,hats) \ + /* end of list */ #define ENUM(upper,lower) GRID_ ## upper, typedef enum grid_type { GRIDGEN_LIST(ENUM) GRID_TYPE_MAX } grid_type; diff --git a/hat-tables.h b/hat-tables.h new file mode 100644 index 0000000..5b3b0ed --- /dev/null +++ b/hat-tables.h @@ -0,0 +1,2183 @@ +/* + * Header file autogenerated by aux/hatgen.c + * + * To regenerate, run 'hatgen --tables > hat-tables.h' + */ + +static const unsigned hats_in_metatile[] = { 4, 1, 2, 2, }; + +static const TileType children_H[] = { + TT_H, TT_H, TT_H, TT_T, TT_P, TT_P, TT_P, TT_F, TT_F, TT_F, TT_F, TT_F, TT_F, +}; +static const TileType children_T[] = { + TT_H, TT_P, TT_P, TT_P, TT_F, TT_F, TT_F, +}; +static const TileType children_P[] = { + TT_H, TT_H, TT_P, TT_P, TT_P, TT_F, TT_F, TT_F, TT_F, TT_F, TT_F, +}; +static const TileType children_F[] = { + TT_H, TT_H, TT_P, TT_P, TT_F, TT_F, TT_F, TT_F, TT_F, TT_F, TT_F, +}; +static const TileType *const children[] = { + children_H, + children_T, + children_P, + children_F, +}; +static const size_t nchildren[] = { + 13, + 7, + 11, + 11, +}; + +static const MetatilePossibleParent permitted_parents_H[] = { + { TT_H, 0 }, + { TT_H, 1 }, + { TT_H, 2 }, + { TT_T, 0 }, + { TT_P, 0 }, + { TT_P, 1 }, + { TT_F, 0 }, + { TT_F, 1 }, +}; +static const MetatilePossibleParent permitted_parents_T[] = { + { TT_H, 3 }, +}; +static const MetatilePossibleParent permitted_parents_P[] = { + { TT_H, 4 }, + { TT_H, 5 }, + { TT_H, 6 }, + { TT_T, 1 }, + { TT_T, 2 }, + { TT_T, 3 }, + { TT_P, 2 }, + { TT_P, 3 }, + { TT_P, 4 }, + { TT_F, 2 }, + { TT_F, 3 }, +}; +static const MetatilePossibleParent permitted_parents_F[] = { + { TT_H, 7 }, + { TT_H, 8 }, + { TT_H, 9 }, + { TT_H, 10 }, + { TT_H, 11 }, + { TT_H, 12 }, + { TT_T, 4 }, + { TT_T, 5 }, + { TT_T, 6 }, + { TT_P, 5 }, + { TT_P, 6 }, + { TT_P, 7 }, + { TT_P, 8 }, + { TT_P, 9 }, + { TT_P, 10 }, + { TT_F, 4 }, + { TT_F, 5 }, + { TT_F, 6 }, + { TT_F, 7 }, + { TT_F, 8 }, + { TT_F, 9 }, + { TT_F, 10 }, +}; +static const MetatilePossibleParent *const permitted_parents[] = { + permitted_parents_H, + permitted_parents_T, + permitted_parents_P, + permitted_parents_F, +}; +static const size_t n_permitted_parents[] = { + 8, + 1, + 11, + 22, +}; + +static const KitemapEntry kitemap_H[] = { + /* hat #0 in metatile #0 (type H) */ + {1,0,0}, {7,3,0}, {3,0,4}, {4,0,4}, + {4,3,0}, {0,0,0}, {5,0,0}, {2,0,0}, + {3,0,4}, {3,0,0}, {1,0,0}, {5,0,0}, + {2,0,0}, {1,2,1}, {4,0,0}, {6,2,1}, + {3,0,3}, {5,0,0}, {6,2,1}, {3,0,0}, + {4,0,0}, {6,0,0}, {2,0,0}, {1,0,0}, + {5,0,0}, {7,0,0}, {4,3,0}, {3,3,0}, + {6,0,0}, {2,0,3}, {7,1,0}, {0,0,3}, + /* hat #1 in metatile #0 (type H) */ + {1,1,0}, {2,0,5}, {7,1,8}, {0,0,5}, + {3,0,2}, {0,1,0}, {5,1,0}, {2,1,0}, + {7,1,8}, {3,1,0}, {1,1,0}, {5,1,0}, + {2,1,0}, {4,1,8}, {4,1,0}, {0,3,0}, + {2,3,0}, {5,1,0}, {0,3,0}, {3,1,0}, + {4,1,0}, {6,1,0}, {2,1,0}, {1,1,0}, + {5,1,0}, {7,1,0}, {3,0,2}, {4,0,2}, + {6,1,0}, {3,3,0}, {0,0,3}, {7,0,0}, + /* hat #2 in metatile #0 (type H) */ + {1,2,0}, {1,0,7}, {7,1,4}, {6,0,7}, + {3,0,8}, {0,2,0}, {5,2,0}, {2,2,0}, + {7,1,4}, {3,2,0}, {1,2,0}, {5,2,0}, + {2,2,0}, {4,1,4}, {4,2,0}, {6,3,0}, + {1,3,0}, {5,2,0}, {6,3,0}, {3,2,0}, + {4,2,0}, {6,2,0}, {2,2,0}, {1,2,0}, + {5,2,0}, {7,2,0}, {3,0,8}, {4,0,8}, + {6,2,0}, {0,3,0}, {3,1,8}, {4,1,8}, + /* hat #3 in metatile #0 (type H) */ + {7,2,0}, {1,3,0}, {3,1,0}, {4,1,0}, + {0,3,0}, {4,2,0}, {2,3,0}, {5,3,0}, + {3,3,0}, {4,1,0}, {5,3,0}, {1,3,0}, + {7,1,0}, {2,3,0}, {6,0,0}, {4,3,0}, + {5,3,0}, {1,0,0}, {3,3,0}, {6,0,0}, + {6,3,0}, {4,3,0}, {1,3,0}, {2,3,0}, + {7,3,0}, {5,3,0}, {3,2,0}, {4,2,0}, + {0,0,0}, {6,3,0}, {3,1,4}, {4,1,4}, + /* hat #0 in metatile #1 (type H) */ + {1,0,1}, {7,3,1}, {3,0,9}, {4,0,9}, + {4,3,1}, {0,0,1}, {5,0,1}, {2,0,1}, + {3,0,9}, {3,0,1}, {1,0,1}, {5,0,1}, + {2,0,1}, {1,0,10}, {4,0,1}, {6,0,10}, + {0,0,6}, {5,0,1}, {6,0,10}, {3,0,1}, + {4,0,1}, {6,0,1}, {2,0,1}, {1,0,1}, + {5,0,1}, {7,0,1}, {4,3,1}, {3,3,1}, + {6,0,1}, {1,0,6}, {7,1,1}, {6,0,6}, + /* hat #1 in metatile #1 (type H) */ + {1,1,1}, {1,1,2}, {7,0,3}, {6,1,2}, + {0,1,6}, {0,1,1}, {5,1,1}, {2,1,1}, + {7,0,3}, {3,1,1}, {1,1,1}, {5,1,1}, + {2,1,1}, {4,0,3}, {4,1,1}, {0,3,1}, + {2,3,1}, {5,1,1}, {0,3,1}, {3,1,1}, + {4,1,1}, {6,1,1}, {2,1,1}, {1,1,1}, + {5,1,1}, {7,1,1}, {0,1,6}, {7,0,6}, + {6,1,1}, {3,3,1}, {6,0,6}, {7,0,1}, + /* hat #2 in metatile #1 (type H) */ + {1,2,1}, {2,0,4}, {7,1,9}, {0,0,4}, + {3,0,0}, {0,2,1}, {5,2,1}, {2,2,1}, + {7,1,9}, {3,2,1}, {1,2,1}, {5,2,1}, + {2,2,1}, {4,1,9}, {4,2,1}, {6,3,1}, + {1,3,1}, {5,2,1}, {6,3,1}, {3,2,1}, + {4,2,1}, {6,2,1}, {2,2,1}, {1,2,1}, + {5,2,1}, {7,2,1}, {3,0,0}, {4,0,0}, + {6,2,1}, {0,3,1}, {3,0,3}, {4,0,3}, + /* hat #3 in metatile #1 (type H) */ + {7,2,1}, {1,3,1}, {3,1,1}, {4,1,1}, + {0,3,1}, {4,2,1}, {2,3,1}, {5,3,1}, + {3,3,1}, {4,1,1}, {5,3,1}, {1,3,1}, + {7,1,1}, {2,3,1}, {6,0,1}, {4,3,1}, + {5,3,1}, {1,0,1}, {3,3,1}, {6,0,1}, + {6,3,1}, {4,3,1}, {1,3,1}, {2,3,1}, + {7,3,1}, {5,3,1}, {3,2,1}, {4,2,1}, + {0,0,1}, {6,3,1}, {3,1,9}, {4,1,9}, + /* hat #0 in metatile #2 (type H) */ + {1,0,2}, {7,3,2}, {3,0,5}, {4,0,5}, + {4,3,2}, {0,0,2}, {5,0,2}, {2,0,2}, + {3,0,5}, {3,0,2}, {1,0,2}, {5,0,2}, + {2,0,2}, {1,1,0}, {4,0,2}, {6,1,0}, + {0,0,3}, {5,0,2}, {6,1,0}, {3,0,2}, + {4,0,2}, {6,0,2}, {2,0,2}, {1,0,2}, + {5,0,2}, {7,0,2}, {4,3,2}, {3,3,2}, + {6,0,2}, {1,0,3}, {7,1,2}, {6,0,3}, + /* hat #1 in metatile #2 (type H) */ + {1,1,2}, {1,1,6}, {7,1,12}, {6,1,6}, + {0,1,1}, {0,1,2}, {5,1,2}, {2,1,2}, + {7,1,12}, {3,1,2}, {1,1,2}, {5,1,2}, + {2,1,2}, {4,1,12}, {4,1,2}, {0,3,2}, + {2,3,2}, {5,1,2}, {0,3,2}, {3,1,2}, + {4,1,2}, {6,1,2}, {2,1,2}, {1,1,2}, + {5,1,2}, {7,1,2}, {0,1,1}, {7,0,3}, + {6,1,2}, {3,3,2}, {6,0,3}, {7,0,2}, + /* hat #2 in metatile #2 (type H) */ + {1,2,2}, {1,0,11}, {7,1,5}, {6,0,11}, + {3,0,12}, {0,2,2}, {5,2,2}, {2,2,2}, + {7,1,5}, {3,2,2}, {1,2,2}, {5,2,2}, + {2,2,2}, {4,1,5}, {4,2,2}, {6,3,2}, + {1,3,2}, {5,2,2}, {6,3,2}, {3,2,2}, + {4,2,2}, {6,2,2}, {2,2,2}, {1,2,2}, + {5,2,2}, {7,2,2}, {3,0,12}, {4,0,12}, + {6,2,2}, {0,3,2}, {3,1,12}, {4,1,12}, + /* hat #3 in metatile #2 (type H) */ + {7,2,2}, {1,3,2}, {3,1,2}, {4,1,2}, + {0,3,2}, {4,2,2}, {2,3,2}, {5,3,2}, + {3,3,2}, {4,1,2}, {5,3,2}, {1,3,2}, + {7,1,2}, {2,3,2}, {6,0,2}, {4,3,2}, + {5,3,2}, {1,0,2}, {3,3,2}, {6,0,2}, + {6,3,2}, {4,3,2}, {1,3,2}, {2,3,2}, + {7,3,2}, {5,3,2}, {3,2,2}, {4,2,2}, + {0,0,2}, {6,3,2}, {3,1,5}, {4,1,5}, + /* hat #0 in metatile #3 (type T) */ + {1,0,3}, {4,0,2}, {7,0,0}, {7,1,0}, + {7,0,2}, {0,0,3}, {5,0,3}, {2,0,3}, + {7,0,0}, {3,0,3}, {1,0,3}, {5,0,3}, + {2,0,3}, {4,0,0}, {4,0,3}, {7,2,1}, + {3,1,1}, {5,0,3}, {7,2,1}, {3,0,3}, + {4,0,3}, {6,0,3}, {2,0,3}, {1,0,3}, + {5,0,3}, {7,0,3}, {7,0,2}, {7,1,2}, + {6,0,3}, {2,1,1}, {6,1,2}, {0,1,1}, + /* hat #1 in metatile #3 (type T) does not exist */ + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + /* hat #2 in metatile #3 (type T) does not exist */ + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + /* hat #3 in metatile #3 (type T) does not exist */ + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + /* hat #0 in metatile #4 (type P) */ + {1,0,4}, {-1,-1,-1}, {0,2,1}, {7,1,9}, + {-1,-1,-1}, {0,0,4}, {5,0,4}, {2,0,4}, + {0,2,1}, {3,0,4}, {1,0,4}, {5,0,4}, + {2,0,4}, {2,0,0}, {4,0,4}, {0,0,0}, + {3,1,4}, {5,0,4}, {0,0,0}, {3,0,4}, + {4,0,4}, {6,0,4}, {2,0,4}, {1,0,4}, + {5,0,4}, {7,0,4}, {-1,-1,-1}, {-1,-1,-1}, + {6,0,4}, {2,1,4}, {-1,-1,-1}, {0,1,4}, + /* hat #1 in metatile #4 (type P) */ + {1,1,4}, {-1,-1,-1}, {7,0,4}, {-1,-1,-1}, + {0,1,7}, {0,1,4}, {5,1,4}, {2,1,4}, + {7,0,4}, {3,1,4}, {1,1,4}, {5,1,4}, + {2,1,4}, {4,0,4}, {4,1,4}, {7,3,0}, + {3,2,0}, {5,1,4}, {7,3,0}, {3,1,4}, + {4,1,4}, {6,1,4}, {2,1,4}, {1,1,4}, + {5,1,4}, {7,1,4}, {0,1,7}, {7,0,7}, + {6,1,4}, {2,2,0}, {6,0,7}, {0,2,0}, + /* hat #2 in metatile #4 (type P) does not exist */ + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + /* hat #3 in metatile #4 (type P) does not exist */ + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + /* hat #0 in metatile #5 (type P) */ + {1,0,5}, {-1,-1,-1}, {0,1,0}, {7,1,8}, + {-1,-1,-1}, {0,0,5}, {5,0,5}, {2,0,5}, + {0,1,0}, {3,0,5}, {1,0,5}, {5,0,5}, + {2,0,5}, {2,0,2}, {4,0,5}, {0,0,2}, + {3,1,5}, {5,0,5}, {0,0,2}, {3,0,5}, + {4,0,5}, {6,0,5}, {2,0,5}, {1,0,5}, + {5,0,5}, {7,0,5}, {-1,-1,-1}, {-1,-1,-1}, + {6,0,5}, {2,1,5}, {-1,-1,-1}, {0,1,5}, + /* hat #1 in metatile #5 (type P) */ + {1,1,5}, {-1,-1,-1}, {7,0,5}, {-1,-1,-1}, + {0,1,11}, {0,1,5}, {5,1,5}, {2,1,5}, + {7,0,5}, {3,1,5}, {1,1,5}, {5,1,5}, + {2,1,5}, {4,0,5}, {4,1,5}, {7,3,2}, + {3,2,2}, {5,1,5}, {7,3,2}, {3,1,5}, + {4,1,5}, {6,1,5}, {2,1,5}, {1,1,5}, + {5,1,5}, {7,1,5}, {0,1,11}, {7,0,11}, + {6,1,5}, {2,2,2}, {6,0,11}, {0,2,2}, + /* hat #2 in metatile #5 (type P) does not exist */ + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + /* hat #3 in metatile #5 (type P) does not exist */ + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + /* hat #0 in metatile #6 (type P) */ + {1,0,6}, {4,0,1}, {0,1,10}, {7,0,10}, + {7,0,1}, {0,0,6}, {5,0,6}, {2,0,6}, + {0,1,10}, {3,0,6}, {1,0,6}, {5,0,6}, + {2,0,6}, {-1,-1,-1}, {4,0,6}, {-1,-1,-1}, + {3,1,6}, {5,0,6}, {-1,-1,-1}, {3,0,6}, + {4,0,6}, {6,0,6}, {2,0,6}, {1,0,6}, + {5,0,6}, {7,0,6}, {7,0,1}, {7,1,1}, + {6,0,6}, {2,1,6}, {6,1,1}, {0,1,6}, + /* hat #1 in metatile #6 (type P) */ + {1,1,6}, {1,1,1}, {7,0,6}, {6,1,1}, + {0,1,2}, {0,1,6}, {5,1,6}, {2,1,6}, + {7,0,6}, {3,1,6}, {1,1,6}, {5,1,6}, + {2,1,6}, {4,0,6}, {4,1,6}, {-1,-1,-1}, + {-1,-1,-1}, {5,1,6}, {-1,-1,-1}, {3,1,6}, + {4,1,6}, {6,1,6}, {2,1,6}, {1,1,6}, + {5,1,6}, {7,1,6}, {0,1,2}, {7,1,12}, + {6,1,6}, {-1,-1,-1}, {6,1,12}, {-1,-1,-1}, + /* hat #2 in metatile #6 (type P) does not exist */ + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + /* hat #3 in metatile #6 (type P) does not exist */ + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + /* hat #0 in metatile #7 (type F) */ + {1,0,7}, {2,0,8}, {-1,-1,-1}, {0,0,8}, + {0,2,0}, {0,0,7}, {5,0,7}, {2,0,7}, + {-1,-1,-1}, {3,0,7}, {1,0,7}, {5,0,7}, + {2,0,7}, {-1,-1,-1}, {4,0,7}, {-1,-1,-1}, + {3,1,7}, {5,0,7}, {-1,-1,-1}, {3,0,7}, + {4,0,7}, {6,0,7}, {2,0,7}, {1,0,7}, + {5,0,7}, {7,0,7}, {0,2,0}, {7,1,4}, + {6,0,7}, {2,1,7}, {6,1,4}, {0,1,7}, + /* hat #1 in metatile #7 (type F) */ + {1,1,7}, {1,1,4}, {7,0,7}, {6,1,4}, + {-1,-1,-1}, {0,1,7}, {5,1,7}, {2,1,7}, + {7,0,7}, {3,1,7}, {1,1,7}, {5,1,7}, + {2,1,7}, {4,0,7}, {4,1,7}, {-1,-1,-1}, + {-1,-1,-1}, {5,1,7}, {-1,-1,-1}, {3,1,7}, + {4,1,7}, {6,1,7}, {2,1,7}, {1,1,7}, + {5,1,7}, {7,1,7}, {-1,-1,-1}, {-1,-1,-1}, + {6,1,7}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + /* hat #2 in metatile #7 (type F) does not exist */ + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + /* hat #3 in metatile #7 (type F) does not exist */ + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + /* hat #0 in metatile #8 (type F) */ + {1,0,8}, {-1,-1,-1}, {0,0,7}, {-1,-1,-1}, + {-1,-1,-1}, {0,0,8}, {5,0,8}, {2,0,8}, + {0,0,7}, {3,0,8}, {1,0,8}, {5,0,8}, + {2,0,8}, {1,2,0}, {4,0,8}, {6,2,0}, + {3,1,8}, {5,0,8}, {6,2,0}, {3,0,8}, + {4,0,8}, {6,0,8}, {2,0,8}, {1,0,8}, + {5,0,8}, {7,0,8}, {-1,-1,-1}, {-1,-1,-1}, + {6,0,8}, {2,1,8}, {-1,-1,-1}, {0,1,8}, + /* hat #1 in metatile #8 (type F) */ + {1,1,8}, {-1,-1,-1}, {7,0,8}, {-1,-1,-1}, + {-1,-1,-1}, {0,1,8}, {5,1,8}, {2,1,8}, + {7,0,8}, {3,1,8}, {1,1,8}, {5,1,8}, + {2,1,8}, {4,0,8}, {4,1,8}, {7,2,0}, + {3,1,0}, {5,1,8}, {7,2,0}, {3,1,8}, + {4,1,8}, {6,1,8}, {2,1,8}, {1,1,8}, + {5,1,8}, {7,1,8}, {-1,-1,-1}, {-1,-1,-1}, + {6,1,8}, {2,1,0}, {0,0,5}, {0,1,0}, + /* hat #2 in metatile #8 (type F) does not exist */ + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + /* hat #3 in metatile #8 (type F) does not exist */ + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + /* hat #0 in metatile #9 (type F) */ + {1,0,9}, {-1,-1,-1}, {0,0,10}, {-1,-1,-1}, + {-1,-1,-1}, {0,0,9}, {5,0,9}, {2,0,9}, + {0,0,10}, {3,0,9}, {1,0,9}, {5,0,9}, + {2,0,9}, {2,0,1}, {4,0,9}, {0,0,1}, + {3,1,9}, {5,0,9}, {0,0,1}, {3,0,9}, + {4,0,9}, {6,0,9}, {2,0,9}, {1,0,9}, + {5,0,9}, {7,0,9}, {-1,-1,-1}, {-1,-1,-1}, + {6,0,9}, {2,1,9}, {-1,-1,-1}, {0,1,9}, + /* hat #1 in metatile #9 (type F) */ + {1,1,9}, {-1,-1,-1}, {7,0,9}, {-1,-1,-1}, + {-1,-1,-1}, {0,1,9}, {5,1,9}, {2,1,9}, + {7,0,9}, {3,1,9}, {1,1,9}, {5,1,9}, + {2,1,9}, {4,0,9}, {4,1,9}, {7,3,1}, + {3,2,1}, {5,1,9}, {7,3,1}, {3,1,9}, + {4,1,9}, {6,1,9}, {2,1,9}, {1,1,9}, + {5,1,9}, {7,1,9}, {-1,-1,-1}, {-1,-1,-1}, + {6,1,9}, {2,2,1}, {0,0,4}, {0,2,1}, + /* hat #2 in metatile #9 (type F) does not exist */ + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + /* hat #3 in metatile #9 (type F) does not exist */ + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + /* hat #0 in metatile #10 (type F) */ + {1,0,10}, {2,0,9}, {-1,-1,-1}, {0,0,9}, + {3,0,1}, {0,0,10}, {5,0,10}, {2,0,10}, + {-1,-1,-1}, {3,0,10}, {1,0,10}, {5,0,10}, + {2,0,10}, {-1,-1,-1}, {4,0,10}, {-1,-1,-1}, + {3,1,10}, {5,0,10}, {-1,-1,-1}, {3,0,10}, + {4,0,10}, {6,0,10}, {2,0,10}, {1,0,10}, + {5,0,10}, {7,0,10}, {3,0,1}, {4,0,1}, + {6,0,10}, {2,1,10}, {0,0,6}, {0,1,10}, + /* hat #1 in metatile #10 (type F) */ + {1,1,10}, {2,0,6}, {7,0,10}, {0,0,6}, + {-1,-1,-1}, {0,1,10}, {5,1,10}, {2,1,10}, + {7,0,10}, {3,1,10}, {1,1,10}, {5,1,10}, + {2,1,10}, {4,0,10}, {4,1,10}, {-1,-1,-1}, + {-1,-1,-1}, {5,1,10}, {-1,-1,-1}, {3,1,10}, + {4,1,10}, {6,1,10}, {2,1,10}, {1,1,10}, + {5,1,10}, {7,1,10}, {-1,-1,-1}, {-1,-1,-1}, + {6,1,10}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + /* hat #2 in metatile #10 (type F) does not exist */ + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + /* hat #3 in metatile #10 (type F) does not exist */ + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + /* hat #0 in metatile #11 (type F) */ + {1,0,11}, {2,0,12}, {-1,-1,-1}, {0,0,12}, + {0,2,2}, {0,0,11}, {5,0,11}, {2,0,11}, + {-1,-1,-1}, {3,0,11}, {1,0,11}, {5,0,11}, + {2,0,11}, {-1,-1,-1}, {4,0,11}, {-1,-1,-1}, + {3,1,11}, {5,0,11}, {-1,-1,-1}, {3,0,11}, + {4,0,11}, {6,0,11}, {2,0,11}, {1,0,11}, + {5,0,11}, {7,0,11}, {0,2,2}, {7,1,5}, + {6,0,11}, {2,1,11}, {6,1,5}, {0,1,11}, + /* hat #1 in metatile #11 (type F) */ + {1,1,11}, {1,1,5}, {7,0,11}, {6,1,5}, + {-1,-1,-1}, {0,1,11}, {5,1,11}, {2,1,11}, + {7,0,11}, {3,1,11}, {1,1,11}, {5,1,11}, + {2,1,11}, {4,0,11}, {4,1,11}, {-1,-1,-1}, + {-1,-1,-1}, {5,1,11}, {-1,-1,-1}, {3,1,11}, + {4,1,11}, {6,1,11}, {2,1,11}, {1,1,11}, + {5,1,11}, {7,1,11}, {-1,-1,-1}, {-1,-1,-1}, + {6,1,11}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + /* hat #2 in metatile #11 (type F) does not exist */ + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + /* hat #3 in metatile #11 (type F) does not exist */ + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + /* hat #0 in metatile #12 (type F) */ + {1,0,12}, {-1,-1,-1}, {0,0,11}, {-1,-1,-1}, + {-1,-1,-1}, {0,0,12}, {5,0,12}, {2,0,12}, + {0,0,11}, {3,0,12}, {1,0,12}, {5,0,12}, + {2,0,12}, {1,2,2}, {4,0,12}, {6,2,2}, + {3,1,12}, {5,0,12}, {6,2,2}, {3,0,12}, + {4,0,12}, {6,0,12}, {2,0,12}, {1,0,12}, + {5,0,12}, {7,0,12}, {-1,-1,-1}, {-1,-1,-1}, + {6,0,12}, {2,1,12}, {-1,-1,-1}, {0,1,12}, + /* hat #1 in metatile #12 (type F) */ + {1,1,12}, {-1,-1,-1}, {7,0,12}, {-1,-1,-1}, + {-1,-1,-1}, {0,1,12}, {5,1,12}, {2,1,12}, + {7,0,12}, {3,1,12}, {1,1,12}, {5,1,12}, + {2,1,12}, {4,0,12}, {4,1,12}, {7,2,2}, + {3,1,2}, {5,1,12}, {7,2,2}, {3,1,12}, + {4,1,12}, {6,1,12}, {2,1,12}, {1,1,12}, + {5,1,12}, {7,1,12}, {-1,-1,-1}, {7,1,6}, + {6,1,12}, {2,1,2}, {6,1,6}, {0,1,2}, + /* hat #2 in metatile #12 (type F) does not exist */ + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + /* hat #3 in metatile #12 (type F) does not exist */ + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, +}; +static const KitemapEntry kitemap_T[] = { + /* hat #0 in metatile #0 (type H) */ + {1,0,0}, {7,3,0}, {3,0,3}, {4,0,3}, + {4,3,0}, {0,0,0}, {5,0,0}, {2,0,0}, + {3,0,3}, {3,0,0}, {1,0,0}, {5,0,0}, + {2,0,0}, {1,1,6}, {4,0,0}, {6,1,6}, + {0,0,2}, {5,0,0}, {6,1,6}, {3,0,0}, + {4,0,0}, {6,0,0}, {2,0,0}, {1,0,0}, + {5,0,0}, {7,0,0}, {4,3,0}, {3,3,0}, + {6,0,0}, {1,0,2}, {7,1,0}, {6,0,2}, + /* hat #1 in metatile #0 (type H) */ + {1,1,0}, {1,1,4}, {7,1,1}, {6,1,4}, + {0,1,2}, {0,1,0}, {5,1,0}, {2,1,0}, + {7,1,1}, {3,1,0}, {1,1,0}, {5,1,0}, + {2,1,0}, {4,1,1}, {4,1,0}, {0,3,0}, + {2,3,0}, {5,1,0}, {0,3,0}, {3,1,0}, + {4,1,0}, {6,1,0}, {2,1,0}, {1,1,0}, + {5,1,0}, {7,1,0}, {0,1,2}, {7,0,2}, + {6,1,0}, {3,3,0}, {6,0,2}, {7,0,0}, + /* hat #2 in metatile #0 (type H) */ + {1,2,0}, {1,1,5}, {7,1,3}, {6,1,5}, + {3,0,1}, {0,2,0}, {5,2,0}, {2,2,0}, + {7,1,3}, {3,2,0}, {1,2,0}, {5,2,0}, + {2,2,0}, {4,1,3}, {4,2,0}, {6,3,0}, + {1,3,0}, {5,2,0}, {6,3,0}, {3,2,0}, + {4,2,0}, {6,2,0}, {2,2,0}, {1,2,0}, + {5,2,0}, {7,2,0}, {3,0,1}, {4,0,1}, + {6,2,0}, {0,3,0}, {3,1,1}, {4,1,1}, + /* hat #3 in metatile #0 (type H) */ + {7,2,0}, {1,3,0}, {3,1,0}, {4,1,0}, + {0,3,0}, {4,2,0}, {2,3,0}, {5,3,0}, + {3,3,0}, {4,1,0}, {5,3,0}, {1,3,0}, + {7,1,0}, {2,3,0}, {6,0,0}, {4,3,0}, + {5,3,0}, {1,0,0}, {3,3,0}, {6,0,0}, + {6,3,0}, {4,3,0}, {1,3,0}, {2,3,0}, + {7,3,0}, {5,3,0}, {3,2,0}, {4,2,0}, + {0,0,0}, {6,3,0}, {3,1,3}, {4,1,3}, + /* hat #0 in metatile #1 (type P) */ + {1,0,1}, {-1,-1,-1}, {0,1,5}, {7,0,5}, + {-1,-1,-1}, {0,0,1}, {5,0,1}, {2,0,1}, + {0,1,5}, {3,0,1}, {1,0,1}, {5,0,1}, + {2,0,1}, {1,2,0}, {4,0,1}, {6,2,0}, + {3,1,1}, {5,0,1}, {6,2,0}, {3,0,1}, + {4,0,1}, {6,0,1}, {2,0,1}, {1,0,1}, + {5,0,1}, {7,0,1}, {-1,-1,-1}, {-1,-1,-1}, + {6,0,1}, {2,1,1}, {-1,-1,-1}, {0,1,1}, + /* hat #1 in metatile #1 (type P) */ + {1,1,1}, {-1,-1,-1}, {7,0,1}, {-1,-1,-1}, + {-1,-1,-1}, {0,1,1}, {5,1,1}, {2,1,1}, + {7,0,1}, {3,1,1}, {1,1,1}, {5,1,1}, + {2,1,1}, {4,0,1}, {4,1,1}, {7,2,0}, + {3,1,0}, {5,1,1}, {7,2,0}, {3,1,1}, + {4,1,1}, {6,1,1}, {2,1,1}, {1,1,1}, + {5,1,1}, {7,1,1}, {-1,-1,-1}, {7,1,4}, + {6,1,1}, {2,1,0}, {6,1,4}, {0,1,0}, + /* hat #2 in metatile #1 (type P) does not exist */ + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + /* hat #3 in metatile #1 (type P) does not exist */ + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + /* hat #0 in metatile #2 (type P) */ + {1,0,2}, {4,0,0}, {-1,-1,-1}, {7,1,6}, + {7,0,0}, {0,0,2}, {5,0,2}, {2,0,2}, + {-1,-1,-1}, {3,0,2}, {1,0,2}, {5,0,2}, + {2,0,2}, {-1,-1,-1}, {4,0,2}, {-1,-1,-1}, + {3,1,2}, {5,0,2}, {-1,-1,-1}, {3,0,2}, + {4,0,2}, {6,0,2}, {2,0,2}, {1,0,2}, + {5,0,2}, {7,0,2}, {7,0,0}, {7,1,0}, + {6,0,2}, {2,1,2}, {6,1,0}, {0,1,2}, + /* hat #1 in metatile #2 (type P) */ + {1,1,2}, {1,1,0}, {7,0,2}, {6,1,0}, + {0,1,4}, {0,1,2}, {5,1,2}, {2,1,2}, + {7,0,2}, {3,1,2}, {1,1,2}, {5,1,2}, + {2,1,2}, {4,0,2}, {4,1,2}, {-1,-1,-1}, + {-1,-1,-1}, {5,1,2}, {-1,-1,-1}, {3,1,2}, + {4,1,2}, {6,1,2}, {2,1,2}, {1,1,2}, + {5,1,2}, {7,1,2}, {0,1,4}, {7,0,4}, + {6,1,2}, {-1,-1,-1}, {6,0,4}, {-1,-1,-1}, + /* hat #2 in metatile #2 (type P) does not exist */ + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + /* hat #3 in metatile #2 (type P) does not exist */ + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + /* hat #0 in metatile #3 (type P) */ + {1,0,3}, {-1,-1,-1}, {0,1,6}, {7,0,6}, + {-1,-1,-1}, {0,0,3}, {5,0,3}, {2,0,3}, + {0,1,6}, {3,0,3}, {1,0,3}, {5,0,3}, + {2,0,3}, {2,0,0}, {4,0,3}, {0,0,0}, + {3,1,3}, {5,0,3}, {0,0,0}, {3,0,3}, + {4,0,3}, {6,0,3}, {2,0,3}, {1,0,3}, + {5,0,3}, {7,0,3}, {-1,-1,-1}, {-1,-1,-1}, + {6,0,3}, {2,1,3}, {-1,-1,-1}, {0,1,3}, + /* hat #1 in metatile #3 (type P) */ + {1,1,3}, {-1,-1,-1}, {7,0,3}, {-1,-1,-1}, + {-1,-1,-1}, {0,1,3}, {5,1,3}, {2,1,3}, + {7,0,3}, {3,1,3}, {1,1,3}, {5,1,3}, + {2,1,3}, {4,0,3}, {4,1,3}, {7,3,0}, + {3,2,0}, {5,1,3}, {7,3,0}, {3,1,3}, + {4,1,3}, {6,1,3}, {2,1,3}, {1,1,3}, + {5,1,3}, {7,1,3}, {-1,-1,-1}, {7,1,5}, + {6,1,3}, {2,2,0}, {6,1,5}, {0,2,0}, + /* hat #2 in metatile #3 (type P) does not exist */ + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + /* hat #3 in metatile #3 (type P) does not exist */ + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + /* hat #0 in metatile #4 (type F) */ + {1,0,4}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {0,0,4}, {5,0,4}, {2,0,4}, + {-1,-1,-1}, {3,0,4}, {1,0,4}, {5,0,4}, + {2,0,4}, {-1,-1,-1}, {4,0,4}, {-1,-1,-1}, + {3,1,4}, {5,0,4}, {-1,-1,-1}, {3,0,4}, + {4,0,4}, {6,0,4}, {2,0,4}, {1,0,4}, + {5,0,4}, {7,0,4}, {-1,-1,-1}, {7,1,2}, + {6,0,4}, {2,1,4}, {6,1,2}, {0,1,4}, + /* hat #1 in metatile #4 (type F) */ + {1,1,4}, {1,1,2}, {7,0,4}, {6,1,2}, + {0,1,0}, {0,1,4}, {5,1,4}, {2,1,4}, + {7,0,4}, {3,1,4}, {1,1,4}, {5,1,4}, + {2,1,4}, {4,0,4}, {4,1,4}, {-1,-1,-1}, + {-1,-1,-1}, {5,1,4}, {-1,-1,-1}, {3,1,4}, + {4,1,4}, {6,1,4}, {2,1,4}, {1,1,4}, + {5,1,4}, {7,1,4}, {0,1,0}, {7,1,1}, + {6,1,4}, {-1,-1,-1}, {6,1,1}, {-1,-1,-1}, + /* hat #2 in metatile #4 (type F) does not exist */ + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + /* hat #3 in metatile #4 (type F) does not exist */ + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + /* hat #0 in metatile #5 (type F) */ + {1,0,5}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {0,0,5}, {5,0,5}, {2,0,5}, + {-1,-1,-1}, {3,0,5}, {1,0,5}, {5,0,5}, + {2,0,5}, {-1,-1,-1}, {4,0,5}, {-1,-1,-1}, + {3,1,5}, {5,0,5}, {-1,-1,-1}, {3,0,5}, + {4,0,5}, {6,0,5}, {2,0,5}, {1,0,5}, + {5,0,5}, {7,0,5}, {-1,-1,-1}, {-1,-1,-1}, + {6,0,5}, {2,1,5}, {0,0,1}, {0,1,5}, + /* hat #1 in metatile #5 (type F) */ + {1,1,5}, {2,0,1}, {7,0,5}, {0,0,1}, + {0,2,0}, {0,1,5}, {5,1,5}, {2,1,5}, + {7,0,5}, {3,1,5}, {1,1,5}, {5,1,5}, + {2,1,5}, {4,0,5}, {4,1,5}, {-1,-1,-1}, + {-1,-1,-1}, {5,1,5}, {-1,-1,-1}, {3,1,5}, + {4,1,5}, {6,1,5}, {2,1,5}, {1,1,5}, + {5,1,5}, {7,1,5}, {0,2,0}, {7,1,3}, + {6,1,5}, {-1,-1,-1}, {6,1,3}, {-1,-1,-1}, + /* hat #2 in metatile #5 (type F) does not exist */ + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + /* hat #3 in metatile #5 (type F) does not exist */ + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + /* hat #0 in metatile #6 (type F) */ + {1,0,6}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {0,0,6}, {5,0,6}, {2,0,6}, + {-1,-1,-1}, {3,0,6}, {1,0,6}, {5,0,6}, + {2,0,6}, {-1,-1,-1}, {4,0,6}, {-1,-1,-1}, + {3,1,6}, {5,0,6}, {-1,-1,-1}, {3,0,6}, + {4,0,6}, {6,0,6}, {2,0,6}, {1,0,6}, + {5,0,6}, {7,0,6}, {-1,-1,-1}, {-1,-1,-1}, + {6,0,6}, {2,1,6}, {0,0,3}, {0,1,6}, + /* hat #1 in metatile #6 (type F) */ + {1,1,6}, {2,0,3}, {7,0,6}, {0,0,3}, + {3,0,0}, {0,1,6}, {5,1,6}, {2,1,6}, + {7,0,6}, {3,1,6}, {1,1,6}, {5,1,6}, + {2,1,6}, {4,0,6}, {4,1,6}, {-1,-1,-1}, + {-1,-1,-1}, {5,1,6}, {-1,-1,-1}, {3,1,6}, + {4,1,6}, {6,1,6}, {2,1,6}, {1,1,6}, + {5,1,6}, {7,1,6}, {3,0,0}, {4,0,0}, + {6,1,6}, {-1,-1,-1}, {0,0,2}, {-1,-1,-1}, + /* hat #2 in metatile #6 (type F) does not exist */ + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + /* hat #3 in metatile #6 (type F) does not exist */ + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, +}; +static const KitemapEntry kitemap_P[] = { + /* hat #0 in metatile #0 (type H) */ + {1,0,0}, {7,3,0}, {3,0,4}, {4,0,4}, + {4,3,0}, {0,0,0}, {5,0,0}, {2,0,0}, + {3,0,4}, {3,0,0}, {1,0,0}, {5,0,0}, + {2,0,0}, {1,1,9}, {4,0,0}, {6,1,9}, + {0,0,3}, {5,0,0}, {6,1,9}, {3,0,0}, + {4,0,0}, {6,0,0}, {2,0,0}, {1,0,0}, + {5,0,0}, {7,0,0}, {4,3,0}, {3,3,0}, + {6,0,0}, {1,0,3}, {7,1,0}, {6,0,3}, + /* hat #1 in metatile #0 (type H) */ + {1,1,0}, {1,1,8}, {7,1,5}, {6,1,8}, + {0,1,3}, {0,1,0}, {5,1,0}, {2,1,0}, + {7,1,5}, {3,1,0}, {1,1,0}, {5,1,0}, + {2,1,0}, {4,1,5}, {4,1,0}, {0,3,0}, + {2,3,0}, {5,1,0}, {0,3,0}, {3,1,0}, + {4,1,0}, {6,1,0}, {2,1,0}, {1,1,0}, + {5,1,0}, {7,1,0}, {0,1,3}, {7,0,3}, + {6,1,0}, {3,3,0}, {6,0,3}, {7,0,0}, + /* hat #2 in metatile #0 (type H) */ + {1,2,0}, {1,0,6}, {7,1,4}, {6,0,6}, + {3,0,5}, {0,2,0}, {5,2,0}, {2,2,0}, + {7,1,4}, {3,2,0}, {1,2,0}, {5,2,0}, + {2,2,0}, {4,1,4}, {4,2,0}, {6,3,0}, + {1,3,0}, {5,2,0}, {6,3,0}, {3,2,0}, + {4,2,0}, {6,2,0}, {2,2,0}, {1,2,0}, + {5,2,0}, {7,2,0}, {3,0,5}, {4,0,5}, + {6,2,0}, {0,3,0}, {3,1,5}, {4,1,5}, + /* hat #3 in metatile #0 (type H) */ + {7,2,0}, {1,3,0}, {3,1,0}, {4,1,0}, + {0,3,0}, {4,2,0}, {2,3,0}, {5,3,0}, + {3,3,0}, {4,1,0}, {5,3,0}, {1,3,0}, + {7,1,0}, {2,3,0}, {6,0,0}, {4,3,0}, + {5,3,0}, {1,0,0}, {3,3,0}, {6,0,0}, + {6,3,0}, {4,3,0}, {1,3,0}, {2,3,0}, + {7,3,0}, {5,3,0}, {3,2,0}, {4,2,0}, + {0,0,0}, {6,3,0}, {3,1,4}, {4,1,4}, + /* hat #0 in metatile #1 (type H) */ + {1,0,1}, {7,3,1}, {3,0,10}, {4,0,10}, + {4,3,1}, {0,0,1}, {5,0,1}, {2,0,1}, + {3,0,10}, {3,0,1}, {1,0,1}, {5,0,1}, + {2,0,1}, {1,0,9}, {4,0,1}, {6,0,9}, + {0,0,4}, {5,0,1}, {6,0,9}, {3,0,1}, + {4,0,1}, {6,0,1}, {2,0,1}, {1,0,1}, + {5,0,1}, {7,0,1}, {4,3,1}, {3,3,1}, + {6,0,1}, {1,0,4}, {7,1,1}, {6,0,4}, + /* hat #1 in metatile #1 (type H) */ + {1,1,1}, {1,1,6}, {7,1,2}, {6,1,6}, + {0,1,4}, {0,1,1}, {5,1,1}, {2,1,1}, + {7,1,2}, {3,1,1}, {1,1,1}, {5,1,1}, + {2,1,1}, {4,1,2}, {4,1,1}, {0,3,1}, + {2,3,1}, {5,1,1}, {0,3,1}, {3,1,1}, + {4,1,1}, {6,1,1}, {2,1,1}, {1,1,1}, + {5,1,1}, {7,1,1}, {0,1,4}, {7,0,4}, + {6,1,1}, {3,3,1}, {6,0,4}, {7,0,1}, + /* hat #2 in metatile #1 (type H) */ + {1,2,1}, {1,1,7}, {7,1,10}, {6,1,7}, + {3,0,2}, {0,2,1}, {5,2,1}, {2,2,1}, + {7,1,10}, {3,2,1}, {1,2,1}, {5,2,1}, + {2,2,1}, {4,1,10}, {4,2,1}, {6,3,1}, + {1,3,1}, {5,2,1}, {6,3,1}, {3,2,1}, + {4,2,1}, {6,2,1}, {2,2,1}, {1,2,1}, + {5,2,1}, {7,2,1}, {3,0,2}, {4,0,2}, + {6,2,1}, {0,3,1}, {3,1,2}, {4,1,2}, + /* hat #3 in metatile #1 (type H) */ + {7,2,1}, {1,3,1}, {3,1,1}, {4,1,1}, + {0,3,1}, {4,2,1}, {2,3,1}, {5,3,1}, + {3,3,1}, {4,1,1}, {5,3,1}, {1,3,1}, + {7,1,1}, {2,3,1}, {6,0,1}, {4,3,1}, + {5,3,1}, {1,0,1}, {3,3,1}, {6,0,1}, + {6,3,1}, {4,3,1}, {1,3,1}, {2,3,1}, + {7,3,1}, {5,3,1}, {3,2,1}, {4,2,1}, + {0,0,1}, {6,3,1}, {3,1,10}, {4,1,10}, + /* hat #0 in metatile #2 (type P) */ + {1,0,2}, {-1,-1,-1}, {0,1,7}, {7,0,7}, + {-1,-1,-1}, {0,0,2}, {5,0,2}, {2,0,2}, + {0,1,7}, {3,0,2}, {1,0,2}, {5,0,2}, + {2,0,2}, {1,2,1}, {4,0,2}, {6,2,1}, + {3,1,2}, {5,0,2}, {6,2,1}, {3,0,2}, + {4,0,2}, {6,0,2}, {2,0,2}, {1,0,2}, + {5,0,2}, {7,0,2}, {-1,-1,-1}, {-1,-1,-1}, + {6,0,2}, {2,1,2}, {-1,-1,-1}, {0,1,2}, + /* hat #1 in metatile #2 (type P) */ + {1,1,2}, {-1,-1,-1}, {7,0,2}, {-1,-1,-1}, + {-1,-1,-1}, {0,1,2}, {5,1,2}, {2,1,2}, + {7,0,2}, {3,1,2}, {1,1,2}, {5,1,2}, + {2,1,2}, {4,0,2}, {4,1,2}, {7,2,1}, + {3,1,1}, {5,1,2}, {7,2,1}, {3,1,2}, + {4,1,2}, {6,1,2}, {2,1,2}, {1,1,2}, + {5,1,2}, {7,1,2}, {-1,-1,-1}, {7,1,6}, + {6,1,2}, {2,1,1}, {6,1,6}, {0,1,1}, + /* hat #2 in metatile #2 (type P) does not exist */ + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + /* hat #3 in metatile #2 (type P) does not exist */ + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + /* hat #0 in metatile #3 (type P) */ + {1,0,3}, {4,0,0}, {-1,-1,-1}, {7,1,9}, + {7,0,0}, {0,0,3}, {5,0,3}, {2,0,3}, + {-1,-1,-1}, {3,0,3}, {1,0,3}, {5,0,3}, + {2,0,3}, {-1,-1,-1}, {4,0,3}, {-1,-1,-1}, + {3,1,3}, {5,0,3}, {-1,-1,-1}, {3,0,3}, + {4,0,3}, {6,0,3}, {2,0,3}, {1,0,3}, + {5,0,3}, {7,0,3}, {7,0,0}, {7,1,0}, + {6,0,3}, {2,1,3}, {6,1,0}, {0,1,3}, + /* hat #1 in metatile #3 (type P) */ + {1,1,3}, {1,1,0}, {7,0,3}, {6,1,0}, + {0,1,8}, {0,1,3}, {5,1,3}, {2,1,3}, + {7,0,3}, {3,1,3}, {1,1,3}, {5,1,3}, + {2,1,3}, {4,0,3}, {4,1,3}, {-1,-1,-1}, + {-1,-1,-1}, {5,1,3}, {-1,-1,-1}, {3,1,3}, + {4,1,3}, {6,1,3}, {2,1,3}, {1,1,3}, + {5,1,3}, {7,1,3}, {0,1,8}, {7,0,8}, + {6,1,3}, {-1,-1,-1}, {6,0,8}, {-1,-1,-1}, + /* hat #2 in metatile #3 (type P) does not exist */ + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + /* hat #3 in metatile #3 (type P) does not exist */ + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + /* hat #0 in metatile #4 (type P) */ + {1,0,4}, {4,0,1}, {0,1,9}, {7,0,9}, + {7,0,1}, {0,0,4}, {5,0,4}, {2,0,4}, + {0,1,9}, {3,0,4}, {1,0,4}, {5,0,4}, + {2,0,4}, {2,0,0}, {4,0,4}, {0,0,0}, + {3,1,4}, {5,0,4}, {0,0,0}, {3,0,4}, + {4,0,4}, {6,0,4}, {2,0,4}, {1,0,4}, + {5,0,4}, {7,0,4}, {7,0,1}, {7,1,1}, + {6,0,4}, {2,1,4}, {6,1,1}, {0,1,4}, + /* hat #1 in metatile #4 (type P) */ + {1,1,4}, {1,1,1}, {7,0,4}, {6,1,1}, + {0,1,6}, {0,1,4}, {5,1,4}, {2,1,4}, + {7,0,4}, {3,1,4}, {1,1,4}, {5,1,4}, + {2,1,4}, {4,0,4}, {4,1,4}, {7,3,0}, + {3,2,0}, {5,1,4}, {7,3,0}, {3,1,4}, + {4,1,4}, {6,1,4}, {2,1,4}, {1,1,4}, + {5,1,4}, {7,1,4}, {0,1,6}, {7,0,6}, + {6,1,4}, {2,2,0}, {6,0,6}, {0,2,0}, + /* hat #2 in metatile #4 (type P) does not exist */ + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + /* hat #3 in metatile #4 (type P) does not exist */ + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + /* hat #0 in metatile #5 (type F) */ + {1,0,5}, {-1,-1,-1}, {0,0,6}, {-1,-1,-1}, + {-1,-1,-1}, {0,0,5}, {5,0,5}, {2,0,5}, + {0,0,6}, {3,0,5}, {1,0,5}, {5,0,5}, + {2,0,5}, {1,2,0}, {4,0,5}, {6,2,0}, + {3,1,5}, {5,0,5}, {6,2,0}, {3,0,5}, + {4,0,5}, {6,0,5}, {2,0,5}, {1,0,5}, + {5,0,5}, {7,0,5}, {-1,-1,-1}, {-1,-1,-1}, + {6,0,5}, {2,1,5}, {-1,-1,-1}, {0,1,5}, + /* hat #1 in metatile #5 (type F) */ + {1,1,5}, {-1,-1,-1}, {7,0,5}, {-1,-1,-1}, + {-1,-1,-1}, {0,1,5}, {5,1,5}, {2,1,5}, + {7,0,5}, {3,1,5}, {1,1,5}, {5,1,5}, + {2,1,5}, {4,0,5}, {4,1,5}, {7,2,0}, + {3,1,0}, {5,1,5}, {7,2,0}, {3,1,5}, + {4,1,5}, {6,1,5}, {2,1,5}, {1,1,5}, + {5,1,5}, {7,1,5}, {-1,-1,-1}, {7,1,8}, + {6,1,5}, {2,1,0}, {6,1,8}, {0,1,0}, + /* hat #2 in metatile #5 (type F) does not exist */ + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + /* hat #3 in metatile #5 (type F) does not exist */ + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + /* hat #0 in metatile #6 (type F) */ + {1,0,6}, {2,0,5}, {-1,-1,-1}, {0,0,5}, + {0,2,0}, {0,0,6}, {5,0,6}, {2,0,6}, + {-1,-1,-1}, {3,0,6}, {1,0,6}, {5,0,6}, + {2,0,6}, {-1,-1,-1}, {4,0,6}, {-1,-1,-1}, + {3,1,6}, {5,0,6}, {-1,-1,-1}, {3,0,6}, + {4,0,6}, {6,0,6}, {2,0,6}, {1,0,6}, + {5,0,6}, {7,0,6}, {0,2,0}, {7,1,4}, + {6,0,6}, {2,1,6}, {6,1,4}, {0,1,6}, + /* hat #1 in metatile #6 (type F) */ + {1,1,6}, {1,1,4}, {7,0,6}, {6,1,4}, + {0,1,1}, {0,1,6}, {5,1,6}, {2,1,6}, + {7,0,6}, {3,1,6}, {1,1,6}, {5,1,6}, + {2,1,6}, {4,0,6}, {4,1,6}, {-1,-1,-1}, + {-1,-1,-1}, {5,1,6}, {-1,-1,-1}, {3,1,6}, + {4,1,6}, {6,1,6}, {2,1,6}, {1,1,6}, + {5,1,6}, {7,1,6}, {0,1,1}, {7,1,2}, + {6,1,6}, {-1,-1,-1}, {6,1,2}, {-1,-1,-1}, + /* hat #2 in metatile #6 (type F) does not exist */ + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + /* hat #3 in metatile #6 (type F) does not exist */ + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + /* hat #0 in metatile #7 (type F) */ + {1,0,7}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {0,0,7}, {5,0,7}, {2,0,7}, + {-1,-1,-1}, {3,0,7}, {1,0,7}, {5,0,7}, + {2,0,7}, {-1,-1,-1}, {4,0,7}, {-1,-1,-1}, + {3,1,7}, {5,0,7}, {-1,-1,-1}, {3,0,7}, + {4,0,7}, {6,0,7}, {2,0,7}, {1,0,7}, + {5,0,7}, {7,0,7}, {-1,-1,-1}, {-1,-1,-1}, + {6,0,7}, {2,1,7}, {0,0,2}, {0,1,7}, + /* hat #1 in metatile #7 (type F) */ + {1,1,7}, {2,0,2}, {7,0,7}, {0,0,2}, + {0,2,1}, {0,1,7}, {5,1,7}, {2,1,7}, + {7,0,7}, {3,1,7}, {1,1,7}, {5,1,7}, + {2,1,7}, {4,0,7}, {4,1,7}, {-1,-1,-1}, + {-1,-1,-1}, {5,1,7}, {-1,-1,-1}, {3,1,7}, + {4,1,7}, {6,1,7}, {2,1,7}, {1,1,7}, + {5,1,7}, {7,1,7}, {0,2,1}, {7,1,10}, + {6,1,7}, {-1,-1,-1}, {6,1,10}, {-1,-1,-1}, + /* hat #2 in metatile #7 (type F) does not exist */ + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + /* hat #3 in metatile #7 (type F) does not exist */ + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + /* hat #0 in metatile #8 (type F) */ + {1,0,8}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {0,0,8}, {5,0,8}, {2,0,8}, + {-1,-1,-1}, {3,0,8}, {1,0,8}, {5,0,8}, + {2,0,8}, {-1,-1,-1}, {4,0,8}, {-1,-1,-1}, + {3,1,8}, {5,0,8}, {-1,-1,-1}, {3,0,8}, + {4,0,8}, {6,0,8}, {2,0,8}, {1,0,8}, + {5,0,8}, {7,0,8}, {-1,-1,-1}, {7,1,3}, + {6,0,8}, {2,1,8}, {6,1,3}, {0,1,8}, + /* hat #1 in metatile #8 (type F) */ + {1,1,8}, {1,1,3}, {7,0,8}, {6,1,3}, + {0,1,0}, {0,1,8}, {5,1,8}, {2,1,8}, + {7,0,8}, {3,1,8}, {1,1,8}, {5,1,8}, + {2,1,8}, {4,0,8}, {4,1,8}, {-1,-1,-1}, + {-1,-1,-1}, {5,1,8}, {-1,-1,-1}, {3,1,8}, + {4,1,8}, {6,1,8}, {2,1,8}, {1,1,8}, + {5,1,8}, {7,1,8}, {0,1,0}, {7,1,5}, + {6,1,8}, {-1,-1,-1}, {6,1,5}, {-1,-1,-1}, + /* hat #2 in metatile #8 (type F) does not exist */ + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + /* hat #3 in metatile #8 (type F) does not exist */ + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + /* hat #0 in metatile #9 (type F) */ + {1,0,9}, {2,0,10}, {-1,-1,-1}, {0,0,10}, + {3,0,1}, {0,0,9}, {5,0,9}, {2,0,9}, + {-1,-1,-1}, {3,0,9}, {1,0,9}, {5,0,9}, + {2,0,9}, {-1,-1,-1}, {4,0,9}, {-1,-1,-1}, + {3,1,9}, {5,0,9}, {-1,-1,-1}, {3,0,9}, + {4,0,9}, {6,0,9}, {2,0,9}, {1,0,9}, + {5,0,9}, {7,0,9}, {3,0,1}, {4,0,1}, + {6,0,9}, {2,1,9}, {0,0,4}, {0,1,9}, + /* hat #1 in metatile #9 (type F) */ + {1,1,9}, {2,0,4}, {7,0,9}, {0,0,4}, + {3,0,0}, {0,1,9}, {5,1,9}, {2,1,9}, + {7,0,9}, {3,1,9}, {1,1,9}, {5,1,9}, + {2,1,9}, {4,0,9}, {4,1,9}, {-1,-1,-1}, + {-1,-1,-1}, {5,1,9}, {-1,-1,-1}, {3,1,9}, + {4,1,9}, {6,1,9}, {2,1,9}, {1,1,9}, + {5,1,9}, {7,1,9}, {3,0,0}, {4,0,0}, + {6,1,9}, {-1,-1,-1}, {0,0,3}, {-1,-1,-1}, + /* hat #2 in metatile #9 (type F) does not exist */ + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + /* hat #3 in metatile #9 (type F) does not exist */ + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + /* hat #0 in metatile #10 (type F) */ + {1,0,10}, {-1,-1,-1}, {0,0,9}, {-1,-1,-1}, + {-1,-1,-1}, {0,0,10}, {5,0,10}, {2,0,10}, + {0,0,9}, {3,0,10}, {1,0,10}, {5,0,10}, + {2,0,10}, {2,0,1}, {4,0,10}, {0,0,1}, + {3,1,10}, {5,0,10}, {0,0,1}, {3,0,10}, + {4,0,10}, {6,0,10}, {2,0,10}, {1,0,10}, + {5,0,10}, {7,0,10}, {-1,-1,-1}, {-1,-1,-1}, + {6,0,10}, {2,1,10}, {-1,-1,-1}, {0,1,10}, + /* hat #1 in metatile #10 (type F) */ + {1,1,10}, {-1,-1,-1}, {7,0,10}, {-1,-1,-1}, + {-1,-1,-1}, {0,1,10}, {5,1,10}, {2,1,10}, + {7,0,10}, {3,1,10}, {1,1,10}, {5,1,10}, + {2,1,10}, {4,0,10}, {4,1,10}, {7,3,1}, + {3,2,1}, {5,1,10}, {7,3,1}, {3,1,10}, + {4,1,10}, {6,1,10}, {2,1,10}, {1,1,10}, + {5,1,10}, {7,1,10}, {-1,-1,-1}, {7,1,7}, + {6,1,10}, {2,2,1}, {6,1,7}, {0,2,1}, + /* hat #2 in metatile #10 (type F) does not exist */ + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + /* hat #3 in metatile #10 (type F) does not exist */ + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, +}; +static const KitemapEntry kitemap_F[] = { + /* hat #0 in metatile #0 (type H) */ + {1,0,0}, {7,3,0}, {3,0,3}, {4,0,3}, + {4,3,0}, {0,0,0}, {5,0,0}, {2,0,0}, + {3,0,3}, {3,0,0}, {1,0,0}, {5,0,0}, + {2,0,0}, {1,1,9}, {4,0,0}, {6,1,9}, + {0,0,2}, {5,0,0}, {6,1,9}, {3,0,0}, + {4,0,0}, {6,0,0}, {2,0,0}, {1,0,0}, + {5,0,0}, {7,0,0}, {4,3,0}, {3,3,0}, + {6,0,0}, {1,0,2}, {7,1,0}, {6,0,2}, + /* hat #1 in metatile #0 (type H) */ + {1,1,0}, {1,1,8}, {7,1,4}, {6,1,8}, + {0,1,2}, {0,1,0}, {5,1,0}, {2,1,0}, + {7,1,4}, {3,1,0}, {1,1,0}, {5,1,0}, + {2,1,0}, {4,1,4}, {4,1,0}, {0,3,0}, + {2,3,0}, {5,1,0}, {0,3,0}, {3,1,0}, + {4,1,0}, {6,1,0}, {2,1,0}, {1,1,0}, + {5,1,0}, {7,1,0}, {0,1,2}, {7,0,2}, + {6,1,0}, {3,3,0}, {6,0,2}, {7,0,0}, + /* hat #2 in metatile #0 (type H) */ + {1,2,0}, {1,0,5}, {7,1,3}, {6,0,5}, + {3,0,4}, {0,2,0}, {5,2,0}, {2,2,0}, + {7,1,3}, {3,2,0}, {1,2,0}, {5,2,0}, + {2,2,0}, {4,1,3}, {4,2,0}, {6,3,0}, + {1,3,0}, {5,2,0}, {6,3,0}, {3,2,0}, + {4,2,0}, {6,2,0}, {2,2,0}, {1,2,0}, + {5,2,0}, {7,2,0}, {3,0,4}, {4,0,4}, + {6,2,0}, {0,3,0}, {3,1,4}, {4,1,4}, + /* hat #3 in metatile #0 (type H) */ + {7,2,0}, {1,3,0}, {3,1,0}, {4,1,0}, + {0,3,0}, {4,2,0}, {2,3,0}, {5,3,0}, + {3,3,0}, {4,1,0}, {5,3,0}, {1,3,0}, + {7,1,0}, {2,3,0}, {6,0,0}, {4,3,0}, + {5,3,0}, {1,0,0}, {3,3,0}, {6,0,0}, + {6,3,0}, {4,3,0}, {1,3,0}, {2,3,0}, + {7,3,0}, {5,3,0}, {3,2,0}, {4,2,0}, + {0,0,0}, {6,3,0}, {3,1,3}, {4,1,3}, + /* hat #0 in metatile #1 (type H) */ + {1,0,1}, {7,3,1}, {3,0,10}, {4,0,10}, + {4,3,1}, {0,0,1}, {5,0,1}, {2,0,1}, + {3,0,10}, {3,0,1}, {1,0,1}, {5,0,1}, + {2,0,1}, {1,0,9}, {4,0,1}, {6,0,9}, + {0,0,3}, {5,0,1}, {6,0,9}, {3,0,1}, + {4,0,1}, {6,0,1}, {2,0,1}, {1,0,1}, + {5,0,1}, {7,0,1}, {4,3,1}, {3,3,1}, + {6,0,1}, {1,0,3}, {7,1,1}, {6,0,3}, + /* hat #1 in metatile #1 (type H) */ + {1,1,1}, {1,1,5}, {7,1,6}, {6,1,5}, + {0,1,3}, {0,1,1}, {5,1,1}, {2,1,1}, + {7,1,6}, {3,1,1}, {1,1,1}, {5,1,1}, + {2,1,1}, {4,1,6}, {4,1,1}, {0,3,1}, + {2,3,1}, {5,1,1}, {0,3,1}, {3,1,1}, + {4,1,1}, {6,1,1}, {2,1,1}, {1,1,1}, + {5,1,1}, {7,1,1}, {0,1,3}, {7,0,3}, + {6,1,1}, {3,3,1}, {6,0,3}, {7,0,1}, + /* hat #2 in metatile #1 (type H) */ + {1,2,1}, {1,0,7}, {7,1,10}, {6,0,7}, + {3,0,6}, {0,2,1}, {5,2,1}, {2,2,1}, + {7,1,10}, {3,2,1}, {1,2,1}, {5,2,1}, + {2,2,1}, {4,1,10}, {4,2,1}, {6,3,1}, + {1,3,1}, {5,2,1}, {6,3,1}, {3,2,1}, + {4,2,1}, {6,2,1}, {2,2,1}, {1,2,1}, + {5,2,1}, {7,2,1}, {3,0,6}, {4,0,6}, + {6,2,1}, {0,3,1}, {3,1,6}, {4,1,6}, + /* hat #3 in metatile #1 (type H) */ + {7,2,1}, {1,3,1}, {3,1,1}, {4,1,1}, + {0,3,1}, {4,2,1}, {2,3,1}, {5,3,1}, + {3,3,1}, {4,1,1}, {5,3,1}, {1,3,1}, + {7,1,1}, {2,3,1}, {6,0,1}, {4,3,1}, + {5,3,1}, {1,0,1}, {3,3,1}, {6,0,1}, + {6,3,1}, {4,3,1}, {1,3,1}, {2,3,1}, + {7,3,1}, {5,3,1}, {3,2,1}, {4,2,1}, + {0,0,1}, {6,3,1}, {3,1,10}, {4,1,10}, + /* hat #0 in metatile #2 (type P) */ + {1,0,2}, {4,0,0}, {-1,-1,-1}, {7,1,9}, + {7,0,0}, {0,0,2}, {5,0,2}, {2,0,2}, + {-1,-1,-1}, {3,0,2}, {1,0,2}, {5,0,2}, + {2,0,2}, {-1,-1,-1}, {4,0,2}, {-1,-1,-1}, + {3,1,2}, {5,0,2}, {-1,-1,-1}, {3,0,2}, + {4,0,2}, {6,0,2}, {2,0,2}, {1,0,2}, + {5,0,2}, {7,0,2}, {7,0,0}, {7,1,0}, + {6,0,2}, {2,1,2}, {6,1,0}, {0,1,2}, + /* hat #1 in metatile #2 (type P) */ + {1,1,2}, {1,1,0}, {7,0,2}, {6,1,0}, + {0,1,8}, {0,1,2}, {5,1,2}, {2,1,2}, + {7,0,2}, {3,1,2}, {1,1,2}, {5,1,2}, + {2,1,2}, {4,0,2}, {4,1,2}, {-1,-1,-1}, + {-1,-1,-1}, {5,1,2}, {-1,-1,-1}, {3,1,2}, + {4,1,2}, {6,1,2}, {2,1,2}, {1,1,2}, + {5,1,2}, {7,1,2}, {0,1,8}, {7,0,8}, + {6,1,2}, {-1,-1,-1}, {6,0,8}, {-1,-1,-1}, + /* hat #2 in metatile #2 (type P) does not exist */ + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + /* hat #3 in metatile #2 (type P) does not exist */ + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + /* hat #0 in metatile #3 (type P) */ + {1,0,3}, {4,0,1}, {0,1,9}, {7,0,9}, + {7,0,1}, {0,0,3}, {5,0,3}, {2,0,3}, + {0,1,9}, {3,0,3}, {1,0,3}, {5,0,3}, + {2,0,3}, {2,0,0}, {4,0,3}, {0,0,0}, + {3,1,3}, {5,0,3}, {0,0,0}, {3,0,3}, + {4,0,3}, {6,0,3}, {2,0,3}, {1,0,3}, + {5,0,3}, {7,0,3}, {7,0,1}, {7,1,1}, + {6,0,3}, {2,1,3}, {6,1,1}, {0,1,3}, + /* hat #1 in metatile #3 (type P) */ + {1,1,3}, {1,1,1}, {7,0,3}, {6,1,1}, + {0,1,5}, {0,1,3}, {5,1,3}, {2,1,3}, + {7,0,3}, {3,1,3}, {1,1,3}, {5,1,3}, + {2,1,3}, {4,0,3}, {4,1,3}, {7,3,0}, + {3,2,0}, {5,1,3}, {7,3,0}, {3,1,3}, + {4,1,3}, {6,1,3}, {2,1,3}, {1,1,3}, + {5,1,3}, {7,1,3}, {0,1,5}, {7,0,5}, + {6,1,3}, {2,2,0}, {6,0,5}, {0,2,0}, + /* hat #2 in metatile #3 (type P) does not exist */ + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + /* hat #3 in metatile #3 (type P) does not exist */ + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + /* hat #0 in metatile #4 (type F) */ + {1,0,4}, {-1,-1,-1}, {0,0,5}, {-1,-1,-1}, + {-1,-1,-1}, {0,0,4}, {5,0,4}, {2,0,4}, + {0,0,5}, {3,0,4}, {1,0,4}, {5,0,4}, + {2,0,4}, {1,2,0}, {4,0,4}, {6,2,0}, + {3,1,4}, {5,0,4}, {6,2,0}, {3,0,4}, + {4,0,4}, {6,0,4}, {2,0,4}, {1,0,4}, + {5,0,4}, {7,0,4}, {-1,-1,-1}, {-1,-1,-1}, + {6,0,4}, {2,1,4}, {-1,-1,-1}, {0,1,4}, + /* hat #1 in metatile #4 (type F) */ + {1,1,4}, {-1,-1,-1}, {7,0,4}, {-1,-1,-1}, + {-1,-1,-1}, {0,1,4}, {5,1,4}, {2,1,4}, + {7,0,4}, {3,1,4}, {1,1,4}, {5,1,4}, + {2,1,4}, {4,0,4}, {4,1,4}, {7,2,0}, + {3,1,0}, {5,1,4}, {7,2,0}, {3,1,4}, + {4,1,4}, {6,1,4}, {2,1,4}, {1,1,4}, + {5,1,4}, {7,1,4}, {-1,-1,-1}, {7,1,8}, + {6,1,4}, {2,1,0}, {6,1,8}, {0,1,0}, + /* hat #2 in metatile #4 (type F) does not exist */ + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + /* hat #3 in metatile #4 (type F) does not exist */ + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + /* hat #0 in metatile #5 (type F) */ + {1,0,5}, {2,0,4}, {-1,-1,-1}, {0,0,4}, + {0,2,0}, {0,0,5}, {5,0,5}, {2,0,5}, + {-1,-1,-1}, {3,0,5}, {1,0,5}, {5,0,5}, + {2,0,5}, {-1,-1,-1}, {4,0,5}, {-1,-1,-1}, + {3,1,5}, {5,0,5}, {-1,-1,-1}, {3,0,5}, + {4,0,5}, {6,0,5}, {2,0,5}, {1,0,5}, + {5,0,5}, {7,0,5}, {0,2,0}, {7,1,3}, + {6,0,5}, {2,1,5}, {6,1,3}, {0,1,5}, + /* hat #1 in metatile #5 (type F) */ + {1,1,5}, {1,1,3}, {7,0,5}, {6,1,3}, + {0,1,1}, {0,1,5}, {5,1,5}, {2,1,5}, + {7,0,5}, {3,1,5}, {1,1,5}, {5,1,5}, + {2,1,5}, {4,0,5}, {4,1,5}, {-1,-1,-1}, + {-1,-1,-1}, {5,1,5}, {-1,-1,-1}, {3,1,5}, + {4,1,5}, {6,1,5}, {2,1,5}, {1,1,5}, + {5,1,5}, {7,1,5}, {0,1,1}, {7,1,6}, + {6,1,5}, {-1,-1,-1}, {6,1,6}, {-1,-1,-1}, + /* hat #2 in metatile #5 (type F) does not exist */ + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + /* hat #3 in metatile #5 (type F) does not exist */ + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + /* hat #0 in metatile #6 (type F) */ + {1,0,6}, {-1,-1,-1}, {0,0,7}, {-1,-1,-1}, + {-1,-1,-1}, {0,0,6}, {5,0,6}, {2,0,6}, + {0,0,7}, {3,0,6}, {1,0,6}, {5,0,6}, + {2,0,6}, {1,2,1}, {4,0,6}, {6,2,1}, + {3,1,6}, {5,0,6}, {6,2,1}, {3,0,6}, + {4,0,6}, {6,0,6}, {2,0,6}, {1,0,6}, + {5,0,6}, {7,0,6}, {-1,-1,-1}, {-1,-1,-1}, + {6,0,6}, {2,1,6}, {-1,-1,-1}, {0,1,6}, + /* hat #1 in metatile #6 (type F) */ + {1,1,6}, {-1,-1,-1}, {7,0,6}, {-1,-1,-1}, + {-1,-1,-1}, {0,1,6}, {5,1,6}, {2,1,6}, + {7,0,6}, {3,1,6}, {1,1,6}, {5,1,6}, + {2,1,6}, {4,0,6}, {4,1,6}, {7,2,1}, + {3,1,1}, {5,1,6}, {7,2,1}, {3,1,6}, + {4,1,6}, {6,1,6}, {2,1,6}, {1,1,6}, + {5,1,6}, {7,1,6}, {-1,-1,-1}, {7,1,5}, + {6,1,6}, {2,1,1}, {6,1,5}, {0,1,1}, + /* hat #2 in metatile #6 (type F) does not exist */ + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + /* hat #3 in metatile #6 (type F) does not exist */ + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + /* hat #0 in metatile #7 (type F) */ + {1,0,7}, {2,0,6}, {-1,-1,-1}, {0,0,6}, + {0,2,1}, {0,0,7}, {5,0,7}, {2,0,7}, + {-1,-1,-1}, {3,0,7}, {1,0,7}, {5,0,7}, + {2,0,7}, {-1,-1,-1}, {4,0,7}, {-1,-1,-1}, + {3,1,7}, {5,0,7}, {-1,-1,-1}, {3,0,7}, + {4,0,7}, {6,0,7}, {2,0,7}, {1,0,7}, + {5,0,7}, {7,0,7}, {0,2,1}, {7,1,10}, + {6,0,7}, {2,1,7}, {6,1,10}, {0,1,7}, + /* hat #1 in metatile #7 (type F) */ + {1,1,7}, {1,1,10}, {7,0,7}, {6,1,10}, + {-1,-1,-1}, {0,1,7}, {5,1,7}, {2,1,7}, + {7,0,7}, {3,1,7}, {1,1,7}, {5,1,7}, + {2,1,7}, {4,0,7}, {4,1,7}, {-1,-1,-1}, + {-1,-1,-1}, {5,1,7}, {-1,-1,-1}, {3,1,7}, + {4,1,7}, {6,1,7}, {2,1,7}, {1,1,7}, + {5,1,7}, {7,1,7}, {-1,-1,-1}, {-1,-1,-1}, + {6,1,7}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + /* hat #2 in metatile #7 (type F) does not exist */ + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + /* hat #3 in metatile #7 (type F) does not exist */ + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + /* hat #0 in metatile #8 (type F) */ + {1,0,8}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {0,0,8}, {5,0,8}, {2,0,8}, + {-1,-1,-1}, {3,0,8}, {1,0,8}, {5,0,8}, + {2,0,8}, {-1,-1,-1}, {4,0,8}, {-1,-1,-1}, + {3,1,8}, {5,0,8}, {-1,-1,-1}, {3,0,8}, + {4,0,8}, {6,0,8}, {2,0,8}, {1,0,8}, + {5,0,8}, {7,0,8}, {-1,-1,-1}, {7,1,2}, + {6,0,8}, {2,1,8}, {6,1,2}, {0,1,8}, + /* hat #1 in metatile #8 (type F) */ + {1,1,8}, {1,1,2}, {7,0,8}, {6,1,2}, + {0,1,0}, {0,1,8}, {5,1,8}, {2,1,8}, + {7,0,8}, {3,1,8}, {1,1,8}, {5,1,8}, + {2,1,8}, {4,0,8}, {4,1,8}, {-1,-1,-1}, + {-1,-1,-1}, {5,1,8}, {-1,-1,-1}, {3,1,8}, + {4,1,8}, {6,1,8}, {2,1,8}, {1,1,8}, + {5,1,8}, {7,1,8}, {0,1,0}, {7,1,4}, + {6,1,8}, {-1,-1,-1}, {6,1,4}, {-1,-1,-1}, + /* hat #2 in metatile #8 (type F) does not exist */ + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + /* hat #3 in metatile #8 (type F) does not exist */ + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + /* hat #0 in metatile #9 (type F) */ + {1,0,9}, {2,0,10}, {-1,-1,-1}, {0,0,10}, + {3,0,1}, {0,0,9}, {5,0,9}, {2,0,9}, + {-1,-1,-1}, {3,0,9}, {1,0,9}, {5,0,9}, + {2,0,9}, {-1,-1,-1}, {4,0,9}, {-1,-1,-1}, + {3,1,9}, {5,0,9}, {-1,-1,-1}, {3,0,9}, + {4,0,9}, {6,0,9}, {2,0,9}, {1,0,9}, + {5,0,9}, {7,0,9}, {3,0,1}, {4,0,1}, + {6,0,9}, {2,1,9}, {0,0,3}, {0,1,9}, + /* hat #1 in metatile #9 (type F) */ + {1,1,9}, {2,0,3}, {7,0,9}, {0,0,3}, + {3,0,0}, {0,1,9}, {5,1,9}, {2,1,9}, + {7,0,9}, {3,1,9}, {1,1,9}, {5,1,9}, + {2,1,9}, {4,0,9}, {4,1,9}, {-1,-1,-1}, + {-1,-1,-1}, {5,1,9}, {-1,-1,-1}, {3,1,9}, + {4,1,9}, {6,1,9}, {2,1,9}, {1,1,9}, + {5,1,9}, {7,1,9}, {3,0,0}, {4,0,0}, + {6,1,9}, {-1,-1,-1}, {0,0,2}, {-1,-1,-1}, + /* hat #2 in metatile #9 (type F) does not exist */ + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + /* hat #3 in metatile #9 (type F) does not exist */ + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + /* hat #0 in metatile #10 (type F) */ + {1,0,10}, {-1,-1,-1}, {0,0,9}, {-1,-1,-1}, + {-1,-1,-1}, {0,0,10}, {5,0,10}, {2,0,10}, + {0,0,9}, {3,0,10}, {1,0,10}, {5,0,10}, + {2,0,10}, {2,0,1}, {4,0,10}, {0,0,1}, + {3,1,10}, {5,0,10}, {0,0,1}, {3,0,10}, + {4,0,10}, {6,0,10}, {2,0,10}, {1,0,10}, + {5,0,10}, {7,0,10}, {-1,-1,-1}, {-1,-1,-1}, + {6,0,10}, {2,1,10}, {-1,-1,-1}, {0,1,10}, + /* hat #1 in metatile #10 (type F) */ + {1,1,10}, {-1,-1,-1}, {7,0,10}, {-1,-1,-1}, + {0,1,7}, {0,1,10}, {5,1,10}, {2,1,10}, + {7,0,10}, {3,1,10}, {1,1,10}, {5,1,10}, + {2,1,10}, {4,0,10}, {4,1,10}, {7,3,1}, + {3,2,1}, {5,1,10}, {7,3,1}, {3,1,10}, + {4,1,10}, {6,1,10}, {2,1,10}, {1,1,10}, + {5,1,10}, {7,1,10}, {0,1,7}, {7,0,7}, + {6,1,10}, {2,2,1}, {6,0,7}, {0,2,1}, + /* hat #2 in metatile #10 (type F) does not exist */ + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + /* hat #3 in metatile #10 (type F) does not exist */ + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, + {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, {-1,-1,-1}, +}; +static const KitemapEntry *const kitemap[] = { + kitemap_H, + kitemap_T, + kitemap_P, + kitemap_F, +}; + +static const MetamapEntry metamap_H[] = { + /* 0, 0 -> */ {0, 0}, /* no alternatives */ + /* 1, 0 -> */ {1, 0}, /* no alternatives */ + /* 2, 0 -> */ {2, 0}, /* no alternatives */ + /* 3, 0 -> */ {3, 0}, /* no alternatives */ + /* 4, 0 -> */ {3, 4}, + /* 5, 0 -> */ {2, 8}, + /* 6, 0 -> */ {3, 3}, + /* 7, 0 -> */ {8, 4}, + /* 8, 0 -> */ {9, 8}, + /* 9, 0 -> */ {9, 4}, + /* 10, 0 -> */ {8, 1}, + /* 11, 0 -> */ {10, 5}, + /* 12, 0 -> */ {5, 3}, + /* 0, 1 -> */ {0, 1}, /* no alternatives */ + /* 1, 1 -> */ {1, 1}, /* no alternatives */ + /* 2, 1 -> */ {2, 1}, /* no alternatives */ + /* 3, 1 -> */ {3, 1}, /* no alternatives */ + /* 4, 1 -> */ {2, 9}, + /* 5, 1 -> */ {2, 3}, + /* 6, 1 -> */ {2, 6}, + /* 7, 1 -> */ {10, 4}, + /* 8, 1 -> */ {6, 3}, + /* 9, 1 -> */ {9, 9}, + /* 10, 1 -> */ {6, 10}, + /* 11, 1 -> */ {4, 3}, + /* 12, 1 -> */ {6, 6}, + /* 0, 2 -> */ {0, 2}, /* no alternatives */ + /* 1, 2 -> */ {1, 2}, /* no alternatives */ + /* 2, 2 -> */ {2, 2}, /* no alternatives */ + /* 3, 2 -> */ {3, 2}, /* no alternatives */ + /* 4, 2 -> */ {3, 5}, + /* 5, 2 -> */ {2, 12}, + /* 6, 2 -> */ {1, 3}, + /* 7, 2 -> */ {8, 5}, + /* 8, 2 -> */ {9, 12}, + /* 9, 2 -> */ {9, 5}, + /* 10, 2 -> */ {12, 0}, + /* 11, 2 -> */ {5, 6}, + /* 12, 2 -> */ {11, 1}, + /* 0, 3 -> */ {0, 3}, /* no alternatives */ + /* 1, 3 -> */ {6, 2}, + /* 2, 3 -> */ {5, 1}, + /* 3, 3 -> */ {6, 0}, + /* 4, 3 -> */ {12, 2}, + /* 5, 3 -> */ {10, 2}, + /* 6, 3 -> */ {10, 0}, + /* 7, 3 -> */ {-1,-1}, /* does not exist */ + /* 8, 3 -> */ {-1,-1}, /* does not exist */ + /* 9, 3 -> */ {-1,-1}, /* does not exist */ + /* 10, 3 -> */ {-1,-1}, /* does not exist */ + /* 11, 3 -> */ {-1,-1}, /* does not exist */ + /* 12, 3 -> */ {-1,-1}, /* does not exist */ + /* 0, 4 -> */ {0, 4}, /* no alternatives */ + /* 1, 4 -> */ {1, 4}, /* no alternatives */ + /* 2, 4 -> */ {2, 4}, /* no alternatives */ + /* 3, 4 -> */ {4, 0}, + /* 4, 4 -> */ {4, 4}, /* no alternatives */ + /* 5, 4 -> */ {5, 7}, + /* 6, 4 -> */ {6, 4}, /* no alternatives */ + /* 7, 4 -> */ {4, 9}, + /* 8, 4 -> */ {6, 7}, + /* 9, 4 -> */ {9, 0}, + /* 10, 4 -> */ {8, 9}, + /* 11, 4 -> */ {-1,-1}, /* does not exist */ + /* 12, 4 -> */ {-1,-1}, /* does not exist */ + /* 0, 5 -> */ {0, 5}, /* no alternatives */ + /* 1, 5 -> */ {1, 5}, /* no alternatives */ + /* 2, 5 -> */ {2, 5}, /* no alternatives */ + /* 3, 5 -> */ {4, 2}, + /* 4, 5 -> */ {4, 5}, /* no alternatives */ + /* 5, 5 -> */ {5, 11}, + /* 6, 5 -> */ {6, 5}, /* no alternatives */ + /* 7, 5 -> */ {4, 8}, + /* 8, 5 -> */ {6, 11}, + /* 9, 5 -> */ {9, 2}, + /* 10, 5 -> */ {8, 8}, + /* 11, 5 -> */ {-1,-1}, /* does not exist */ + /* 12, 5 -> */ {-1,-1}, /* does not exist */ + /* 0, 6 -> */ {0, 6}, /* no alternatives */ + /* 1, 6 -> */ {1, 6}, /* no alternatives */ + /* 2, 6 -> */ {6, 1}, + /* 3, 6 -> */ {3, 6}, /* no alternatives */ + /* 4, 6 -> */ {4, 6}, /* no alternatives */ + /* 5, 6 -> */ {8, 12}, + /* 6, 6 -> */ {12, 1}, + /* 7, 6 -> */ {10, 1}, + /* 8, 6 -> */ {4, 12}, + /* 9, 6 -> */ {9, 6}, /* no alternatives */ + /* 10, 6 -> */ {5, 10}, + /* 11, 6 -> */ {-1,-1}, /* does not exist */ + /* 12, 6 -> */ {-1,-1}, /* does not exist */ + /* 0, 7 -> */ {0, 7}, /* no alternatives */ + /* 1, 7 -> */ {1, 7}, /* no alternatives */ + /* 2, 7 -> */ {2, 7}, /* no alternatives */ + /* 3, 7 -> */ {3, 7}, /* no alternatives */ + /* 4, 7 -> */ {4, 7}, /* no alternatives */ + /* 5, 7 -> */ {5, 4}, + /* 6, 7 -> */ {7, 0}, + /* 7, 7 -> */ {10, 8}, + /* 8, 7 -> */ {8, 7}, /* no alternatives */ + /* 9, 7 -> */ {9, 7}, /* no alternatives */ + /* 10, 7 -> */ {10, 7}, /* no alternatives */ + /* 11, 7 -> */ {-1,-1}, /* does not exist */ + /* 12, 7 -> */ {-1,-1}, /* does not exist */ + /* 0, 8 -> */ {0, 8}, /* no alternatives */ + /* 1, 8 -> */ {1, 8}, /* no alternatives */ + /* 2, 8 -> */ {5, 0}, + /* 3, 8 -> */ {3, 8}, /* no alternatives */ + /* 4, 8 -> */ {7, 5}, + /* 5, 8 -> */ {5, 8}, /* no alternatives */ + /* 6, 8 -> */ {6, 8}, /* no alternatives */ + /* 7, 8 -> */ {7, 8}, /* no alternatives */ + /* 8, 8 -> */ {11, 0}, + /* 9, 8 -> */ {8, 0}, + /* 10, 8 -> */ {7, 7}, + /* 11, 8 -> */ {-1,-1}, /* does not exist */ + /* 12, 8 -> */ {-1,-1}, /* does not exist */ + /* 0, 9 -> */ {0, 9}, /* no alternatives */ + /* 1, 9 -> */ {1, 9}, /* no alternatives */ + /* 2, 9 -> */ {4, 1}, + /* 3, 9 -> */ {3, 9}, /* no alternatives */ + /* 4, 9 -> */ {7, 4}, + /* 5, 9 -> */ {5, 9}, /* no alternatives */ + /* 6, 9 -> */ {6, 9}, /* no alternatives */ + /* 7, 9 -> */ {7, 9}, /* no alternatives */ + /* 8, 9 -> */ {7, 1}, + /* 9, 9 -> */ {9, 1}, + /* 10, 9 -> */ {7, 10}, + /* 11, 9 -> */ {-1,-1}, /* does not exist */ + /* 12, 9 -> */ {-1,-1}, /* does not exist */ + /* 0, 10 -> */ {0, 10}, /* no alternatives */ + /* 1, 10 -> */ {1, 10}, /* no alternatives */ + /* 2, 10 -> */ {2, 10}, /* no alternatives */ + /* 3, 10 -> */ {3, 10}, /* no alternatives */ + /* 4, 10 -> */ {4, 10}, /* no alternatives */ + /* 5, 10 -> */ {10, 6}, + /* 6, 10 -> */ {7, 6}, + /* 7, 10 -> */ {10, 9}, + /* 8, 10 -> */ {8, 10}, /* no alternatives */ + /* 9, 10 -> */ {9, 10}, /* no alternatives */ + /* 10, 10 -> */ {10, 10}, /* no alternatives */ + /* 11, 10 -> */ {-1,-1}, /* does not exist */ + /* 12, 10 -> */ {-1,-1}, /* does not exist */ + /* 0, 11 -> */ {0, 11}, /* no alternatives */ + /* 1, 11 -> */ {1, 11}, /* no alternatives */ + /* 2, 11 -> */ {2, 11}, /* no alternatives */ + /* 3, 11 -> */ {3, 11}, /* no alternatives */ + /* 4, 11 -> */ {4, 11}, /* no alternatives */ + /* 5, 11 -> */ {5, 5}, + /* 6, 11 -> */ {7, 2}, + /* 7, 11 -> */ {10, 12}, + /* 8, 11 -> */ {8, 11}, /* no alternatives */ + /* 9, 11 -> */ {9, 11}, /* no alternatives */ + /* 10, 11 -> */ {10, 11}, /* no alternatives */ + /* 11, 11 -> */ {-1,-1}, /* does not exist */ + /* 12, 11 -> */ {-1,-1}, /* does not exist */ + /* 0, 12 -> */ {0, 12}, /* no alternatives */ + /* 1, 12 -> */ {1, 12}, /* no alternatives */ + /* 2, 12 -> */ {5, 2}, + /* 3, 12 -> */ {3, 12}, /* no alternatives */ + /* 4, 12 -> */ {8, 6}, + /* 5, 12 -> */ {5, 12}, /* no alternatives */ + /* 6, 12 -> */ {6, 12}, /* no alternatives */ + /* 7, 12 -> */ {7, 12}, /* no alternatives */ + /* 8, 12 -> */ {11, 2}, + /* 9, 12 -> */ {8, 2}, + /* 10, 12 -> */ {7, 11}, + /* 11, 12 -> */ {-1,-1}, /* does not exist */ + /* 12, 12 -> */ {-1,-1}, /* does not exist */ +}; +static const MetamapEntry metamap_T[] = { + /* 0, 0 -> */ {0, 0}, /* no alternatives */ + /* 1, 0 -> */ {1, 0}, /* no alternatives */ + /* 2, 0 -> */ {2, 0}, /* no alternatives */ + /* 3, 0 -> */ {3, 0}, /* no alternatives */ + /* 4, 0 -> */ {3, 3}, + /* 5, 0 -> */ {3, 1}, + /* 6, 0 -> */ {2, 2}, + /* 7, 0 -> */ {8, 3}, + /* 8, 0 -> */ {9, 1}, + /* 9, 0 -> */ {9, 3}, + /* 10, 0 -> */ {4, 6}, + /* 11, 0 -> */ {4, 4}, + /* 12, 0 -> */ {6, 2}, + /* 0, 1 -> */ {0, 1}, /* no alternatives */ + /* 1, 1 -> */ {1, 1}, /* no alternatives */ + /* 2, 1 -> */ {2, 1}, /* no alternatives */ + /* 3, 1 -> */ {5, 0}, + /* 4, 1 -> */ {4, 1}, /* no alternatives */ + /* 5, 1 -> */ {8, 4}, + /* 6, 1 -> */ {6, 1}, /* no alternatives */ + /* 7, 1 -> */ {6, 5}, + /* 8, 1 -> */ {11, 0}, + /* 9, 1 -> */ {8, 0}, + /* 10, 1 -> */ {5, 5}, + /* 11, 1 -> */ {-1,-1}, /* does not exist */ + /* 12, 1 -> */ {-1,-1}, /* does not exist */ + /* 0, 2 -> */ {0, 2}, /* no alternatives */ + /* 1, 2 -> */ {1, 2}, /* no alternatives */ + /* 2, 2 -> */ {6, 0}, + /* 3, 2 -> */ {3, 2}, /* no alternatives */ + /* 4, 2 -> */ {4, 2}, /* no alternatives */ + /* 5, 2 -> */ {5, 4}, + /* 6, 2 -> */ {12, 0}, + /* 7, 2 -> */ {10, 0}, + /* 8, 2 -> */ {6, 4}, + /* 9, 2 -> */ {9, 2}, /* no alternatives */ + /* 10, 2 -> */ {8, 6}, + /* 11, 2 -> */ {-1,-1}, /* does not exist */ + /* 12, 2 -> */ {-1,-1}, /* does not exist */ + /* 0, 3 -> */ {0, 3}, /* no alternatives */ + /* 1, 3 -> */ {1, 3}, /* no alternatives */ + /* 2, 3 -> */ {2, 3}, /* no alternatives */ + /* 3, 3 -> */ {4, 0}, + /* 4, 3 -> */ {4, 3}, /* no alternatives */ + /* 5, 3 -> */ {8, 5}, + /* 6, 3 -> */ {6, 3}, /* no alternatives */ + /* 7, 3 -> */ {6, 6}, + /* 8, 3 -> */ {4, 5}, + /* 9, 3 -> */ {9, 0}, + /* 10, 3 -> */ {5, 6}, + /* 11, 3 -> */ {-1,-1}, /* does not exist */ + /* 12, 3 -> */ {-1,-1}, /* does not exist */ + /* 0, 4 -> */ {0, 4}, /* no alternatives */ + /* 1, 4 -> */ {1, 4}, /* no alternatives */ + /* 2, 4 -> */ {2, 4}, /* no alternatives */ + /* 3, 4 -> */ {3, 4}, /* no alternatives */ + /* 4, 4 -> */ {8, 1}, + /* 5, 4 -> */ {5, 2}, + /* 6, 4 -> */ {8, 2}, + /* 7, 4 -> */ {7, 4}, /* no alternatives */ + /* 8, 4 -> */ {5, 1}, + /* 9, 4 -> */ {9, 4}, /* no alternatives */ + /* 10, 4 -> */ {10, 4}, /* no alternatives */ + /* 11, 4 -> */ {-1,-1}, /* does not exist */ + /* 12, 4 -> */ {-1,-1}, /* does not exist */ + /* 0, 5 -> */ {0, 5}, /* no alternatives */ + /* 1, 5 -> */ {1, 5}, /* no alternatives */ + /* 2, 5 -> */ {2, 5}, /* no alternatives */ + /* 3, 5 -> */ {3, 5}, /* no alternatives */ + /* 4, 5 -> */ {7, 0}, + /* 5, 5 -> */ {10, 1}, + /* 6, 5 -> */ {7, 1}, + /* 7, 5 -> */ {7, 5}, /* no alternatives */ + /* 8, 5 -> */ {5, 3}, + /* 9, 5 -> */ {9, 5}, /* no alternatives */ + /* 10, 5 -> */ {10, 5}, /* no alternatives */ + /* 11, 5 -> */ {-1,-1}, /* does not exist */ + /* 12, 5 -> */ {-1,-1}, /* does not exist */ + /* 0, 6 -> */ {0, 6}, /* no alternatives */ + /* 1, 6 -> */ {1, 6}, /* no alternatives */ + /* 2, 6 -> */ {2, 6}, /* no alternatives */ + /* 3, 6 -> */ {3, 6}, /* no alternatives */ + /* 4, 6 -> */ {7, 2}, + /* 5, 6 -> */ {10, 3}, + /* 6, 6 -> */ {7, 3}, + /* 7, 6 -> */ {7, 6}, /* no alternatives */ + /* 8, 6 -> */ {10, 2}, + /* 9, 6 -> */ {9, 6}, /* no alternatives */ + /* 10, 6 -> */ {10, 6}, /* no alternatives */ + /* 11, 6 -> */ {-1,-1}, /* does not exist */ + /* 12, 6 -> */ {-1,-1}, /* does not exist */ +}; +static const MetamapEntry metamap_P[] = { + /* 0, 0 -> */ {0, 0}, /* no alternatives */ + /* 1, 0 -> */ {1, 0}, /* no alternatives */ + /* 2, 0 -> */ {2, 0}, /* no alternatives */ + /* 3, 0 -> */ {3, 0}, /* no alternatives */ + /* 4, 0 -> */ {3, 4}, + /* 5, 0 -> */ {2, 5}, + /* 6, 0 -> */ {2, 3}, + /* 7, 0 -> */ {8, 4}, + /* 8, 0 -> */ {9, 5}, + /* 9, 0 -> */ {9, 4}, + /* 10, 0 -> */ {4, 9}, + /* 11, 0 -> */ {4, 8}, + /* 12, 0 -> */ {6, 3}, + /* 0, 1 -> */ {0, 1}, /* no alternatives */ + /* 1, 1 -> */ {1, 1}, /* no alternatives */ + /* 2, 1 -> */ {2, 1}, /* no alternatives */ + /* 3, 1 -> */ {3, 1}, /* no alternatives */ + /* 4, 1 -> */ {2, 10}, + /* 5, 1 -> */ {3, 2}, + /* 6, 1 -> */ {2, 4}, + /* 7, 1 -> */ {8, 10}, + /* 8, 1 -> */ {9, 2}, + /* 9, 1 -> */ {9, 10}, + /* 10, 1 -> */ {7, 4}, + /* 11, 1 -> */ {8, 2}, + /* 12, 1 -> */ {6, 4}, + /* 0, 2 -> */ {0, 2}, /* no alternatives */ + /* 1, 2 -> */ {1, 2}, /* no alternatives */ + /* 2, 2 -> */ {2, 2}, /* no alternatives */ + /* 3, 2 -> */ {5, 1}, + /* 4, 2 -> */ {4, 2}, /* no alternatives */ + /* 5, 2 -> */ {8, 6}, + /* 6, 2 -> */ {6, 2}, /* no alternatives */ + /* 7, 2 -> */ {6, 7}, + /* 8, 2 -> */ {4, 6}, + /* 9, 2 -> */ {8, 1}, + /* 10, 2 -> */ {5, 7}, + /* 11, 2 -> */ {-1,-1}, /* does not exist */ + /* 12, 2 -> */ {-1,-1}, /* does not exist */ + /* 0, 3 -> */ {0, 3}, /* no alternatives */ + /* 1, 3 -> */ {1, 3}, /* no alternatives */ + /* 2, 3 -> */ {6, 0}, + /* 3, 3 -> */ {3, 3}, /* no alternatives */ + /* 4, 3 -> */ {4, 3}, /* no alternatives */ + /* 5, 3 -> */ {5, 8}, + /* 6, 3 -> */ {12, 0}, + /* 7, 3 -> */ {10, 0}, + /* 8, 3 -> */ {6, 8}, + /* 9, 3 -> */ {9, 3}, /* no alternatives */ + /* 10, 3 -> */ {8, 9}, + /* 11, 3 -> */ {-1,-1}, /* does not exist */ + /* 12, 3 -> */ {-1,-1}, /* does not exist */ + /* 0, 4 -> */ {0, 4}, /* no alternatives */ + /* 1, 4 -> */ {1, 4}, /* no alternatives */ + /* 2, 4 -> */ {6, 1}, + /* 3, 4 -> */ {4, 0}, + /* 4, 4 -> */ {4, 4}, /* no alternatives */ + /* 5, 4 -> */ {5, 6}, + /* 6, 4 -> */ {12, 1}, + /* 7, 4 -> */ {6, 9}, + /* 8, 4 -> */ {6, 6}, + /* 9, 4 -> */ {9, 0}, + /* 10, 4 -> */ {5, 9}, + /* 11, 4 -> */ {-1,-1}, /* does not exist */ + /* 12, 4 -> */ {-1,-1}, /* does not exist */ + /* 0, 5 -> */ {0, 5}, /* no alternatives */ + /* 1, 5 -> */ {1, 5}, /* no alternatives */ + /* 2, 5 -> */ {5, 0}, + /* 3, 5 -> */ {3, 5}, /* no alternatives */ + /* 4, 5 -> */ {8, 8}, + /* 5, 5 -> */ {5, 5}, /* no alternatives */ + /* 6, 5 -> */ {6, 5}, /* no alternatives */ + /* 7, 5 -> */ {7, 5}, /* no alternatives */ + /* 8, 5 -> */ {11, 0}, + /* 9, 5 -> */ {8, 0}, + /* 10, 5 -> */ {7, 6}, + /* 11, 5 -> */ {-1,-1}, /* does not exist */ + /* 12, 5 -> */ {-1,-1}, /* does not exist */ + /* 0, 6 -> */ {0, 6}, /* no alternatives */ + /* 1, 6 -> */ {1, 6}, /* no alternatives */ + /* 2, 6 -> */ {2, 6}, /* no alternatives */ + /* 3, 6 -> */ {3, 6}, /* no alternatives */ + /* 4, 6 -> */ {11, 1}, + /* 5, 6 -> */ {5, 4}, + /* 6, 6 -> */ {7, 0}, + /* 7, 6 -> */ {10, 5}, + /* 8, 6 -> */ {5, 2}, + /* 9, 6 -> */ {9, 6}, /* no alternatives */ + /* 10, 6 -> */ {10, 6}, /* no alternatives */ + /* 11, 6 -> */ {-1,-1}, /* does not exist */ + /* 12, 6 -> */ {-1,-1}, /* does not exist */ + /* 0, 7 -> */ {0, 7}, /* no alternatives */ + /* 1, 7 -> */ {1, 7}, /* no alternatives */ + /* 2, 7 -> */ {2, 7}, /* no alternatives */ + /* 3, 7 -> */ {3, 7}, /* no alternatives */ + /* 4, 7 -> */ {7, 1}, + /* 5, 7 -> */ {10, 2}, + /* 6, 7 -> */ {7, 2}, + /* 7, 7 -> */ {7, 7}, /* no alternatives */ + /* 8, 7 -> */ {4, 10}, + /* 9, 7 -> */ {9, 7}, /* no alternatives */ + /* 10, 7 -> */ {10, 7}, /* no alternatives */ + /* 11, 7 -> */ {-1,-1}, /* does not exist */ + /* 12, 7 -> */ {-1,-1}, /* does not exist */ + /* 0, 8 -> */ {0, 8}, /* no alternatives */ + /* 1, 8 -> */ {1, 8}, /* no alternatives */ + /* 2, 8 -> */ {2, 8}, /* no alternatives */ + /* 3, 8 -> */ {3, 8}, /* no alternatives */ + /* 4, 8 -> */ {8, 5}, + /* 5, 8 -> */ {5, 3}, + /* 6, 8 -> */ {8, 3}, + /* 7, 8 -> */ {7, 8}, /* no alternatives */ + /* 8, 8 -> */ {4, 5}, + /* 9, 8 -> */ {9, 8}, /* no alternatives */ + /* 10, 8 -> */ {10, 8}, /* no alternatives */ + /* 11, 8 -> */ {-1,-1}, /* does not exist */ + /* 12, 8 -> */ {-1,-1}, /* does not exist */ + /* 0, 9 -> */ {0, 9}, /* no alternatives */ + /* 1, 9 -> */ {1, 9}, /* no alternatives */ + /* 2, 9 -> */ {2, 9}, /* no alternatives */ + /* 3, 9 -> */ {3, 9}, /* no alternatives */ + /* 4, 9 -> */ {7, 3}, + /* 5, 9 -> */ {10, 4}, + /* 6, 9 -> */ {10, 1}, + /* 7, 9 -> */ {10, 10}, + /* 8, 9 -> */ {10, 3}, + /* 9, 9 -> */ {9, 9}, /* no alternatives */ + /* 10, 9 -> */ {10, 9}, /* no alternatives */ + /* 11, 9 -> */ {-1,-1}, /* does not exist */ + /* 12, 9 -> */ {-1,-1}, /* does not exist */ + /* 0, 10 -> */ {0, 10}, /* no alternatives */ + /* 1, 10 -> */ {1, 10}, /* no alternatives */ + /* 2, 10 -> */ {4, 1}, + /* 3, 10 -> */ {3, 10}, /* no alternatives */ + /* 4, 10 -> */ {8, 7}, + /* 5, 10 -> */ {5, 10}, /* no alternatives */ + /* 6, 10 -> */ {6, 10}, /* no alternatives */ + /* 7, 10 -> */ {7, 10}, /* no alternatives */ + /* 8, 10 -> */ {4, 7}, + /* 9, 10 -> */ {9, 1}, + /* 10, 10 -> */ {7, 9}, + /* 11, 10 -> */ {-1,-1}, /* does not exist */ + /* 12, 10 -> */ {-1,-1}, /* does not exist */ +}; +static const MetamapEntry metamap_F[] = { + /* 0, 0 -> */ {0, 0}, /* no alternatives */ + /* 1, 0 -> */ {1, 0}, /* no alternatives */ + /* 2, 0 -> */ {2, 0}, /* no alternatives */ + /* 3, 0 -> */ {3, 0}, /* no alternatives */ + /* 4, 0 -> */ {3, 3}, + /* 5, 0 -> */ {2, 4}, + /* 6, 0 -> */ {2, 2}, + /* 7, 0 -> */ {8, 3}, + /* 8, 0 -> */ {9, 4}, + /* 9, 0 -> */ {9, 3}, + /* 10, 0 -> */ {4, 9}, + /* 11, 0 -> */ {4, 8}, + /* 12, 0 -> */ {6, 2}, + /* 0, 1 -> */ {0, 1}, /* no alternatives */ + /* 1, 1 -> */ {1, 1}, /* no alternatives */ + /* 2, 1 -> */ {2, 1}, /* no alternatives */ + /* 3, 1 -> */ {3, 1}, /* no alternatives */ + /* 4, 1 -> */ {2, 10}, + /* 5, 1 -> */ {2, 6}, + /* 6, 1 -> */ {2, 3}, + /* 7, 1 -> */ {8, 10}, + /* 8, 1 -> */ {9, 6}, + /* 9, 1 -> */ {9, 10}, + /* 10, 1 -> */ {7, 3}, + /* 11, 1 -> */ {8, 6}, + /* 12, 1 -> */ {6, 3}, + /* 0, 2 -> */ {0, 2}, /* no alternatives */ + /* 1, 2 -> */ {1, 2}, /* no alternatives */ + /* 2, 2 -> */ {6, 0}, + /* 3, 2 -> */ {3, 2}, /* no alternatives */ + /* 4, 2 -> */ {4, 2}, /* no alternatives */ + /* 5, 2 -> */ {5, 8}, + /* 6, 2 -> */ {12, 0}, + /* 7, 2 -> */ {10, 0}, + /* 8, 2 -> */ {6, 8}, + /* 9, 2 -> */ {9, 2}, /* no alternatives */ + /* 10, 2 -> */ {8, 9}, + /* 11, 2 -> */ {-1,-1}, /* does not exist */ + /* 12, 2 -> */ {-1,-1}, /* does not exist */ + /* 0, 3 -> */ {0, 3}, /* no alternatives */ + /* 1, 3 -> */ {1, 3}, /* no alternatives */ + /* 2, 3 -> */ {6, 1}, + /* 3, 3 -> */ {4, 0}, + /* 4, 3 -> */ {4, 3}, /* no alternatives */ + /* 5, 3 -> */ {5, 5}, + /* 6, 3 -> */ {12, 1}, + /* 7, 3 -> */ {6, 9}, + /* 8, 3 -> */ {6, 5}, + /* 9, 3 -> */ {9, 0}, + /* 10, 3 -> */ {5, 9}, + /* 11, 3 -> */ {-1,-1}, /* does not exist */ + /* 12, 3 -> */ {-1,-1}, /* does not exist */ + /* 0, 4 -> */ {0, 4}, /* no alternatives */ + /* 1, 4 -> */ {1, 4}, /* no alternatives */ + /* 2, 4 -> */ {5, 0}, + /* 3, 4 -> */ {3, 4}, /* no alternatives */ + /* 4, 4 -> */ {8, 8}, + /* 5, 4 -> */ {5, 4}, /* no alternatives */ + /* 6, 4 -> */ {6, 4}, /* no alternatives */ + /* 7, 4 -> */ {7, 4}, /* no alternatives */ + /* 8, 4 -> */ {11, 0}, + /* 9, 4 -> */ {8, 0}, + /* 10, 4 -> */ {7, 5}, + /* 11, 4 -> */ {-1,-1}, /* does not exist */ + /* 12, 4 -> */ {-1,-1}, /* does not exist */ + /* 0, 5 -> */ {0, 5}, /* no alternatives */ + /* 1, 5 -> */ {1, 5}, /* no alternatives */ + /* 2, 5 -> */ {2, 5}, /* no alternatives */ + /* 3, 5 -> */ {3, 5}, /* no alternatives */ + /* 4, 5 -> */ {11, 1}, + /* 5, 5 -> */ {5, 3}, + /* 6, 5 -> */ {7, 0}, + /* 7, 5 -> */ {10, 4}, + /* 8, 5 -> */ {4, 6}, + /* 9, 5 -> */ {9, 5}, /* no alternatives */ + /* 10, 5 -> */ {10, 5}, /* no alternatives */ + /* 11, 5 -> */ {-1,-1}, /* does not exist */ + /* 12, 5 -> */ {-1,-1}, /* does not exist */ + /* 0, 6 -> */ {0, 6}, /* no alternatives */ + /* 1, 6 -> */ {1, 6}, /* no alternatives */ + /* 2, 6 -> */ {5, 1}, + /* 3, 6 -> */ {3, 6}, /* no alternatives */ + /* 4, 6 -> */ {8, 5}, + /* 5, 6 -> */ {5, 6}, /* no alternatives */ + /* 6, 6 -> */ {6, 6}, /* no alternatives */ + /* 7, 6 -> */ {7, 6}, /* no alternatives */ + /* 8, 6 -> */ {4, 5}, + /* 9, 6 -> */ {8, 1}, + /* 10, 6 -> */ {7, 7}, + /* 11, 6 -> */ {-1,-1}, /* does not exist */ + /* 12, 6 -> */ {-1,-1}, /* does not exist */ + /* 0, 7 -> */ {0, 7}, /* no alternatives */ + /* 1, 7 -> */ {1, 7}, /* no alternatives */ + /* 2, 7 -> */ {2, 7}, /* no alternatives */ + /* 3, 7 -> */ {3, 7}, /* no alternatives */ + /* 4, 7 -> */ {4, 7}, /* no alternatives */ + /* 5, 7 -> */ {4, 10}, + /* 6, 7 -> */ {7, 1}, + /* 7, 7 -> */ {10, 6}, + /* 8, 7 -> */ {8, 7}, /* no alternatives */ + /* 9, 7 -> */ {9, 7}, /* no alternatives */ + /* 10, 7 -> */ {10, 7}, /* no alternatives */ + /* 11, 7 -> */ {-1,-1}, /* does not exist */ + /* 12, 7 -> */ {-1,-1}, /* does not exist */ + /* 0, 8 -> */ {0, 8}, /* no alternatives */ + /* 1, 8 -> */ {1, 8}, /* no alternatives */ + /* 2, 8 -> */ {2, 8}, /* no alternatives */ + /* 3, 8 -> */ {3, 8}, /* no alternatives */ + /* 4, 8 -> */ {8, 4}, + /* 5, 8 -> */ {5, 2}, + /* 6, 8 -> */ {8, 2}, + /* 7, 8 -> */ {7, 8}, /* no alternatives */ + /* 8, 8 -> */ {4, 4}, + /* 9, 8 -> */ {9, 8}, /* no alternatives */ + /* 10, 8 -> */ {10, 8}, /* no alternatives */ + /* 11, 8 -> */ {-1,-1}, /* does not exist */ + /* 12, 8 -> */ {-1,-1}, /* does not exist */ + /* 0, 9 -> */ {0, 9}, /* no alternatives */ + /* 1, 9 -> */ {1, 9}, /* no alternatives */ + /* 2, 9 -> */ {2, 9}, /* no alternatives */ + /* 3, 9 -> */ {3, 9}, /* no alternatives */ + /* 4, 9 -> */ {7, 2}, + /* 5, 9 -> */ {10, 3}, + /* 6, 9 -> */ {10, 1}, + /* 7, 9 -> */ {10, 10}, + /* 8, 9 -> */ {10, 2}, + /* 9, 9 -> */ {9, 9}, /* no alternatives */ + /* 10, 9 -> */ {10, 9}, /* no alternatives */ + /* 11, 9 -> */ {-1,-1}, /* does not exist */ + /* 12, 9 -> */ {-1,-1}, /* does not exist */ + /* 0, 10 -> */ {0, 10}, /* no alternatives */ + /* 1, 10 -> */ {1, 10}, /* no alternatives */ + /* 2, 10 -> */ {4, 1}, + /* 3, 10 -> */ {3, 10}, /* no alternatives */ + /* 4, 10 -> */ {5, 7}, + /* 5, 10 -> */ {5, 10}, /* no alternatives */ + /* 6, 10 -> */ {6, 10}, /* no alternatives */ + /* 7, 10 -> */ {7, 10}, /* no alternatives */ + /* 8, 10 -> */ {6, 7}, + /* 9, 10 -> */ {9, 1}, + /* 10, 10 -> */ {7, 9}, + /* 11, 10 -> */ {-1,-1}, /* does not exist */ + /* 12, 10 -> */ {-1,-1}, /* does not exist */ +}; +static const MetamapEntry *const metamap[] = { + metamap_H, + metamap_T, + metamap_P, + metamap_F, +}; diff --git a/hat.c b/hat.c new file mode 100644 index 0000000..d59f81e --- /dev/null +++ b/hat.c @@ -0,0 +1,1248 @@ +/* + * Code to generate patches of the aperiodic 'hat' tiling discovered + * in 2023. + * + * aux/doc/hats.html contains an explanation of the basic ideas of + * this algorithm, which can't really be put in a source file because + * it just has too many complicated diagrams. So read that first, + * because the comments in here will refer to it. + * + * Discoverers' website: https://cs.uwaterloo.ca/~csk/hat/ + * Preprint of paper: https://arxiv.org/abs/2303.10798 + */ + +#include +#include +#include +#include +#include +#include + +#include "puzzles.h" +#include "hat.h" + +/* + * Coordinate system: + * + * The output of this code lives on the tiling known to grid.c as + * 'Kites', which can be viewed as a tiling of hexagons each of which + * is subdivided into six kites sharing their pointy vertex, or + * (equivalently) a tiling of equilateral triangles each subdivided + * into three kits sharing their blunt vertex. + * + * We express coordinates in this system relative to the basis (1, r) + * where r = (1 + sqrt(3)i) / 2 is a primitive 6th root of unity. This + * gives us a system in which two integer coordinates can address any + * grid point, provided we scale up so that the side length of the + * equilateral triangles in the tiling is 6. + */ + +typedef struct Point { + int x, y; /* represents x + yr */ +} Point; + +static inline Point pointscale(int scale, Point a) +{ + Point r = { scale * a.x, scale * a.y }; + return r; +} + +static inline Point pointadd(Point a, Point b) +{ + Point r = { a.x + b.x, a.y + b.y }; + return r; +} + +/* + * We identify a single kite by the coordinates of its four vertices. + * This allows us to construct the coordinates of an adjacent kite by + * taking affine transformations of the original kite's vertices. + * + * This is a useful way to do it because it means that if you reflect + * the kite (by swapping its left and right vertices) then these + * transformations also perform in a reflected way. This will be + * useful in the code below that outputs the coordinates of each hat, + * because this way it can work by walking around its 8 kites using a + * fixed set of steps, and if the hat is reflected, then we just + * reflect the starting kite before doing that, and everything still + * works. + */ + +typedef struct Kite { + Point centre, left, right, outer; +} Kite; + +static inline Kite kite_left(Kite k) +{ + Kite r; + r.centre = k.centre; + r.right = k.left; + r.outer = pointadd(pointscale(2, k.left), pointscale(-1, k.outer)); + r.left = pointadd(pointadd(k.centre, k.left), pointscale(-1, k.right)); + return r; +} + +static inline Kite kite_right(Kite k) +{ + Kite r; + r.centre = k.centre; + r.left = k.right; + r.outer = pointadd(pointscale(2, k.right), pointscale(-1, k.outer)); + r.right = pointadd(pointadd(k.centre, k.right), pointscale(-1, k.left)); + return r; +} + +static inline Kite kite_forward_left(Kite k) +{ + Kite r; + r.outer = k.outer; + r.right = k.left; + r.centre = pointadd(pointscale(2, k.left), pointscale(-1, k.centre)); + r.left = pointadd(pointadd(k.right, k.left), pointscale(-1, k.centre)); + return r; +} + +static inline Kite kite_forward_right(Kite k) +{ + Kite r; + r.outer = k.outer; + r.left = k.right; + r.centre = pointadd(pointscale(2, k.right), pointscale(-1, k.centre)); + r.right = pointadd(pointadd(k.left, k.right), pointscale(-1, k.centre)); + return r; +} + +typedef enum KiteStep { KS_LEFT, KS_RIGHT, KS_F_LEFT, KS_F_RIGHT } KiteStep; + +static inline Kite kite_step(Kite k, KiteStep step) +{ + switch (step) { + case KS_LEFT: return kite_left(k); + case KS_RIGHT: return kite_right(k); + case KS_F_LEFT: return kite_forward_left(k); + default /* case KS_F_RIGHT */: return kite_forward_right(k); + } +} + +/* + * Function to enumerate the kites in a rectangular region, in a + * serpentine-raster fashion so that every kite delivered shares an + * edge with a recent previous one. + */ +#define KE_NKEEP 3 +typedef struct KiteEnum { + /* Fields private to the enumerator */ + int state; + int x, y, w, h; + unsigned curr_index; + + /* Fields the client can legitimately read out */ + Kite *curr; + Kite recent[KE_NKEEP]; + unsigned last_index; + KiteStep last_step; /* step that got curr from recent[last_index] */ +} KiteEnum; + +static void first_kite(KiteEnum *s, int w, int h) +{ + Kite start = { {0,0}, {0, 3}, {3, 0}, {2, 2} }; + size_t i; + + for (i = 0; i < KE_NKEEP; i++) + s->recent[i] = start; /* initialise to *something* */ + s->curr_index = 0; + s->curr = &s->recent[s->curr_index]; + s->state = 1; + s->w = w; + s->h = h; + s->x = 0; + s->y = 0; +} +static bool next_kite(KiteEnum *s) +{ + unsigned lastbut1 = s->last_index; + s->last_index = s->curr_index; + s->curr_index = (s->curr_index + 1) % KE_NKEEP; + s->curr = &s->recent[s->curr_index]; + + switch (s->state) { + /* States 1,2,3 walk rightwards along the upper side of a + * horizontal grid line with a pointy kite end at the start + * point */ + case 1: + s->last_step = KS_F_RIGHT; + s->state = 2; + break; + + case 2: + if (s->x+1 >= s->w) { + s->last_step = KS_F_RIGHT; + s->state = 4; + break; + } + s->last_step = KS_RIGHT; + s->state = 3; + s->x++; + break; + + case 3: + s->last_step = KS_RIGHT; + s->state = 1; + break; + + /* State 4 is special: we've just moved up into a row below a + * grid line, but we can't produce the rightmost tile of that + * row because it's not adjacent any tile so far emitted. So + * instead, emit the second-rightmost tile, and next time, + * we'll emit the rightmost. */ + case 4: + s->last_step = KS_LEFT; + s->state = 5; + break; + + /* And now we have to emit the third-rightmost tile relative + * to the last but one tile we emitted (the one from state 2, + * not state 4). */ + case 5: + s->last_step = KS_RIGHT; + s->last_index = lastbut1; + s->state = 6; + break; + + /* Now states 6-8 handle the general case of walking leftwards + * along the lower side of a line, starting from a + * right-angled kite end. */ + case 6: + if (s->x <= 0) { + if (s->y+1 >= s->h) { + s->state = 0; + return false; + } + s->last_step = KS_RIGHT; + s->state = 9; + s->y++; + break; + } + s->last_step = KS_F_RIGHT; + s->state = 7; + s->x--; + break; + + case 7: + s->last_step = KS_RIGHT; + s->state = 8; + break; + + case 8: + s->last_step = KS_RIGHT; + s->state = 6; + break; + + /* States 9,10,11 walk rightwards along the upper side of a + * horizontal grid line with a right-angled kite end at the + * start point. This time there's no awkward transition from + * the previous row. */ + case 9: + s->last_step = KS_RIGHT; + s->state = 10; + break; + + case 10: + s->last_step = KS_RIGHT; + s->state = 11; + break; + + case 11: + if (s->x+1 >= s->w) { + /* Another awkward transition to the next row, where we + * have to generate it based on the previous state-9 tile. + * But this time at least we generate the rightmost tile + * of the new row, so the next states will be simple. */ + s->last_step = KS_F_RIGHT; + s->last_index = lastbut1; + s->state = 12; + break; + } + s->last_step = KS_F_RIGHT; + s->state = 9; + s->x++; + break; + + /* States 12,13,14 walk leftwards along the upper edge of a + * horizontal grid line with a pointy kite end at the start + * point */ + case 12: + s->last_step = KS_F_RIGHT; + s->state = 13; + break; + + case 13: + if (s->x <= 0) { + if (s->y+1 >= s->h) { + s->state = 0; + return false; + } + s->last_step = KS_LEFT; + s->state = 1; + s->y++; + break; + } + s->last_step = KS_RIGHT; + s->state = 14; + s->x--; + break; + + case 14: + s->last_step = KS_RIGHT; + s->state = 12; + break; + + default: + return false; + } + + *s->curr = kite_step(s->recent[s->last_index], s->last_step); + return true; +} + +/* + * Assorted useful definitions. + */ +typedef enum TileType { TT_H, TT_T, TT_P, TT_F, TT_KITE, TT_HAT } TileType; +static const char tilechars[] = "HTPF"; + +#define HAT_KITES 8 /* number of kites in a hat */ +#define MT_MAXEXPAND 13 /* largest number of metatiles in any expansion */ + +/* + * Definitions for the autogenerated hat-tables.h header file that + * defines all the lookup tables. + */ +typedef struct MetatilePossibleParent { + TileType type; + unsigned index; +} MetatilePossibleParent; + +typedef struct KitemapEntry { + int kite, hat, meta; /* all -1 if impossible */ +} KitemapEntry; + +typedef struct MetamapEntry { + int meta, meta2; +} MetamapEntry; + +static inline size_t kitemap_index(KiteStep step, unsigned kite, + unsigned hat, unsigned meta) +{ + return step + 4 * (kite + 8 * (hat + 4 * meta)); +} + +static inline size_t metamap_index(unsigned meta, unsigned meta2) +{ + return meta2 * MT_MAXEXPAND + meta; +} + +/* + * The actual tables. + */ +#include "hat-tables.h" + +/* + * Coordinate system for tracking kites within a randomly selected + * part of the recursively expanded hat tiling. + * + * HatCoords will store an array of HatCoord, in little-endian + * arrangement. So hc->c[0] will always have type TT_KITE and index a + * single kite within a hat; hc->c[1] will have type TT_HAT and index + * a hat within a first-order metatile; hc->c[2] will be the smallest + * metatile containing this hat, and hc->c[3, 4, 5, ...] will be + * higher-order metatiles as needed. + * + * The last coordinate stored, hc->c[hc->nc-1], will have a tile type + * but no index (represented by index==-1). This means "we haven't + * decided yet what this level of metatile needs to be". If we need to + * refer to this level during the step_coords algorithm, we make it up + * at random, based on a table of what metatiles each type can + * possibly be part of, at what index. + */ +typedef struct HatCoord { + int index; /* index within that tile, or -1 if not yet known */ + TileType type; /* type of this tile */ +} HatCoord; + +typedef struct HatCoords { + HatCoord *c; + size_t nc, csize; +} HatCoords; + +static HatCoords *hc_new(void) +{ + HatCoords *hc = snew(HatCoords); + hc->nc = hc->csize = 0; + hc->c = NULL; + return hc; +} + +static void hc_free(HatCoords *hc) +{ + if (hc) { + sfree(hc->c); + sfree(hc); + } +} + +static void hc_make_space(HatCoords *hc, size_t size) +{ + if (hc->csize < size) { + hc->csize = hc->csize * 5 / 4 + 16; + if (hc->csize < size) + hc->csize = size; + hc->c = sresize(hc->c, hc->csize, HatCoord); + } +} + +static HatCoords *hc_copy(HatCoords *hc_in) +{ + HatCoords *hc_out = hc_new(); + hc_make_space(hc_out, hc_in->nc); + memcpy(hc_out->c, hc_in->c, hc_in->nc * sizeof(*hc_out->c)); + hc_out->nc = hc_in->nc; + return hc_out; +} + +/* + * HatCoordContext is the shared context of a whole run of the + * algorithm. Its 'prototype' HatCoords object represents the + * coordinates of the starting kite, and is extended as necessary; any + * other HatCoord that needs extending will copy the higher-order + * values from ctx->prototype as needed, so that once each choice has + * been made, it remains consistent. + * + * When we're inventing a random piece of tiling in the first place, + * we append to ctx->prototype by choosing a random (but legal) + * higher-level metatile for the current topmost one to turn out to be + * part of. When we're replaying a generation whose parameters are + * already stored, we don't have a random_state, and we make fixed + * decisions if not enough coordinates were provided. + * + * (Of course another approach would be to reject grid descriptions + * that didn't define enough coordinates! But that would involve a + * whole extra iteration over the whole grid region just for + * validation, and that seems like more timewasting than really + * needed. So we tolerate short descriptions, and do something + * deterministic with them.) + */ + +typedef struct HatCoordContext { + random_state *rs; + HatCoords *prototype; +} HatCoordContext; + +static void init_coords_random(HatCoordContext *ctx, random_state *rs) +{ + ctx->rs = rs; + ctx->prototype = hc_new(); + hc_make_space(ctx->prototype, 3); + ctx->prototype->c[0].type = TT_KITE; + ctx->prototype->c[1].type = TT_HAT; + ctx->prototype->c[2].type = random_upto(rs, 4); + ctx->prototype->c[2].index = -1; + ctx->prototype->c[1].index = random_upto( + rs, hats_in_metatile[ctx->prototype->c[2].type]); + ctx->prototype->c[0].index = random_upto(rs, HAT_KITES); + ctx->prototype->nc = 3; +} + +static inline int metatile_char_to_enum(char metatile) +{ + return (metatile == 'H' ? TT_H : + metatile == 'T' ? TT_T : + metatile == 'P' ? TT_P : + metatile == 'F' ? TT_F : -1); +} + +static void init_coords_params(HatCoordContext *ctx, + const struct HatPatchParams *hp) +{ + size_t i; + + ctx->rs = NULL; + ctx->prototype = hc_new(); + + assert(hp->ncoords >= 3); + + hc_make_space(ctx->prototype, hp->ncoords + 1); + ctx->prototype->nc = hp->ncoords + 1; + + for (i = 0; i < hp->ncoords; i++) + ctx->prototype->c[i].index = hp->coords[i]; + + ctx->prototype->c[hp->ncoords].type = + metatile_char_to_enum(hp->final_metatile); + ctx->prototype->c[hp->ncoords].index = -1; + + ctx->prototype->c[0].type = TT_KITE; + ctx->prototype->c[1].type = TT_HAT; + + for (i = hp->ncoords - 1; i > 1; i--) { + TileType metatile = ctx->prototype->c[i+1].type; + assert(hp->coords[i] < nchildren[metatile]); + ctx->prototype->c[i].type = children[metatile][hp->coords[i]]; + } + + assert(hp->coords[0] < 8); +} + +static HatCoords *initial_coords(HatCoordContext *ctx) +{ + return hc_copy(ctx->prototype); +} + +/* + * Extend hc until it has at least n coordinates in, by copying from + * ctx->prototype if needed, and extending ctx->prototype if needed in + * order to do that. + */ +static void ensure_coords(HatCoordContext *ctx, HatCoords *hc, size_t n) +{ + if (ctx->prototype->nc < n) { + hc_make_space(ctx->prototype, n); + while (ctx->prototype->nc < n) { + TileType type = ctx->prototype->c[ctx->prototype->nc - 1].type; + assert(ctx->prototype->c[ctx->prototype->nc - 1].index == -1); + const MetatilePossibleParent *parents = permitted_parents[type]; + size_t parent_index; + if (ctx->rs) { + parent_index = random_upto(ctx->rs, n_permitted_parents[type]); + } else { + parent_index = 0; + } + ctx->prototype->c[ctx->prototype->nc - 1].index = + parents[parent_index].index; + ctx->prototype->c[ctx->prototype->nc].index = -1; + ctx->prototype->c[ctx->prototype->nc].type = + parents[parent_index].type; + ctx->prototype->nc++; + } + } + + hc_make_space(hc, n); + while (hc->nc < n) { + assert(hc->c[hc->nc - 1].index == -1); + assert(hc->c[hc->nc - 1].type == ctx->prototype->c[hc->nc - 1].type); + hc->c[hc->nc - 1].index = ctx->prototype->c[hc->nc - 1].index; + hc->c[hc->nc].index = -1; + hc->c[hc->nc].type = ctx->prototype->c[hc->nc].type; + hc->nc++; + } +} + +static void cleanup_coords(HatCoordContext *ctx) +{ + hc_free(ctx->prototype); +} + +#ifdef DEBUG_COORDS +static inline void debug_coords(const char *prefix, HatCoords *hc, + const char *suffix) +{ + const char *sep = ""; + static const char *const types[] = {"H","T","P","F","kite","hat"}; + + fputs(prefix, stderr); + for (size_t i = 0; i < hc->nc; i++) { + fprintf(stderr, "%s %s ", sep, types[hc->c[i].type]); + sep = " ."; + if (hc->c[i].index == -1) + fputs("?", stderr); + else + fprintf(stderr, "%d", hc->c[i].index); + } + fputs(suffix, stderr); +} +#else +#define debug_coords(p,c,s) ((void)0) +#endif + +/* + * The actual system for finding the coordinates of an adjacent kite. + */ + +/* + * Kitemap step: ensure we have enough coordinates to know two levels + * of meta-tiling, and use the kite map for the outer layer to move + * around the individual kites. If this fails, return NULL. + */ +static HatCoords *try_step_coords_kitemap( + HatCoordContext *ctx, HatCoords *hc_in, KiteStep step) +{ + ensure_coords(ctx, hc_in, 4); + debug_coords(" try kitemap ", hc_in, "\n"); + unsigned kite = hc_in->c[0].index; + unsigned hat = hc_in->c[1].index; + unsigned meta = hc_in->c[2].index; + TileType meta2type = hc_in->c[3].type; + const KitemapEntry *ke = &kitemap[meta2type][ + kitemap_index(step, kite, hat, meta)]; + if (ke->kite >= 0) { + /* + * Success! We've got coordinates for the next kite in this + * direction. + */ + HatCoords *hc_out = hc_copy(hc_in); + + hc_out->c[2].index = ke->meta; + hc_out->c[2].type = children[meta2type][ke->meta]; + hc_out->c[1].index = ke->hat; + hc_out->c[1].type = TT_HAT; + hc_out->c[0].index = ke->kite; + hc_out->c[0].type = TT_KITE; + + debug_coords(" success! ", hc_out, "\n"); + return hc_out; + } + + return NULL; +} + +/* + * Recursive metamap step. Try using the metamap to rewrite the + * coordinates at hc->c[depth] and hc->c[depth+1] (using the metamap + * for the tile type described in hc->c[depth+2]). If successful, + * recurse back down to see if this led to a successful step via the + * kitemap. If even that fails (so that we need to try a higher-order + * metamap rewrite), return NULL. + */ +static HatCoords *try_step_coords_metamap( + HatCoordContext *ctx, HatCoords *hc_in, KiteStep step, size_t depth) +{ + HatCoords *hc_tmp = NULL, *hc_out; + + ensure_coords(ctx, hc_in, depth+3); +#ifdef DEBUG_COORDS + fprintf(stderr, " try meta %-4d", (int)depth); + debug_coords("", hc_in, "\n"); +#endif + unsigned meta_orig = hc_in->c[depth].index; + unsigned meta2_orig = hc_in->c[depth+1].index; + TileType meta3type = hc_in->c[depth+2].type; + + unsigned meta = meta_orig, meta2 = meta2_orig; + + while (true) { + const MetamapEntry *me; + HatCoords *hc_curr = hc_tmp ? hc_tmp : hc_in; + + if (depth > 2) + hc_out = try_step_coords_metamap(ctx, hc_curr, step, depth - 1); + else + hc_out = try_step_coords_kitemap(ctx, hc_curr, step); + if (hc_out) { + hc_free(hc_tmp); + return hc_out; + } + + me = &metamap[meta3type][metamap_index(meta, meta2)]; + assert(me->meta != -1); + if (me->meta == meta_orig && me->meta2 == meta2_orig) { + hc_free(hc_tmp); + return NULL; + } + + meta = me->meta; + meta2 = me->meta2; + + /* + * We must do the rewrite in a copy of hc_in. It's not + * _necessarily_ obvious that that's the case (any successful + * rewrite leaves the coordinates still valid and still + * referring to the same kite, right?). But the problem is + * that we might do a rewrite at this level more than once, + * and in between, a metamap rewrite at the next level down + * might have modified _one_ of the two coordinates we're + * messing about with. So it's easiest to let the recursion + * just use a separate copy. + */ + if (!hc_tmp) + hc_tmp = hc_copy(hc_in); + + hc_tmp->c[depth+1].index = meta2; + hc_tmp->c[depth+1].type = children[meta3type][meta2]; + hc_tmp->c[depth].index = meta; + hc_tmp->c[depth].type = children[hc_tmp->c[depth+1].type][meta]; + + debug_coords(" rewritten -> ", hc_tmp, "\n"); + } +} + +/* + * The top-level algorithm for finding the next tile. + */ +static HatCoords *step_coords(HatCoordContext *ctx, HatCoords *hc_in, + KiteStep step) +{ + HatCoords *hc_out; + size_t depth; + +#ifdef DEBUG_COORDS + static const char *const directions[] = { + " left\n", " right\n", " forward left\n", " forward right\n" }; + debug_coords("step start ", hc_in, directions[step]); +#endif + + /* + * First, just try a kitemap step immediately. If that succeeds, + * we're done. + */ + if ((hc_out = try_step_coords_kitemap(ctx, hc_in, step)) != NULL) + return hc_out; + + /* + * Otherwise, try metamap rewrites at successively higher layers + * until one works. Each one will recurse back down to the + * kitemap, as described above. + */ + for (depth = 2;; depth++) { + if ((hc_out = try_step_coords_metamap( + ctx, hc_in, step, depth)) != NULL) + return hc_out; + } +} + +/* + * Generate a random set of parameters for a tiling of a given size. + * To do this, we iterate over the whole tiling via first_kite and + * next_kite, and for each kite, calculate its coordinates. But then + * we throw the coordinates away and don't do anything with them! + * + * But the side effect of _calculating_ all those coordinates is that + * we found out how far ctx->prototype needed to be extended, and did + * so, pulling random choices out of our random_state. So after this + * iteration, ctx->prototype contains everything we need to replicate + * the same piece of tiling next time. + */ +void hat_tiling_randomise(struct HatPatchParams *hp, int w, int h, + random_state *rs) +{ + HatCoordContext ctx[1]; + HatCoords *coords[KE_NKEEP]; + KiteEnum s[1]; + size_t i; + + init_coords_random(ctx, rs); + for (i = 0; i < lenof(coords); i++) + coords[i] = NULL; + + first_kite(s, w, h); + coords[s->curr_index] = initial_coords(ctx); + + while (next_kite(s)) { + hc_free(coords[s->curr_index]); + coords[s->curr_index] = step_coords( + ctx, coords[s->last_index], s->last_step); + } + + hp->ncoords = ctx->prototype->nc - 1; + hp->coords = snewn(hp->ncoords, unsigned char); + for (i = 0; i < hp->ncoords; i++) + hp->coords[i] = ctx->prototype->c[i].index; + hp->final_metatile = tilechars[ctx->prototype->c[hp->ncoords].type]; + + cleanup_coords(ctx); + for (i = 0; i < lenof(coords); i++) + hc_free(coords[i]); +} + +const char *hat_tiling_params_invalid(const struct HatPatchParams *hp) +{ + TileType metatile; + size_t i; + + if (hp->ncoords < 3) + return "Grid parameters require at least three coordinates"; + if (metatile_char_to_enum(hp->final_metatile) < 0) + return "Grid parameters contain an invalid final metatile"; + if (hp->coords[0] >= 8) + return "Grid parameters contain an invalid kite index"; + + metatile = metatile_char_to_enum(hp->final_metatile); + for (i = hp->ncoords - 1; i > 1; i--) { + if (hp->coords[i] >= nchildren[metatile]) + return "Grid parameters contain an invalid metatile index"; + metatile = children[metatile][hp->coords[i]]; + } + + if (hp->coords[1] >= hats_in_metatile[metatile]) + return "Grid parameters contain an invalid hat index"; + + return NULL; +} + +/* + * For each kite generated by hat_tiling_generate, potentially + * generate an output hat and give it to our caller. + * + * We do this by starting from kite #0 of each hat, and tracing round + * the boundary. If the whole boundary is within the caller's bounding + * region, we return it; if it goes off the edge, we don't. + * + * (Of course, every hat we _do_ want to return will have all its + * kites inside the rectangle, so its kite #0 will certainly be caught + * by this iteration.) + */ +static void maybe_report_hat(int w, int h, Kite kite, HatCoords *hc, + hat_tile_callback_fn cb, void *cbctx) +{ + Point vertices[14]; + size_t i, j; + bool reversed = false; + int coords[28]; + + /* Only iterate from kite #0 of a hat */ + if (hc->c[0].index != 0) + return; + + /* + * Identify reflected hats: they are always hat #3 of an H + * metatile. If we find one, reflect the starting kite so that the + * kite_step operations below will go in the other direction. + */ + if (hc->c[2].type == TT_H && hc->c[1].index == 3) { + reversed = true; + Point tmp = kite.left; + kite.left = kite.right; + kite.right = tmp; + } + + vertices[0] = kite.centre; + vertices[1] = kite.right; + vertices[2] = kite.outer; + vertices[3] = kite.left; + kite = kite_left(kite); /* now on kite #1 */ + kite = kite_forward_right(kite); /* now on kite #2 */ + vertices[4] = kite.centre; + kite = kite_right(kite); /* now on kite #3 */ + vertices[5] = kite.right; + vertices[6] = kite.outer; + kite = kite_forward_left(kite); /* now on kite #4 */ + vertices[7] = kite.left; + vertices[8] = kite.centre; + kite = kite_right(kite); /* now on kite #5 */ + kite = kite_right(kite); /* now on kite #6 */ + kite = kite_right(kite); /* now on kite #7 */ + vertices[9] = kite.right; + vertices[10] = kite.outer; + vertices[11] = kite.left; + kite = kite_left(kite); /* now on kite #6 again */ + vertices[12] = kite.outer; + vertices[13] = kite.left; + + if (reversed) { + /* For a reversed kite, also reverse the vertex order, so that + * we report every polygon in a consistent orientation */ + for (i = 0, j = 13; i < j; i++, j--) { + Point tmp = vertices[i]; + vertices[i] = vertices[j]; + vertices[j] = tmp; + } + } + + /* + * Convert from our internal coordinate system into the orthogonal + * one used in this module's external API. In the same loop, we + * might as well do the bounds check. + */ + for (i = 0; i < 14; i++) { + Point v = vertices[i]; + int x = (v.x * 2 + v.y) / 3, y = v.y; + + if (x < 0 || x > 4*w || y < 0 || y > 6*h) + return; /* a vertex of this kite is out of bounds */ + + coords[2*i] = x; + coords[2*i+1] = y; + } + + cb(cbctx, 14, coords); +} + +/* + * Generate a hat tiling from a previously generated set of parameters. + */ +void hat_tiling_generate(const struct HatPatchParams *hp, int w, int h, + hat_tile_callback_fn cb, void *cbctx) +{ + HatCoordContext ctx[1]; + HatCoords *coords[KE_NKEEP]; + KiteEnum s[1]; + size_t i; + + init_coords_params(ctx, hp); + for (i = 0; i < lenof(coords); i++) + coords[i] = NULL; + + first_kite(s, w, h); + coords[s->curr_index] = initial_coords(ctx); + maybe_report_hat(w, h, *s->curr, coords[s->curr_index], cb, cbctx); + + while (next_kite(s)) { + hc_free(coords[s->curr_index]); + coords[s->curr_index] = step_coords( + ctx, coords[s->last_index], s->last_step); + maybe_report_hat(w, h, *s->curr, coords[s->curr_index], cb, cbctx); + } + + cleanup_coords(ctx); + for (i = 0; i < lenof(coords); i++) + hc_free(coords[i]); +} + +#ifdef TEST_HAT + +#include + +static HatCoords *hc_construct_v(TileType type, va_list ap) +{ + HatCoords *hc = hc_new(); + while (true) { + int index = va_arg(ap, int); + + hc_make_space(hc, hc->nc + 1); + hc->c[hc->nc].type = type; + hc->c[hc->nc].index = index; + hc->nc++; + + if (index < 0) + return hc; + + type = va_arg(ap, TileType); + } +} + +static HatCoords *hc_construct(TileType type, ...) +{ + HatCoords *hc; + va_list ap; + + va_start(ap, type); + hc = hc_construct_v(type, ap); + va_end(ap); + + return hc; +} + +static bool hc_equal(HatCoords *hc1, HatCoords *hc2) +{ + size_t i; + + if (hc1->nc != hc2->nc) + return false; + + for (i = 0; i < hc1->nc; i++) { + if (hc1->c[i].type != hc2->c[i].type || + hc1->c[i].index != hc2->c[i].index) + return false; + } + + return true; +} + +static bool hc_expect(const char *file, int line, HatCoords *hc, + TileType type, ...) +{ + bool equal; + va_list ap; + HatCoords *hce; + + va_start(ap, type); + hce = hc_construct_v(type, ap); + va_end(ap); + + equal = hc_equal(hc, hce); + + if (!equal) { + fprintf(stderr, "%s:%d: coordinate mismatch\n", file, line); + debug_coords(" expected: ", hce, "\n"); + debug_coords(" actual: ", hc, "\n"); + } + + hc_free(hce); + return equal; +} + +#define EXPECT(hc, ...) do { \ + if (!hc_expect(__FILE__, __LINE__, hc, __VA_ARGS__)) \ + fails++; \ + } while (0) + +static bool unit_tests(void) +{ + int fails = 0; + HatCoordContext ctx[1]; + HatCoords *hc_in, *hc_out; + + ctx->rs = NULL; + ctx->prototype = hc_construct(TT_KITE, 0, TT_HAT, 0, TT_H, -1); + + /* Simple steps within a hat */ + + hc_in = hc_construct(TT_KITE, 6, TT_HAT, 2, TT_H, 1, TT_H, -1); + hc_out = step_coords(ctx, hc_in, KS_LEFT); + EXPECT(hc_out, TT_KITE, 5, TT_HAT, 2, TT_H, 1, TT_H, -1); + hc_free(hc_in); + hc_free(hc_out); + + hc_in = hc_construct(TT_KITE, 6, TT_HAT, 2, TT_H, 1, TT_H, -1); + hc_out = step_coords(ctx, hc_in, KS_RIGHT); + EXPECT(hc_out, TT_KITE, 7, TT_HAT, 2, TT_H, 1, TT_H, -1); + hc_free(hc_in); + hc_free(hc_out); + + hc_in = hc_construct(TT_KITE, 5, TT_HAT, 2, TT_H, 1, TT_H, -1); + hc_out = step_coords(ctx, hc_in, KS_F_LEFT); + EXPECT(hc_out, TT_KITE, 2, TT_HAT, 2, TT_H, 1, TT_H, -1); + hc_free(hc_in); + hc_free(hc_out); + + hc_in = hc_construct(TT_KITE, 5, TT_HAT, 2, TT_H, 1, TT_H, -1); + hc_out = step_coords(ctx, hc_in, KS_F_RIGHT); + EXPECT(hc_out, TT_KITE, 1, TT_HAT, 2, TT_H, 1, TT_H, -1); + hc_free(hc_in); + hc_free(hc_out); + + /* Step between hats in the same kitemap, which can change the + * metatile type at layer 2 */ + + hc_in = hc_construct(TT_KITE, 6, TT_HAT, 2, TT_H, 1, TT_H, -1); + hc_out = step_coords(ctx, hc_in, KS_F_LEFT); + EXPECT(hc_out, TT_KITE, 3, TT_HAT, 0, TT_H, 0, TT_H, -1); + hc_free(hc_in); + hc_free(hc_out); + + hc_in = hc_construct(TT_KITE, 7, TT_HAT, 2, TT_H, 1, TT_H, -1); + hc_out = step_coords(ctx, hc_in, KS_F_RIGHT); + EXPECT(hc_out, TT_KITE, 4, TT_HAT, 0, TT_T, 3, TT_H, -1); + hc_free(hc_in); + hc_free(hc_out); + + /* Step off the edge of one kitemap, necessitating a metamap + * rewrite of layers 2,3 to get into a different kitemap where + * that step can be made */ + + hc_in = hc_construct(TT_KITE, 6, TT_HAT, 0, TT_P, 2, TT_P, 3, TT_P, -1); + hc_out = step_coords(ctx, hc_in, KS_F_RIGHT); + /* Working: + * kite 6 . hat 0 . P 2 . P 3 . P ? + * -> kite 6 . hat 0 . P 6 . H 0 . P ? (P metamap says 2.3 = 6.0) + */ + EXPECT(hc_out, TT_KITE, 7, TT_HAT, 1, TT_H, 1, TT_H, 0, TT_P, -1); + hc_free(hc_in); + hc_free(hc_out); + + cleanup_coords(ctx); + return fails == 0; +} + +typedef struct pspoint { + float x, y; +} pspoint; + +static inline pspoint pscoords(Point p) +{ + pspoint q = { p.x + p.y / 2.0F, p.y * sqrt(0.75) }; + return q; +} + +typedef struct psbbox { + bool started; + pspoint bl, tr; +} psbbox; + +static inline void psbbox_add(psbbox *bbox, pspoint p) +{ + if (!bbox->started || bbox->bl.x > p.x) + bbox->bl.x = p.x; + if (!bbox->started || bbox->tr.x < p.x) + bbox->tr.x = p.x; + if (!bbox->started || bbox->bl.y > p.y) + bbox->bl.y = p.y; + if (!bbox->started || bbox->tr.y < p.y) + bbox->tr.y = p.y; + bbox->started = true; +} + +static void header(psbbox *bbox) +{ + float xext = bbox->tr.x - bbox->bl.x, yext = bbox->tr.y - bbox->bl.y; + float ext = (xext > yext ? xext : yext); + float scale = 500 / ext; + float ox = 287 - scale * (bbox->bl.x + bbox->tr.x) / 2; + float oy = 421 - scale * (bbox->bl.y + bbox->tr.y) / 2; + + printf("%%!PS-Adobe-2.0\n%%%%Creator: hat-test from Simon Tatham's " + "Portable Puzzle Collection\n%%%%Pages: 1\n" + "%%%%BoundingBox: %f %f %f %f\n" + "%%%%EndComments\n%%%%Page: 1 1\n", + ox + scale * bbox->bl.x - 20, oy + scale * bbox->bl.y - 20, + ox + scale * bbox->tr.x + 20, oy + scale * bbox->tr.y + 20); + + printf("%f %f translate %f dup scale\n", ox, oy, scale); + printf("%f setlinewidth\n", 0.1); + printf("/thick { %f setlinewidth } def\n", 0.7); + printf("0 setgray 1 setlinejoin 1 setlinecap\n"); +} + +static void bbox_add_kite(Kite k, psbbox *bbox) +{ + pspoint p[4]; + size_t i; + + p[0] = pscoords(k.centre); + p[1] = pscoords(k.left); + p[2] = pscoords(k.outer); + p[3] = pscoords(k.right); + + for (i = 0; i < 4; i++) + psbbox_add(bbox, p[i]); +} + +static void fill_kite(Kite k, HatCoords *hc) +{ + pspoint p[4]; + size_t i; + + p[0] = pscoords(k.centre); + p[1] = pscoords(k.left); + p[2] = pscoords(k.outer); + p[3] = pscoords(k.right); + + printf("newpath"); + for (i = 0; i < 4; i++) + printf(" %f %f %s", p[i].x, p[i].y, i ? "lineto" : "moveto"); + printf(" closepath gsave"); + if (hc) { + const char *colour = "0 setgray"; + if (hc->c[2].type == TT_H) { + colour = (hc->c[1].index == 3 ? "0 0.5 0.8 setrgbcolor" : + "0.6 0.8 1 setrgbcolor"); + } else if (hc->c[2].type == TT_F) { + colour = "0.7 setgray"; + } else { + colour = "1 setgray"; + } + printf(" %s fill grestore\n", colour); + } +} + +static void stroke_kite(Kite k, HatCoords *hc) +{ + pspoint p[4]; + size_t i; + + p[0] = pscoords(k.centre); + p[1] = pscoords(k.left); + p[2] = pscoords(k.outer); + p[3] = pscoords(k.right); + + printf("newpath"); + for (i = 0; i < 4; i++) + printf(" %f %f %s", p[i].x, p[i].y, i ? "lineto" : "moveto"); + printf(" closepath"); + printf(" stroke\n"); + + if (hc->c[2].type == TT_H && hc->c[1].index == 3) { + pspoint t = p[1]; p[1] = p[3]; p[3] = t; + } + #define LINE(a,b) printf("gsave newpath %f %f moveto %f %f lineto thick " \ + "stroke grestore\n", p[a].x, p[a].y, p[b].x, p[b].y) + switch (hc->c[0].index) { + case 0: LINE(1, 2); LINE(2, 3); LINE(3, 0); break; + case 1: LINE(0, 1); break; + case 2: LINE(0, 1); break; + case 3: LINE(2, 3); LINE(3, 0); break; + case 4: LINE(0, 1); LINE(1, 2); break; + case 6: LINE(1, 2); LINE(2, 3); break; + case 7: LINE(1, 2); LINE(2, 3); LINE(3, 0); break; + } + #undef LINE +} + +static void trailer(void) +{ + printf("showpage\n"); + printf("%%%%Trailer\n"); + printf("%%%%EOF\n"); +} + +int main(int argc, char **argv) +{ + psbbox bbox[1]; + KiteEnum s[1]; + HatCoordContext ctx[1]; + HatCoords *coords[KE_NKEEP]; + random_state *rs = random_new("12345", 5); + int w = 10, h = 10; + size_t i; + + if (argc > 1 && !strcmp(argv[1], "--test")) { + return unit_tests() ? 0 : 1; + } + + for (i = 0; i < lenof(coords); i++) + coords[i] = NULL; + + init_coords_random(ctx, rs); + + bbox->started = false; + + first_kite(s, w, h); + coords[s->curr_index] = initial_coords(ctx); + bbox_add_kite(*s->curr, bbox); + while (next_kite(s)) { + hc_free(coords[s->curr_index]); + coords[s->curr_index] = step_coords( + ctx, coords[s->last_index], s->last_step); + bbox_add_kite(*s->curr, bbox); + } + for (i = 0; i < lenof(coords); i++) { + hc_free(coords[i]); + coords[i] = NULL; + } + + header(bbox); + + first_kite(s, w, h); + coords[s->curr_index] = initial_coords(ctx); + fill_kite(*s->curr, coords[s->curr_index]); + while (next_kite(s)) { + hc_free(coords[s->curr_index]); + coords[s->curr_index] = step_coords( + ctx, coords[s->last_index], s->last_step); + fill_kite(*s->curr, coords[s->curr_index]); + } + for (i = 0; i < lenof(coords); i++) { + hc_free(coords[i]); + coords[i] = NULL; + } + + first_kite(s, w, h); + coords[s->curr_index] = initial_coords(ctx); + stroke_kite(*s->curr, coords[s->curr_index]); + while (next_kite(s)) { + hc_free(coords[s->curr_index]); + coords[s->curr_index] = step_coords( + ctx, coords[s->last_index], s->last_step); + stroke_kite(*s->curr, coords[s->curr_index]); + } + for (i = 0; i < lenof(coords); i++) { + hc_free(coords[i]); + coords[i] = NULL; + } + + trailer(); + + cleanup_coords(ctx); + + return 0; +} +#endif diff --git a/hat.h b/hat.h new file mode 100644 index 0000000..39e2d31 --- /dev/null +++ b/hat.h @@ -0,0 +1,67 @@ +#ifndef PUZZLES_HAT_H +#define PUZZLES_HAT_H + +struct HatPatchParams { + /* + * A patch of hat tiling is identified by giving the coordinates + * of the kite in one corner, using a multi-level coordinate + * system based on metatile expansions. Coordinates are a sequence + * of small non-negative integers. The valid range for each + * coordinate depends on the next coordinate, or on final_metatile + * if it's the last one in the list. The largest valid range is + * {0,...,12}. + * + * 'final_metatile' is one of the characters 'H', 'T', 'P' or 'F'. + */ + size_t ncoords; + unsigned char *coords; + char final_metatile; +}; + +/* + * Fill in HatPatchParams with a randomly selected set of coordinates, + * in enough detail to generate a patch of tiling covering an area of + * w x h 'squares' of a kite tiling. + * + * The kites grid is considered to be oriented so that it includes + * horizontal lines and not vertical ones. So each of the smallest + * equilateral triangles in the grid has a bounding rectangle whose + * height is sqrt(3)/2 times its width, and either the top or the + * bottom of that bounding rectangle is the horizontal edge of the + * triangle. A 'square' of a kite tiling (for convenience of choosing + * grid dimensions) counts as one of those bounding rectangles. + * + * The 'coords' field of the structure will be filled in with a new + * dynamically allocated array. Any previous pointer in that field + * will be overwritten. + */ +void hat_tiling_randomise(struct HatPatchParams *params, int w, int h, + random_state *rs); + +/* + * Validate a HatPatchParams to ensure it contains no illegal + * coordinates. Returns NULL if it's acceptable, or an error string if + * not. + */ +const char *hat_tiling_params_invalid(const struct HatPatchParams *params); + +/* + * Generate the actual set of hat tiles from a HatPatchParams, passing + * each one to a callback. The callback receives the vertices of each + * point, as a sequence of 2*nvertices integers, with x,y coordinates + * interleaved. + * + * The x coordinates are measured in units of 1/4 of the side length + * of the smallest equilateral triangle, or equivalently, 1/2 the + * length of one of the long edges of a single kite. The y coordinates + * are measured in units of 1/6 the height of the triangle, which is + * also 1/2 the length of the short edge of a kite. Therefore, you can + * expect x to go up to 4*w and y up to 6*h. + */ +typedef void (*hat_tile_callback_fn)(void *ctx, size_t nvertices, + int *coords); + +void hat_tiling_generate(const struct HatPatchParams *params, int w, int h, + hat_tile_callback_fn cb, void *cbctx); + +#endif diff --git a/loopy.c b/loopy.c index c627f2b..86f6d5e 100644 --- a/loopy.c +++ b/loopy.c @@ -280,6 +280,7 @@ static void check_caches(const solver_state* sstate); A("Great-Great-Dodecagonal",GREATGREATDODECAGONAL,2,2) \ A("Kagome",KAGOME,3,3) \ A("Compass-Dodecagonal",COMPASSDODECAGONAL,2,2) \ + A("Hats",HATS,6,6) \ /* end of list */ #define GRID_NAME(title,type,amin,omin) title, @@ -564,6 +565,7 @@ static const game_params loopy_presets_more[] = { { 5, 4, DIFF_HARD, LOOPY_GRID_GREATDODECAGONAL }, { 5, 3, DIFF_HARD, LOOPY_GRID_GREATGREATDODECAGONAL }, { 5, 4, DIFF_HARD, LOOPY_GRID_COMPASSDODECAGONAL }, + { 10, 10, DIFF_HARD, LOOPY_GRID_HATS }, #endif }; @@ -2299,7 +2301,7 @@ static int dline_deductions(solver_state *sstate) * on that. We check this with an assertion, in case someone decides to * make a grid which has larger faces than this. Note, this algorithm * could get quite expensive if there are many large faces. */ -#define MAX_FACE_SIZE 12 +#define MAX_FACE_SIZE 14 for (i = 0; i < g->num_faces; i++) { int maxs[MAX_FACE_SIZE][MAX_FACE_SIZE];