diff options
Diffstat (limited to 'apps/plugins/puzzles/src/hat.c')
-rw-r--r-- | apps/plugins/puzzles/src/hat.c | 891 |
1 files changed, 891 insertions, 0 deletions
diff --git a/apps/plugins/puzzles/src/hat.c b/apps/plugins/puzzles/src/hat.c new file mode 100644 index 0000000000..176d1f049e --- /dev/null +++ b/apps/plugins/puzzles/src/hat.c | |||
@@ -0,0 +1,891 @@ | |||
1 | /* | ||
2 | * Code to generate patches of the aperiodic 'hat' tiling discovered | ||
3 | * in 2023. | ||
4 | * | ||
5 | * This uses the 'combinatorial coordinates' system documented in my | ||
6 | * public article | ||
7 | * https://www.chiark.greenend.org.uk/~sgtatham/quasiblog/aperiodic-tilings/ | ||
8 | * | ||
9 | * The internal document auxiliary/doc/hats.html also contains an | ||
10 | * explanation of the basic ideas of this algorithm (less polished but | ||
11 | * containing more detail). | ||
12 | * | ||
13 | * Neither of those documents can really be put in a source file, | ||
14 | * because they just have too many complicated diagrams. So read at | ||
15 | * least one of those first; the comments in here will refer to it. | ||
16 | * | ||
17 | * Discoverers' website: https://cs.uwaterloo.ca/~csk/hat/ | ||
18 | * Preprint of paper: https://arxiv.org/abs/2303.10798 | ||
19 | */ | ||
20 | |||
21 | #include <assert.h> | ||
22 | #ifdef NO_TGMATH_H | ||
23 | # include <math.h> | ||
24 | #else | ||
25 | # include <tgmath.h> | ||
26 | #endif | ||
27 | #include <stdbool.h> | ||
28 | #include <stdio.h> | ||
29 | #include <stdlib.h> | ||
30 | #include <string.h> | ||
31 | |||
32 | #include "puzzles.h" | ||
33 | #include "hat.h" | ||
34 | #include "hat-internal.h" | ||
35 | |||
36 | void hat_kiteenum_first(KiteEnum *s, int w, int h) | ||
37 | { | ||
38 | Kite start = { {0,0}, {0, 3}, {3, 0}, {2, 2} }; | ||
39 | size_t i; | ||
40 | |||
41 | for (i = 0; i < KE_NKEEP; i++) | ||
42 | s->recent[i] = start; /* initialise to *something* */ | ||
43 | s->curr_index = 0; | ||
44 | s->curr = &s->recent[s->curr_index]; | ||
45 | s->state = 1; | ||
46 | s->w = w; | ||
47 | s->h = h; | ||
48 | s->x = 0; | ||
49 | s->y = 0; | ||
50 | } | ||
51 | |||
52 | bool hat_kiteenum_next(KiteEnum *s) | ||
53 | { | ||
54 | unsigned lastbut1 = s->last_index; | ||
55 | s->last_index = s->curr_index; | ||
56 | s->curr_index = (s->curr_index + 1) % KE_NKEEP; | ||
57 | s->curr = &s->recent[s->curr_index]; | ||
58 | |||
59 | switch (s->state) { | ||
60 | /* States 1,2,3 walk rightwards along the upper side of a | ||
61 | * horizontal grid line with a pointy kite end at the start | ||
62 | * point */ | ||
63 | case 1: | ||
64 | s->last_step = KS_F_RIGHT; | ||
65 | s->state = 2; | ||
66 | break; | ||
67 | |||
68 | case 2: | ||
69 | if (s->x+1 >= s->w) { | ||
70 | s->last_step = KS_F_RIGHT; | ||
71 | s->state = 4; | ||
72 | break; | ||
73 | } | ||
74 | s->last_step = KS_RIGHT; | ||
75 | s->state = 3; | ||
76 | s->x++; | ||
77 | break; | ||
78 | |||
79 | case 3: | ||
80 | s->last_step = KS_RIGHT; | ||
81 | s->state = 1; | ||
82 | break; | ||
83 | |||
84 | /* State 4 is special: we've just moved up into a row below a | ||
85 | * grid line, but we can't produce the rightmost tile of that | ||
86 | * row because it's not adjacent any tile so far emitted. So | ||
87 | * instead, emit the second-rightmost tile, and next time, | ||
88 | * we'll emit the rightmost. */ | ||
89 | case 4: | ||
90 | s->last_step = KS_LEFT; | ||
91 | s->state = 5; | ||
92 | break; | ||
93 | |||
94 | /* And now we have to emit the third-rightmost tile relative | ||
95 | * to the last but one tile we emitted (the one from state 2, | ||
96 | * not state 4). */ | ||
97 | case 5: | ||
98 | s->last_step = KS_RIGHT; | ||
99 | s->last_index = lastbut1; | ||
100 | s->state = 6; | ||
101 | break; | ||
102 | |||
103 | /* Now states 6-8 handle the general case of walking leftwards | ||
104 | * along the lower side of a line, starting from a | ||
105 | * right-angled kite end. */ | ||
106 | case 6: | ||
107 | if (s->x <= 0) { | ||
108 | if (s->y+1 >= s->h) { | ||
109 | s->state = 0; | ||
110 | return false; | ||
111 | } | ||
112 | s->last_step = KS_RIGHT; | ||
113 | s->state = 9; | ||
114 | s->y++; | ||
115 | break; | ||
116 | } | ||
117 | s->last_step = KS_F_RIGHT; | ||
118 | s->state = 7; | ||
119 | s->x--; | ||
120 | break; | ||
121 | |||
122 | case 7: | ||
123 | s->last_step = KS_RIGHT; | ||
124 | s->state = 8; | ||
125 | break; | ||
126 | |||
127 | case 8: | ||
128 | s->last_step = KS_RIGHT; | ||
129 | s->state = 6; | ||
130 | break; | ||
131 | |||
132 | /* States 9,10,11 walk rightwards along the upper side of a | ||
133 | * horizontal grid line with a right-angled kite end at the | ||
134 | * start point. This time there's no awkward transition from | ||
135 | * the previous row. */ | ||
136 | case 9: | ||
137 | s->last_step = KS_RIGHT; | ||
138 | s->state = 10; | ||
139 | break; | ||
140 | |||
141 | case 10: | ||
142 | s->last_step = KS_RIGHT; | ||
143 | s->state = 11; | ||
144 | break; | ||
145 | |||
146 | case 11: | ||
147 | if (s->x+1 >= s->w) { | ||
148 | /* Another awkward transition to the next row, where we | ||
149 | * have to generate it based on the previous state-9 tile. | ||
150 | * But this time at least we generate the rightmost tile | ||
151 | * of the new row, so the next states will be simple. */ | ||
152 | s->last_step = KS_F_RIGHT; | ||
153 | s->last_index = lastbut1; | ||
154 | s->state = 12; | ||
155 | break; | ||
156 | } | ||
157 | s->last_step = KS_F_RIGHT; | ||
158 | s->state = 9; | ||
159 | s->x++; | ||
160 | break; | ||
161 | |||
162 | /* States 12,13,14 walk leftwards along the upper edge of a | ||
163 | * horizontal grid line with a pointy kite end at the start | ||
164 | * point */ | ||
165 | case 12: | ||
166 | s->last_step = KS_F_RIGHT; | ||
167 | s->state = 13; | ||
168 | break; | ||
169 | |||
170 | case 13: | ||
171 | if (s->x <= 0) { | ||
172 | if (s->y+1 >= s->h) { | ||
173 | s->state = 0; | ||
174 | return false; | ||
175 | } | ||
176 | s->last_step = KS_LEFT; | ||
177 | s->state = 1; | ||
178 | s->y++; | ||
179 | break; | ||
180 | } | ||
181 | s->last_step = KS_RIGHT; | ||
182 | s->state = 14; | ||
183 | s->x--; | ||
184 | break; | ||
185 | |||
186 | case 14: | ||
187 | s->last_step = KS_RIGHT; | ||
188 | s->state = 12; | ||
189 | break; | ||
190 | |||
191 | default: | ||
192 | return false; | ||
193 | } | ||
194 | |||
195 | *s->curr = kite_step(s->recent[s->last_index], s->last_step); | ||
196 | return true; | ||
197 | } | ||
198 | |||
199 | /* | ||
200 | * The actual tables. | ||
201 | */ | ||
202 | #include "hat-tables.h" | ||
203 | |||
204 | /* | ||
205 | * One set of tables that we write by hand: the permitted ways to | ||
206 | * extend the coordinate system outwards from a given metatile. | ||
207 | * | ||
208 | * One obvious approach would be to make a table of all the places | ||
209 | * each metatile can appear in the expansion of another (e.g. H can be | ||
210 | * subtile 0, 1 or 2 of another H, subtile 0 of a T, or 0 or 1 of a P | ||
211 | * or an F), and when we need to decide what our current topmost tile | ||
212 | * turns out to be a subtile of, choose equiprobably at random from | ||
213 | * those options. | ||
214 | * | ||
215 | * That's what I did originally, but a better approach is to skew the | ||
216 | * probabilities. We'd like to generate our patch of actual tiling | ||
217 | * uniformly at random, in the sense that if you selected uniformly | ||
218 | * from a very large region of the plane, the distribution of possible | ||
219 | * finite patches of tiling would converge to some limit as that | ||
220 | * region tended to infinity, and we'd be picking from that limiting | ||
221 | * distribution on finite patches. | ||
222 | * | ||
223 | * For this we have to refer back to the original paper, which | ||
224 | * indicates the subset of each metatile's expansion that can be | ||
225 | * considered to 'belong' to that metatile, such that every subtile | ||
226 | * belongs to exactly one parent metatile, and the overlaps are | ||
227 | * eliminated. Reading out the diagrams from their Figure 2.8: | ||
228 | * | ||
229 | * - H: we discard three of the outer F subtiles, in the symmetric | ||
230 | * positions index by our coordinates as 7, 10, 11. So we keep the | ||
231 | * remaining subtiles {0,1,2,3,4,5,6,8,9,12}, which consist of | ||
232 | * three H, one T, three P and three F. | ||
233 | * | ||
234 | * - T: only the central H expanded from a T is considered to belong | ||
235 | * to it, so we just keep {0}, a single H. | ||
236 | * | ||
237 | * - P: we discard everything intersected by a long edge of the | ||
238 | * parallelogram, leaving the central three tiles and the endmost | ||
239 | * pair of F. That is, we keep {0,1,4,5,10}, consisting of two H, | ||
240 | * one P and two F. | ||
241 | * | ||
242 | * - F: looks like P at one end, and we retain the corresponding set | ||
243 | * of tiles there, but at the other end we keep the two F on either | ||
244 | * side of the endmost one. So we keep {0,1,3,6,8,10}, consisting of | ||
245 | * two H, one P and _three_ F. | ||
246 | * | ||
247 | * Adding up the tile numbers gives us this matrix system: | ||
248 | * | ||
249 | * (H_1) (3 1 2 2)(H_0) | ||
250 | * (T_1) = (1 0 0 0)(T_0) | ||
251 | * (P_1) (3 0 1 1)(P_0) | ||
252 | * (F_1) (3 0 2 3)(F_0) | ||
253 | * | ||
254 | * which says that if you have a patch of metatiling consisting of H_0 | ||
255 | * H tiles, T_0 T tiles etc, then this matrix shows the number H_1 of | ||
256 | * smaller H tiles, etc, expanded from it. | ||
257 | * | ||
258 | * If you expand _many_ times, that's equivalent to raising the matrix | ||
259 | * to a power: | ||
260 | * | ||
261 | * n | ||
262 | * (H_n) (3 1 2 2) (H_0) | ||
263 | * (T_n) = (1 0 0 0) (T_0) | ||
264 | * (P_n) (3 0 1 1) (P_0) | ||
265 | * (F_n) (3 0 2 3) (F_0) | ||
266 | * | ||
267 | * The limiting distribution of metatiles is obtained by looking at | ||
268 | * the four-way ratio between H_n, T_n, P_n and F_n as n tends to | ||
269 | * infinity. To calculate this, we find the eigenvalues and | ||
270 | * eigenvectors of the matrix, and extract the eigenvector | ||
271 | * corresponding to the eigenvalue of largest magnitude. (Things get | ||
272 | * more complicated in cases where there isn't a _unique_ eigenvalue | ||
273 | * of largest magnitude, but here, there is.) | ||
274 | * | ||
275 | * That eigenvector is | ||
276 | * | ||
277 | * [ 1 ] [ 1 ] | ||
278 | * [ (7 - 3 sqrt(5)) / 2 ] ~= [ 0.14589803375031545538 ] | ||
279 | * [ 3 sqrt(5) - 6 ] [ 0.70820393249936908922 ] | ||
280 | * [ (9 - 3 sqrt(5)) / 2 ] [ 1.14589803375031545538 ] | ||
281 | * | ||
282 | * So those are the limiting relative proportions of metatiles. | ||
283 | * | ||
284 | * So if we have a particular metatile, how likely is it for its | ||
285 | * parent to be one of those? We have to adjust by the number of | ||
286 | * metatiles of each type that each tile has as its children. For | ||
287 | * example, the P and F tiles have one P child each, but the H has | ||
288 | * three P children. So if we have a P, the proportion of H in its | ||
289 | * potential ancestry is three times what's shown here. (And T can't | ||
290 | * occur at all as a parent.) | ||
291 | * | ||
292 | * In other words, we should choose _each coordinate_ with probability | ||
293 | * corresponding to one of those numbers (scaled down so they all sum | ||
294 | * to 1). Continuing to use P as an example, it will be: | ||
295 | * | ||
296 | * - child 4 of H with relative probability 1 | ||
297 | * - child 5 of H with relative probability 1 | ||
298 | * - child 6 of H with relative probability 1 | ||
299 | * - child 4 of P with relative probability 0.70820393249936908922 | ||
300 | * - child 3 of F with relative probability 1.14589803375031545538 | ||
301 | * | ||
302 | * and then we obtain the true probabilities by scaling those values | ||
303 | * down so that they sum to 1. | ||
304 | * | ||
305 | * The tables below give a reasonable approximation in 32-bit | ||
306 | * integers to these proportions. | ||
307 | */ | ||
308 | |||
309 | typedef struct MetatilePossibleParent { | ||
310 | TileType type; | ||
311 | unsigned index; | ||
312 | unsigned long probability; | ||
313 | } MetatilePossibleParent; | ||
314 | |||
315 | /* The above probabilities scaled up by 10000000 */ | ||
316 | #define PROB_H 10000000 | ||
317 | #define PROB_T 1458980 | ||
318 | #define PROB_P 7082039 | ||
319 | #define PROB_F 11458980 | ||
320 | |||
321 | static const MetatilePossibleParent parents_H[] = { | ||
322 | { TT_H, 0, PROB_H }, | ||
323 | { TT_H, 1, PROB_H }, | ||
324 | { TT_H, 2, PROB_H }, | ||
325 | { TT_T, 0, PROB_T }, | ||
326 | { TT_P, 0, PROB_P }, | ||
327 | { TT_P, 1, PROB_P }, | ||
328 | { TT_F, 0, PROB_F }, | ||
329 | { TT_F, 1, PROB_F }, | ||
330 | }; | ||
331 | static const MetatilePossibleParent parents_T[] = { | ||
332 | { TT_H, 3, PROB_H }, | ||
333 | }; | ||
334 | static const MetatilePossibleParent parents_P[] = { | ||
335 | { TT_H, 4, PROB_H }, | ||
336 | { TT_H, 5, PROB_H }, | ||
337 | { TT_H, 6, PROB_H }, | ||
338 | { TT_P, 4, PROB_P }, | ||
339 | { TT_F, 3, PROB_F }, | ||
340 | }; | ||
341 | static const MetatilePossibleParent parents_F[] = { | ||
342 | { TT_H, 8, PROB_H }, | ||
343 | { TT_H, 9, PROB_H }, | ||
344 | { TT_H, 12, PROB_H }, | ||
345 | { TT_P, 5, PROB_P }, | ||
346 | { TT_P, 10, PROB_P }, | ||
347 | { TT_F, 6, PROB_F }, | ||
348 | { TT_F, 8, PROB_F }, | ||
349 | { TT_F, 10, PROB_F }, | ||
350 | }; | ||
351 | |||
352 | static const MetatilePossibleParent *const possible_parents[] = { | ||
353 | parents_H, parents_T, parents_P, parents_F, | ||
354 | }; | ||
355 | static const size_t n_possible_parents[] = { | ||
356 | lenof(parents_H), lenof(parents_T), lenof(parents_P), lenof(parents_F), | ||
357 | }; | ||
358 | |||
359 | /* | ||
360 | * Similarly, we also want to choose our absolute starting hat with | ||
361 | * close to uniform probability, which again we do by looking at the | ||
362 | * limiting ratio of the metatile types, and this time, scaling by the | ||
363 | * number of hats in each metatile. | ||
364 | * | ||
365 | * We cheatingly use the same MetatilePossibleParent struct, because | ||
366 | * it's got all the right fields, even if it has an inappropriate | ||
367 | * name. | ||
368 | */ | ||
369 | static const MetatilePossibleParent starting_hats[] = { | ||
370 | { TT_H, 0, PROB_H }, | ||
371 | { TT_H, 1, PROB_H }, | ||
372 | { TT_H, 2, PROB_H }, | ||
373 | { TT_H, 3, PROB_H }, | ||
374 | { TT_T, 0, PROB_P }, | ||
375 | { TT_P, 0, PROB_P }, | ||
376 | { TT_P, 1, PROB_P }, | ||
377 | { TT_F, 0, PROB_F }, | ||
378 | { TT_F, 1, PROB_F }, | ||
379 | }; | ||
380 | |||
381 | #undef PROB_H | ||
382 | #undef PROB_T | ||
383 | #undef PROB_P | ||
384 | #undef PROB_F | ||
385 | |||
386 | HatCoords *hat_coords_new(void) | ||
387 | { | ||
388 | HatCoords *hc = snew(HatCoords); | ||
389 | hc->nc = hc->csize = 0; | ||
390 | hc->c = NULL; | ||
391 | return hc; | ||
392 | } | ||
393 | |||
394 | void hat_coords_free(HatCoords *hc) | ||
395 | { | ||
396 | if (hc) { | ||
397 | sfree(hc->c); | ||
398 | sfree(hc); | ||
399 | } | ||
400 | } | ||
401 | |||
402 | void hat_coords_make_space(HatCoords *hc, size_t size) | ||
403 | { | ||
404 | if (hc->csize < size) { | ||
405 | hc->csize = hc->csize * 5 / 4 + 16; | ||
406 | if (hc->csize < size) | ||
407 | hc->csize = size; | ||
408 | hc->c = sresize(hc->c, hc->csize, HatCoord); | ||
409 | } | ||
410 | } | ||
411 | |||
412 | HatCoords *hat_coords_copy(HatCoords *hc_in) | ||
413 | { | ||
414 | HatCoords *hc_out = hat_coords_new(); | ||
415 | hat_coords_make_space(hc_out, hc_in->nc); | ||
416 | memcpy(hc_out->c, hc_in->c, hc_in->nc * sizeof(*hc_out->c)); | ||
417 | hc_out->nc = hc_in->nc; | ||
418 | return hc_out; | ||
419 | } | ||
420 | |||
421 | static const MetatilePossibleParent *choose_mpp( | ||
422 | random_state *rs, const MetatilePossibleParent *parents, size_t nparents) | ||
423 | { | ||
424 | /* | ||
425 | * If we needed to do this _efficiently_, we'd rewrite all those | ||
426 | * tables above as cumulative frequency tables and use binary | ||
427 | * search. But this happens about log n times in a grid of area n, | ||
428 | * so it hardly matters, and it's easier to keep the tables | ||
429 | * legible. | ||
430 | */ | ||
431 | unsigned long limit = 0, value; | ||
432 | size_t i; | ||
433 | |||
434 | for (i = 0; i < nparents; i++) | ||
435 | limit += parents[i].probability; | ||
436 | |||
437 | value = random_upto(rs, limit); | ||
438 | |||
439 | for (i = 0; i+1 < nparents; i++) { | ||
440 | if (value < parents[i].probability) | ||
441 | return &parents[i]; | ||
442 | value -= parents[i].probability; | ||
443 | } | ||
444 | |||
445 | assert(i == nparents - 1); | ||
446 | assert(value < parents[i].probability); | ||
447 | return &parents[i]; | ||
448 | } | ||
449 | void hatctx_init_random(HatContext *ctx, random_state *rs) | ||
450 | { | ||
451 | const MetatilePossibleParent *starting_hat = choose_mpp( | ||
452 | rs, starting_hats, lenof(starting_hats)); | ||
453 | |||
454 | ctx->rs = rs; | ||
455 | ctx->prototype = hat_coords_new(); | ||
456 | hat_coords_make_space(ctx->prototype, 3); | ||
457 | ctx->prototype->c[2].type = starting_hat->type; | ||
458 | ctx->prototype->c[2].index = -1; | ||
459 | ctx->prototype->c[1].type = TT_HAT; | ||
460 | ctx->prototype->c[1].index = starting_hat->index; | ||
461 | ctx->prototype->c[0].type = TT_KITE; | ||
462 | ctx->prototype->c[0].index = random_upto(rs, HAT_KITES); | ||
463 | ctx->prototype->nc = 3; | ||
464 | } | ||
465 | |||
466 | static inline int metatile_char_to_enum(char metatile) | ||
467 | { | ||
468 | return (metatile == 'H' ? TT_H : | ||
469 | metatile == 'T' ? TT_T : | ||
470 | metatile == 'P' ? TT_P : | ||
471 | metatile == 'F' ? TT_F : -1); | ||
472 | } | ||
473 | |||
474 | static void init_coords_params(HatContext *ctx, | ||
475 | const struct HatPatchParams *hp) | ||
476 | { | ||
477 | size_t i; | ||
478 | |||
479 | ctx->rs = NULL; | ||
480 | ctx->prototype = hat_coords_new(); | ||
481 | |||
482 | assert(hp->ncoords >= 3); | ||
483 | |||
484 | hat_coords_make_space(ctx->prototype, hp->ncoords + 1); | ||
485 | ctx->prototype->nc = hp->ncoords + 1; | ||
486 | |||
487 | for (i = 0; i < hp->ncoords; i++) | ||
488 | ctx->prototype->c[i].index = hp->coords[i]; | ||
489 | |||
490 | ctx->prototype->c[hp->ncoords].type = | ||
491 | metatile_char_to_enum(hp->final_metatile); | ||
492 | ctx->prototype->c[hp->ncoords].index = -1; | ||
493 | |||
494 | ctx->prototype->c[0].type = TT_KITE; | ||
495 | ctx->prototype->c[1].type = TT_HAT; | ||
496 | |||
497 | for (i = hp->ncoords - 1; i > 1; i--) { | ||
498 | TileType metatile = ctx->prototype->c[i+1].type; | ||
499 | assert(hp->coords[i] < nchildren[metatile]); | ||
500 | ctx->prototype->c[i].type = children[metatile][hp->coords[i]]; | ||
501 | } | ||
502 | |||
503 | assert(hp->coords[0] < 8); | ||
504 | } | ||
505 | |||
506 | HatCoords *hatctx_initial_coords(HatContext *ctx) | ||
507 | { | ||
508 | return hat_coords_copy(ctx->prototype); | ||
509 | } | ||
510 | |||
511 | /* | ||
512 | * Extend hc until it has at least n coordinates in, by copying from | ||
513 | * ctx->prototype if needed, and extending ctx->prototype if needed in | ||
514 | * order to do that. | ||
515 | */ | ||
516 | void hatctx_extend_coords(HatContext *ctx, HatCoords *hc, size_t n) | ||
517 | { | ||
518 | if (ctx->prototype->nc < n) { | ||
519 | hat_coords_make_space(ctx->prototype, n); | ||
520 | while (ctx->prototype->nc < n) { | ||
521 | TileType type = ctx->prototype->c[ctx->prototype->nc - 1].type; | ||
522 | assert(ctx->prototype->c[ctx->prototype->nc - 1].index == -1); | ||
523 | const MetatilePossibleParent *parent; | ||
524 | |||
525 | if (ctx->rs) | ||
526 | parent = choose_mpp(ctx->rs, possible_parents[type], | ||
527 | n_possible_parents[type]); | ||
528 | else | ||
529 | parent = possible_parents[type]; | ||
530 | |||
531 | ctx->prototype->c[ctx->prototype->nc - 1].index = parent->index; | ||
532 | ctx->prototype->c[ctx->prototype->nc].index = -1; | ||
533 | ctx->prototype->c[ctx->prototype->nc].type = parent->type; | ||
534 | ctx->prototype->nc++; | ||
535 | } | ||
536 | } | ||
537 | |||
538 | hat_coords_make_space(hc, n); | ||
539 | while (hc->nc < n) { | ||
540 | assert(hc->c[hc->nc - 1].index == -1); | ||
541 | assert(hc->c[hc->nc - 1].type == ctx->prototype->c[hc->nc - 1].type); | ||
542 | hc->c[hc->nc - 1].index = ctx->prototype->c[hc->nc - 1].index; | ||
543 | hc->c[hc->nc].index = -1; | ||
544 | hc->c[hc->nc].type = ctx->prototype->c[hc->nc].type; | ||
545 | hc->nc++; | ||
546 | } | ||
547 | } | ||
548 | |||
549 | void hatctx_cleanup(HatContext *ctx) | ||
550 | { | ||
551 | hat_coords_free(ctx->prototype); | ||
552 | } | ||
553 | |||
554 | /* | ||
555 | * The actual system for finding the coordinates of an adjacent kite. | ||
556 | */ | ||
557 | |||
558 | /* | ||
559 | * Kitemap step: ensure we have enough coordinates to know two levels | ||
560 | * of meta-tiling, and use the kite map for the outer layer to move | ||
561 | * around the individual kites. If this fails, return NULL. | ||
562 | */ | ||
563 | static HatCoords *try_step_coords_kitemap( | ||
564 | HatContext *ctx, HatCoords *hc_in, KiteStep step) | ||
565 | { | ||
566 | hatctx_extend_coords(ctx, hc_in, 4); | ||
567 | hat_coords_debug(" try kitemap ", hc_in, "\n"); | ||
568 | unsigned kite = hc_in->c[0].index; | ||
569 | unsigned hat = hc_in->c[1].index; | ||
570 | unsigned meta = hc_in->c[2].index; | ||
571 | TileType meta2type = hc_in->c[3].type; | ||
572 | const KitemapEntry *ke = &kitemap[meta2type][ | ||
573 | kitemap_index(step, kite, hat, meta)]; | ||
574 | if (ke->kite >= 0) { | ||
575 | /* | ||
576 | * Success! We've got coordinates for the next kite in this | ||
577 | * direction. | ||
578 | */ | ||
579 | HatCoords *hc_out = hat_coords_copy(hc_in); | ||
580 | |||
581 | hc_out->c[2].index = ke->meta; | ||
582 | hc_out->c[2].type = children[meta2type][ke->meta]; | ||
583 | hc_out->c[1].index = ke->hat; | ||
584 | hc_out->c[1].type = TT_HAT; | ||
585 | hc_out->c[0].index = ke->kite; | ||
586 | hc_out->c[0].type = TT_KITE; | ||
587 | |||
588 | hat_coords_debug(" success! ", hc_out, "\n"); | ||
589 | return hc_out; | ||
590 | } | ||
591 | |||
592 | return NULL; | ||
593 | } | ||
594 | |||
595 | /* | ||
596 | * Recursive metamap step. Try using the metamap to rewrite the | ||
597 | * coordinates at hc->c[depth] and hc->c[depth+1] (using the metamap | ||
598 | * for the tile type described in hc->c[depth+2]). If successful, | ||
599 | * recurse back down to see if this led to a successful step via the | ||
600 | * kitemap. If even that fails (so that we need to try a higher-order | ||
601 | * metamap rewrite), return NULL. | ||
602 | */ | ||
603 | static HatCoords *try_step_coords_metamap( | ||
604 | HatContext *ctx, HatCoords *hc_in, KiteStep step, size_t depth) | ||
605 | { | ||
606 | HatCoords *hc_tmp = NULL, *hc_out; | ||
607 | |||
608 | hatctx_extend_coords(ctx, hc_in, depth+3); | ||
609 | #ifdef HAT_COORDS_DEBUG | ||
610 | fprintf(stderr, " try meta %-4d", (int)depth); | ||
611 | hat_coords_debug("", hc_in, "\n"); | ||
612 | #endif | ||
613 | unsigned meta_orig = hc_in->c[depth].index; | ||
614 | unsigned meta2_orig = hc_in->c[depth+1].index; | ||
615 | TileType meta3type = hc_in->c[depth+2].type; | ||
616 | |||
617 | unsigned meta = meta_orig, meta2 = meta2_orig; | ||
618 | |||
619 | while (true) { | ||
620 | const MetamapEntry *me; | ||
621 | HatCoords *hc_curr = hc_tmp ? hc_tmp : hc_in; | ||
622 | |||
623 | if (depth > 2) | ||
624 | hc_out = try_step_coords_metamap(ctx, hc_curr, step, depth - 1); | ||
625 | else | ||
626 | hc_out = try_step_coords_kitemap(ctx, hc_curr, step); | ||
627 | if (hc_out) { | ||
628 | hat_coords_free(hc_tmp); | ||
629 | return hc_out; | ||
630 | } | ||
631 | |||
632 | me = &metamap[meta3type][metamap_index(meta, meta2)]; | ||
633 | assert(me->meta != -1); | ||
634 | if (me->meta == meta_orig && me->meta2 == meta2_orig) { | ||
635 | hat_coords_free(hc_tmp); | ||
636 | return NULL; | ||
637 | } | ||
638 | |||
639 | meta = me->meta; | ||
640 | meta2 = me->meta2; | ||
641 | |||
642 | /* | ||
643 | * We must do the rewrite in a copy of hc_in. It's not | ||
644 | * _necessarily_ obvious that that's the case (any successful | ||
645 | * rewrite leaves the coordinates still valid and still | ||
646 | * referring to the same kite, right?). But the problem is | ||
647 | * that we might do a rewrite at this level more than once, | ||
648 | * and in between, a metamap rewrite at the next level down | ||
649 | * might have modified _one_ of the two coordinates we're | ||
650 | * messing about with. So it's easiest to let the recursion | ||
651 | * just use a separate copy. | ||
652 | */ | ||
653 | if (!hc_tmp) | ||
654 | hc_tmp = hat_coords_copy(hc_in); | ||
655 | |||
656 | hc_tmp->c[depth+1].index = meta2; | ||
657 | hc_tmp->c[depth+1].type = children[meta3type][meta2]; | ||
658 | hc_tmp->c[depth].index = meta; | ||
659 | hc_tmp->c[depth].type = children[hc_tmp->c[depth+1].type][meta]; | ||
660 | |||
661 | hat_coords_debug(" rewritten -> ", hc_tmp, "\n"); | ||
662 | } | ||
663 | } | ||
664 | |||
665 | /* | ||
666 | * The top-level algorithm for finding the next tile. | ||
667 | */ | ||
668 | HatCoords *hatctx_step(HatContext *ctx, HatCoords *hc_in, KiteStep step) | ||
669 | { | ||
670 | HatCoords *hc_out; | ||
671 | size_t depth; | ||
672 | |||
673 | #ifdef HAT_COORDS_DEBUG | ||
674 | static const char *const directions[] = { | ||
675 | " left\n", " right\n", " forward left\n", " forward right\n" }; | ||
676 | hat_coords_debug("step start ", hc_in, directions[step]); | ||
677 | #endif | ||
678 | |||
679 | /* | ||
680 | * First, just try a kitemap step immediately. If that succeeds, | ||
681 | * we're done. | ||
682 | */ | ||
683 | if ((hc_out = try_step_coords_kitemap(ctx, hc_in, step)) != NULL) | ||
684 | return hc_out; | ||
685 | |||
686 | /* | ||
687 | * Otherwise, try metamap rewrites at successively higher layers | ||
688 | * until one works. Each one will recurse back down to the | ||
689 | * kitemap, as described above. | ||
690 | */ | ||
691 | for (depth = 2;; depth++) { | ||
692 | if ((hc_out = try_step_coords_metamap( | ||
693 | ctx, hc_in, step, depth)) != NULL) | ||
694 | return hc_out; | ||
695 | } | ||
696 | } | ||
697 | |||
698 | /* | ||
699 | * Generate a random set of parameters for a tiling of a given size. | ||
700 | * To do this, we iterate over the whole tiling via hat_kiteenum_first | ||
701 | * and hat_kiteenum_next, and for each kite, calculate its | ||
702 | * coordinates. But then we throw the coordinates away and don't do | ||
703 | * anything with them! | ||
704 | * | ||
705 | * But the side effect of _calculating_ all those coordinates is that | ||
706 | * we found out how far ctx->prototype needed to be extended, and did | ||
707 | * so, pulling random choices out of our random_state. So after this | ||
708 | * iteration, ctx->prototype contains everything we need to replicate | ||
709 | * the same piece of tiling next time. | ||
710 | */ | ||
711 | void hat_tiling_randomise(struct HatPatchParams *hp, int w, int h, | ||
712 | random_state *rs) | ||
713 | { | ||
714 | HatContext ctx[1]; | ||
715 | HatCoords *coords[KE_NKEEP]; | ||
716 | KiteEnum s[1]; | ||
717 | size_t i; | ||
718 | |||
719 | hatctx_init_random(ctx, rs); | ||
720 | for (i = 0; i < lenof(coords); i++) | ||
721 | coords[i] = NULL; | ||
722 | |||
723 | hat_kiteenum_first(s, w, h); | ||
724 | coords[s->curr_index] = hatctx_initial_coords(ctx); | ||
725 | |||
726 | while (hat_kiteenum_next(s)) { | ||
727 | hat_coords_free(coords[s->curr_index]); | ||
728 | coords[s->curr_index] = hatctx_step( | ||
729 | ctx, coords[s->last_index], s->last_step); | ||
730 | } | ||
731 | |||
732 | hp->ncoords = ctx->prototype->nc - 1; | ||
733 | hp->coords = snewn(hp->ncoords, unsigned char); | ||
734 | for (i = 0; i < hp->ncoords; i++) | ||
735 | hp->coords[i] = ctx->prototype->c[i].index; | ||
736 | hp->final_metatile = tilechars[ctx->prototype->c[hp->ncoords].type]; | ||
737 | |||
738 | hatctx_cleanup(ctx); | ||
739 | for (i = 0; i < lenof(coords); i++) | ||
740 | hat_coords_free(coords[i]); | ||
741 | } | ||
742 | |||
743 | const char *hat_tiling_params_invalid(const struct HatPatchParams *hp) | ||
744 | { | ||
745 | TileType metatile; | ||
746 | size_t i; | ||
747 | |||
748 | if (hp->ncoords < 3) | ||
749 | return "Grid parameters require at least three coordinates"; | ||
750 | if (metatile_char_to_enum(hp->final_metatile) < 0) | ||
751 | return "Grid parameters contain an invalid final metatile"; | ||
752 | if (hp->coords[0] >= 8) | ||
753 | return "Grid parameters contain an invalid kite index"; | ||
754 | |||
755 | metatile = metatile_char_to_enum(hp->final_metatile); | ||
756 | for (i = hp->ncoords - 1; i > 1; i--) { | ||
757 | if (hp->coords[i] >= nchildren[metatile]) | ||
758 | return "Grid parameters contain an invalid metatile index"; | ||
759 | metatile = children[metatile][hp->coords[i]]; | ||
760 | } | ||
761 | |||
762 | if (hp->coords[1] >= hats_in_metatile[metatile]) | ||
763 | return "Grid parameters contain an invalid hat index"; | ||
764 | |||
765 | return NULL; | ||
766 | } | ||
767 | |||
768 | void maybe_report_hat(int w, int h, Kite kite, HatCoords *hc, | ||
769 | internal_hat_callback_fn cb, void *cbctx) | ||
770 | { | ||
771 | Kite kite0; | ||
772 | Point vertices[14]; | ||
773 | size_t i, j; | ||
774 | bool reversed = false; | ||
775 | int coords[28]; | ||
776 | |||
777 | /* Only iterate from kite #0 of a hat */ | ||
778 | if (hc->c[0].index != 0) | ||
779 | return; | ||
780 | kite0 = kite; | ||
781 | |||
782 | /* | ||
783 | * Identify reflected hats: they are always hat #3 of an H | ||
784 | * metatile. If we find one, reflect the starting kite so that the | ||
785 | * kite_step operations below will go in the other direction. | ||
786 | */ | ||
787 | if (hc->c[2].type == TT_H && hc->c[1].index == 3) { | ||
788 | reversed = true; | ||
789 | Point tmp = kite.left; | ||
790 | kite.left = kite.right; | ||
791 | kite.right = tmp; | ||
792 | } | ||
793 | |||
794 | vertices[0] = kite.centre; | ||
795 | vertices[1] = kite.right; | ||
796 | vertices[2] = kite.outer; | ||
797 | vertices[3] = kite.left; | ||
798 | kite = kite_left(kite); /* now on kite #1 */ | ||
799 | kite = kite_forward_right(kite); /* now on kite #2 */ | ||
800 | vertices[4] = kite.centre; | ||
801 | kite = kite_right(kite); /* now on kite #3 */ | ||
802 | vertices[5] = kite.right; | ||
803 | vertices[6] = kite.outer; | ||
804 | kite = kite_forward_left(kite); /* now on kite #4 */ | ||
805 | vertices[7] = kite.left; | ||
806 | vertices[8] = kite.centre; | ||
807 | kite = kite_right(kite); /* now on kite #5 */ | ||
808 | kite = kite_right(kite); /* now on kite #6 */ | ||
809 | kite = kite_right(kite); /* now on kite #7 */ | ||
810 | vertices[9] = kite.right; | ||
811 | vertices[10] = kite.outer; | ||
812 | vertices[11] = kite.left; | ||
813 | kite = kite_left(kite); /* now on kite #6 again */ | ||
814 | vertices[12] = kite.outer; | ||
815 | vertices[13] = kite.left; | ||
816 | |||
817 | if (reversed) { | ||
818 | /* For a reversed kite, also reverse the vertex order, so that | ||
819 | * we report every polygon in a consistent orientation */ | ||
820 | for (i = 0, j = 13; i < j; i++, j--) { | ||
821 | Point tmp = vertices[i]; | ||
822 | vertices[i] = vertices[j]; | ||
823 | vertices[j] = tmp; | ||
824 | } | ||
825 | } | ||
826 | |||
827 | /* | ||
828 | * Convert from our internal coordinate system into the orthogonal | ||
829 | * one used in this module's external API. In the same loop, we | ||
830 | * might as well do the bounds check. | ||
831 | */ | ||
832 | for (i = 0; i < 14; i++) { | ||
833 | Point v = vertices[i]; | ||
834 | int x = (v.x * 2 + v.y) / 3, y = v.y; | ||
835 | |||
836 | if (x < 0 || x > 4*w || y < 0 || y > 6*h) | ||
837 | return; /* a vertex of this kite is out of bounds */ | ||
838 | |||
839 | coords[2*i] = x; | ||
840 | coords[2*i+1] = y; | ||
841 | } | ||
842 | |||
843 | cb(cbctx, kite0, hc, coords); | ||
844 | } | ||
845 | |||
846 | struct internal_ctx { | ||
847 | hat_tile_callback_fn external_cb; | ||
848 | void *external_cbctx; | ||
849 | }; | ||
850 | static void report_hat(void *vctx, Kite kite0, HatCoords *hc, int *coords) | ||
851 | { | ||
852 | struct internal_ctx *ctx = (struct internal_ctx *)vctx; | ||
853 | ctx->external_cb(ctx->external_cbctx, 14, coords); | ||
854 | } | ||
855 | |||
856 | /* | ||
857 | * Generate a hat tiling from a previously generated set of parameters. | ||
858 | */ | ||
859 | void hat_tiling_generate(const struct HatPatchParams *hp, int w, int h, | ||
860 | hat_tile_callback_fn cb, void *cbctx) | ||
861 | { | ||
862 | HatContext ctx[1]; | ||
863 | HatCoords *coords[KE_NKEEP]; | ||
864 | KiteEnum s[1]; | ||
865 | size_t i; | ||
866 | struct internal_ctx report_hat_ctx[1]; | ||
867 | |||
868 | report_hat_ctx->external_cb = cb; | ||
869 | report_hat_ctx->external_cbctx = cbctx; | ||
870 | |||
871 | init_coords_params(ctx, hp); | ||
872 | for (i = 0; i < lenof(coords); i++) | ||
873 | coords[i] = NULL; | ||
874 | |||
875 | hat_kiteenum_first(s, w, h); | ||
876 | coords[s->curr_index] = hatctx_initial_coords(ctx); | ||
877 | maybe_report_hat(w, h, *s->curr, coords[s->curr_index], | ||
878 | report_hat, report_hat_ctx); | ||
879 | |||
880 | while (hat_kiteenum_next(s)) { | ||
881 | hat_coords_free(coords[s->curr_index]); | ||
882 | coords[s->curr_index] = hatctx_step( | ||
883 | ctx, coords[s->last_index], s->last_step); | ||
884 | maybe_report_hat(w, h, *s->curr, coords[s->curr_index], | ||
885 | report_hat, report_hat_ctx); | ||
886 | } | ||
887 | |||
888 | hatctx_cleanup(ctx); | ||
889 | for (i = 0; i < lenof(coords); i++) | ||
890 | hat_coords_free(coords[i]); | ||
891 | } | ||