hat-internal.h 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. /*
  2. * Internal definitions for the hat.c tiling generator, shared between
  3. * hat.c itself and hat-test.c.
  4. */
  5. #include "puzzles.h"
  6. /*
  7. * Coordinate system:
  8. *
  9. * The output of this code lives on the tiling known to grid.c as
  10. * 'Kites', which can be viewed as a tiling of hexagons each of which
  11. * is subdivided into six kites sharing their pointy vertex, or
  12. * (equivalently) a tiling of equilateral triangles each subdivided
  13. * into three kits sharing their blunt vertex.
  14. *
  15. * We express coordinates in this system relative to the basis (1, r)
  16. * where r = (1 + sqrt(3)i) / 2 is a primitive 6th root of unity. This
  17. * gives us a system in which two integer coordinates can address any
  18. * grid point, provided we scale up so that the side length of the
  19. * equilateral triangles in the tiling is 6.
  20. */
  21. typedef struct Point {
  22. int x, y; /* represents x + yr */
  23. } Point;
  24. static inline Point pointscale(int scale, Point a)
  25. {
  26. Point r = { scale * a.x, scale * a.y };
  27. return r;
  28. }
  29. static inline Point pointadd(Point a, Point b)
  30. {
  31. Point r = { a.x + b.x, a.y + b.y };
  32. return r;
  33. }
  34. /*
  35. * We identify a single kite by the coordinates of its four vertices.
  36. * This allows us to construct the coordinates of an adjacent kite by
  37. * taking affine transformations of the original kite's vertices.
  38. *
  39. * This is a useful way to do it because it means that if you reflect
  40. * the kite (by swapping its left and right vertices) then these
  41. * transformations also perform in a reflected way. This will be
  42. * useful in the code below that outputs the coordinates of each hat,
  43. * because this way it can work by walking around its 8 kites using a
  44. * fixed set of steps, and if the hat is reflected, then we just
  45. * reflect the starting kite before doing that, and everything still
  46. * works.
  47. */
  48. typedef struct Kite {
  49. Point centre, left, right, outer;
  50. } Kite;
  51. static inline Kite kite_left(Kite k)
  52. {
  53. Kite r;
  54. r.centre = k.centre;
  55. r.right = k.left;
  56. r.outer = pointadd(pointscale(2, k.left), pointscale(-1, k.outer));
  57. r.left = pointadd(pointadd(k.centre, k.left), pointscale(-1, k.right));
  58. return r;
  59. }
  60. static inline Kite kite_right(Kite k)
  61. {
  62. Kite r;
  63. r.centre = k.centre;
  64. r.left = k.right;
  65. r.outer = pointadd(pointscale(2, k.right), pointscale(-1, k.outer));
  66. r.right = pointadd(pointadd(k.centre, k.right), pointscale(-1, k.left));
  67. return r;
  68. }
  69. static inline Kite kite_forward_left(Kite k)
  70. {
  71. Kite r;
  72. r.outer = k.outer;
  73. r.right = k.left;
  74. r.centre = pointadd(pointscale(2, k.left), pointscale(-1, k.centre));
  75. r.left = pointadd(pointadd(k.right, k.left), pointscale(-1, k.centre));
  76. return r;
  77. }
  78. static inline Kite kite_forward_right(Kite k)
  79. {
  80. Kite r;
  81. r.outer = k.outer;
  82. r.left = k.right;
  83. r.centre = pointadd(pointscale(2, k.right), pointscale(-1, k.centre));
  84. r.right = pointadd(pointadd(k.left, k.right), pointscale(-1, k.centre));
  85. return r;
  86. }
  87. typedef enum KiteStep { KS_LEFT, KS_RIGHT, KS_F_LEFT, KS_F_RIGHT } KiteStep;
  88. static inline Kite kite_step(Kite k, KiteStep step)
  89. {
  90. switch (step) {
  91. case KS_LEFT: return kite_left(k);
  92. case KS_RIGHT: return kite_right(k);
  93. case KS_F_LEFT: return kite_forward_left(k);
  94. default /* case KS_F_RIGHT */: return kite_forward_right(k);
  95. }
  96. }
  97. /*
  98. * Functiond to enumerate the kites in a rectangular region, in a
  99. * serpentine-raster fashion so that every kite delivered shares an
  100. * edge with a recent previous one.
  101. */
  102. #define KE_NKEEP 3
  103. typedef struct KiteEnum {
  104. /* Fields private to the enumerator */
  105. int state;
  106. int x, y, w, h;
  107. unsigned curr_index;
  108. /* Fields the client can legitimately read out */
  109. Kite *curr;
  110. Kite recent[KE_NKEEP];
  111. unsigned last_index;
  112. KiteStep last_step; /* step that got curr from recent[last_index] */
  113. } KiteEnum;
  114. void hat_kiteenum_first(KiteEnum *s, int w, int h);
  115. bool hat_kiteenum_next(KiteEnum *s);
  116. /*
  117. * Assorted useful definitions.
  118. */
  119. typedef enum TileType { TT_H, TT_T, TT_P, TT_F, TT_KITE, TT_HAT } TileType;
  120. static const char tilechars[] = "HTPF";
  121. #define HAT_KITES 8 /* number of kites in a hat */
  122. #define MT_MAXEXPAND 13 /* largest number of metatiles in any expansion */
  123. /*
  124. * Definitions for the autogenerated hat-tables.h header file that
  125. * defines all the lookup tables.
  126. */
  127. typedef struct KitemapEntry {
  128. int kite, hat, meta; /* all -1 if impossible */
  129. } KitemapEntry;
  130. typedef struct MetamapEntry {
  131. int meta, meta2;
  132. } MetamapEntry;
  133. static inline size_t kitemap_index(KiteStep step, unsigned kite,
  134. unsigned hat, unsigned meta)
  135. {
  136. return step + 4 * (kite + 8 * (hat + 4 * meta));
  137. }
  138. static inline size_t metamap_index(unsigned meta, unsigned meta2)
  139. {
  140. return meta2 * MT_MAXEXPAND + meta;
  141. }
  142. /*
  143. * Coordinate system for tracking kites within a randomly selected
  144. * part of the recursively expanded hat tiling.
  145. *
  146. * HatCoords will store an array of HatCoord, in little-endian
  147. * arrangement. So hc->c[0] will always have type TT_KITE and index a
  148. * single kite within a hat; hc->c[1] will have type TT_HAT and index
  149. * a hat within a first-order metatile; hc->c[2] will be the smallest
  150. * metatile containing this hat, and hc->c[3, 4, 5, ...] will be
  151. * higher-order metatiles as needed.
  152. *
  153. * The last coordinate stored, hc->c[hc->nc-1], will have a tile type
  154. * but no index (represented by index==-1). This means "we haven't
  155. * decided yet what this level of metatile needs to be". If we need to
  156. * refer to this level during the hatctx_step algorithm, we make it up
  157. * at random, based on a table of what metatiles each type can
  158. * possibly be part of, at what index.
  159. */
  160. typedef struct HatCoord {
  161. int index; /* index within that tile, or -1 if not yet known */
  162. TileType type; /* type of this tile */
  163. } HatCoord;
  164. typedef struct HatCoords {
  165. HatCoord *c;
  166. size_t nc, csize;
  167. } HatCoords;
  168. HatCoords *hat_coords_new(void);
  169. void hat_coords_free(HatCoords *hc);
  170. void hat_coords_make_space(HatCoords *hc, size_t size);
  171. HatCoords *hat_coords_copy(HatCoords *hc_in);
  172. #ifdef HAT_COORDS_DEBUG
  173. static inline void hat_coords_debug(const char *prefix, HatCoords *hc,
  174. const char *suffix)
  175. {
  176. const char *sep = "";
  177. static const char *const types[] = {"H","T","P","F","kite","hat"};
  178. fputs(prefix, stderr);
  179. for (size_t i = 0; i < hc->nc; i++) {
  180. fprintf(stderr, "%s %s ", sep, types[hc->c[i].type]);
  181. sep = " .";
  182. if (hc->c[i].index == -1)
  183. fputs("?", stderr);
  184. else
  185. fprintf(stderr, "%d", hc->c[i].index);
  186. }
  187. fputs(suffix, stderr);
  188. }
  189. #else
  190. #define hat_coords_debug(p,c,s) ((void)0)
  191. #endif
  192. /*
  193. * HatContext is the shared context of a whole run of the algorithm.
  194. * Its 'prototype' HatCoords object represents the coordinates of the
  195. * starting kite, and is extended as necessary; any other HatCoord
  196. * that needs extending will copy the higher-order values from
  197. * ctx->prototype as needed, so that once each choice has been made,
  198. * it remains consistent.
  199. *
  200. * When we're inventing a random piece of tiling in the first place,
  201. * we append to ctx->prototype by choosing a random (but legal)
  202. * higher-level metatile for the current topmost one to turn out to be
  203. * part of. When we're replaying a generation whose parameters are
  204. * already stored, we don't have a random_state, and we make fixed
  205. * decisions if not enough coordinates were provided.
  206. *
  207. * (Of course another approach would be to reject grid descriptions
  208. * that didn't define enough coordinates! But that would involve a
  209. * whole extra iteration over the whole grid region just for
  210. * validation, and that seems like more timewasting than really
  211. * needed. So we tolerate short descriptions, and do something
  212. * deterministic with them.)
  213. */
  214. typedef struct HatContext {
  215. random_state *rs;
  216. HatCoords *prototype;
  217. } HatContext;
  218. void hatctx_init_random(HatContext *ctx, random_state *rs);
  219. void hatctx_cleanup(HatContext *ctx);
  220. HatCoords *hatctx_initial_coords(HatContext *ctx);
  221. void hatctx_extend_coords(HatContext *ctx, HatCoords *hc, size_t n);
  222. HatCoords *hatctx_step(HatContext *ctx, HatCoords *hc_in, KiteStep step);
  223. /*
  224. * Subroutine of hat_tiling_generate, called for each kite in the grid
  225. * as we iterate over it, to decide whether to generate an output hat
  226. * and pass it to the client. Exposed in this header file so that
  227. * hat-test can reuse it.
  228. *
  229. * We do this by starting from kite #0 of each hat, and tracing round
  230. * the boundary. If the whole boundary is within the caller's bounding
  231. * region, we return it; if it goes off the edge, we don't.
  232. *
  233. * (Of course, every hat we _do_ want to return will have all its
  234. * kites inside the rectangle, so its kite #0 will certainly be caught
  235. * by this iteration.)
  236. */
  237. typedef void (*internal_hat_callback_fn)(void *ctx, Kite kite0, HatCoords *hc,
  238. int *coords);
  239. void maybe_report_hat(int w, int h, Kite kite, HatCoords *hc,
  240. internal_hat_callback_fn cb, void *cbctx);