1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
|
/*
* Further data tables used to generate the final transition maps.
*/
/*
* Locations in the plane of the centres of the 8 hexagons in the
* expansion of each hex.
*
* We take the centre-to-centre distance to be 6 units, so that other
* locations in the hex tiling (e.g. edge midpoints and vertices) will
* still have integer coefficients.
*
* These locations are represented using the same Point type used for
* the whole tiling, but all our angles are 60 degrees, so we don't
* ever need the coefficients of d or d^3, only of 1 and d^2.
*/
static const Point hex_centres[] = {
{{0, 0, 0, 0}}, {{6, 0, 0, 0}}, /* 0 1 */
{{0, 0, -6, 0}}, {{6, 0, -6, 0}}, /* 2 3 */
{{0, 0, -12, 0}}, {{6, 0, -12, 0}}, {{12, 0, -12, 0}}, /* 4 5 6 */
{{12, 0, -18, 0}}, /* 7 */
};
/*
* Orientations of all the sub-hexes in the expansion of each hex.
* Measured anticlockwise (that is, as a power of s) from 0, where 0
* means the hex is upright, with its own vertex #0 at the top.
*/
static const unsigned orientations_G[] = {
2, /* HEX_F */
1, /* HEX_X */
0, /* HEX_G */
1, /* HEX_S */
4, /* HEX_P */
5, /* HEX_D */
0, /* HEX_J */
/* hex #7 is not present for this tile */
};
static const unsigned orientations_D[] = {
2, /* HEX_F */
1, /* HEX_P */
0, /* HEX_G */
1, /* HEX_S */
4, /* HEX_X */
5, /* HEX_D */
0, /* HEX_F */
5, /* HEX_X */
};
static const unsigned orientations_J[] = {
2, /* HEX_F */
1, /* HEX_P */
0, /* HEX_G */
1, /* HEX_S */
4, /* HEX_Y */
5, /* HEX_D */
0, /* HEX_F */
5, /* HEX_P */
};
static const unsigned orientations_L[] = {
2, /* HEX_F */
1, /* HEX_P */
0, /* HEX_G */
1, /* HEX_S */
4, /* HEX_Y */
5, /* HEX_D */
0, /* HEX_F */
5, /* HEX_X */
};
static const unsigned orientations_X[] = {
2, /* HEX_F */
1, /* HEX_Y */
0, /* HEX_G */
1, /* HEX_S */
4, /* HEX_Y */
5, /* HEX_D */
0, /* HEX_F */
5, /* HEX_P */
};
static const unsigned orientations_P[] = {
2, /* HEX_F */
1, /* HEX_Y */
0, /* HEX_G */
1, /* HEX_S */
4, /* HEX_Y */
5, /* HEX_D */
0, /* HEX_F */
5, /* HEX_X */
};
static const unsigned orientations_S[] = {
2, /* HEX_L */
1, /* HEX_P */
0, /* HEX_G */
1, /* HEX_S */
4, /* HEX_X */
5, /* HEX_D */
0, /* HEX_F */
5, /* HEX_X */
};
static const unsigned orientations_F[] = {
2, /* HEX_F */
1, /* HEX_P */
0, /* HEX_G */
1, /* HEX_S */
4, /* HEX_Y */
5, /* HEX_D */
0, /* HEX_F */
5, /* HEX_Y */
};
static const unsigned orientations_Y[] = {
2, /* HEX_F */
1, /* HEX_Y */
0, /* HEX_G */
1, /* HEX_S */
4, /* HEX_Y */
5, /* HEX_D */
0, /* HEX_F */
5, /* HEX_Y */
};
/*
* For each hex type, indicate the point on the boundary of the
* expansion that corresponds to vertex 0 of the superhex. Also,
* indicate the initial direction we head in to go round the edge.
*/
#define HEX_OUTLINE_START_COMMON {{ -4, 0, -10, 0 }}, {{ +2, 0, +2, 0 }}
#define HEX_OUTLINE_START_RARE {{ -2, 0, -14, 0 }}, {{ -2, 0, +4, 0 }}
#define HEX_OUTLINE_START_G HEX_OUTLINE_START_COMMON
#define HEX_OUTLINE_START_D HEX_OUTLINE_START_RARE
#define HEX_OUTLINE_START_J HEX_OUTLINE_START_COMMON
#define HEX_OUTLINE_START_L HEX_OUTLINE_START_COMMON
#define HEX_OUTLINE_START_X HEX_OUTLINE_START_COMMON
#define HEX_OUTLINE_START_P HEX_OUTLINE_START_COMMON
#define HEX_OUTLINE_START_S HEX_OUTLINE_START_RARE
#define HEX_OUTLINE_START_F HEX_OUTLINE_START_COMMON
#define HEX_OUTLINE_START_Y HEX_OUTLINE_START_COMMON
/*
* Similarly, for each hex type, indicate the point on the boundary of
* its Spectre expansion that corresponds to hex vertex 0.
*
* This time, it's easiest just to indicate which vertex of which
* sub-Spectre we take in each case, because the Spectre outlines
* don't take predictable turns between the edge expansions, so the
* routine consuming this data will have to look things up in its
* edgemap anyway.
*/
#define SPEC_OUTLINE_START_COMMON 0, 9
#define SPEC_OUTLINE_START_RARE 0, 8
#define SPEC_OUTLINE_START_G SPEC_OUTLINE_START_COMMON
#define SPEC_OUTLINE_START_D SPEC_OUTLINE_START_RARE
#define SPEC_OUTLINE_START_J SPEC_OUTLINE_START_COMMON
#define SPEC_OUTLINE_START_L SPEC_OUTLINE_START_COMMON
#define SPEC_OUTLINE_START_X SPEC_OUTLINE_START_COMMON
#define SPEC_OUTLINE_START_P SPEC_OUTLINE_START_COMMON
#define SPEC_OUTLINE_START_S SPEC_OUTLINE_START_RARE
#define SPEC_OUTLINE_START_F SPEC_OUTLINE_START_COMMON
#define SPEC_OUTLINE_START_Y SPEC_OUTLINE_START_COMMON
/*
* The paper also defines a set of 8 different classes of edges for
* the hexagons. (You can imagine these as different shapes of
* jigsaw-piece tab, constraining how the hexes can fit together). So
* for each hex, we need a list of its edge types.
*
* Most edge types come in two matching pairs, which the paper labels
* with the same lowercase Greek letter and a + or - superscript, e.g.
* alpha^+ and alpha^-. The usual rule is that when two edges meet,
* they have to be the + and - versions of the same letter. The
* exception to this rule is the 'eta' edge, which has no sign: it's
* symmetric, so any two eta edges can validly meet.
*
* We express this here by defining an enumeration in which eta = 0
* and all other edge types have positive values, so that integer
* negation can be used to indicate the other edge that fits with this
* one (and for eta, it doesn't change the value).
*/
enum Edge {
edge_eta = 0,
edge_alpha,
edge_beta,
edge_gamma,
edge_delta,
edge_epsilon,
edge_zeta,
edge_theta,
};
/*
* Edge types for each hex are specified anticlockwise, starting from
* the top vertex, so that edge #0 is the top-left diagonal edge, edge
* #1 the left-hand vertical edge, etc.
*/
static const int edges_G[6] = {
-edge_beta, -edge_alpha, +edge_alpha,
-edge_gamma, -edge_delta, +edge_beta,
};
static const int edges_D[6] = {
-edge_zeta, +edge_gamma, +edge_beta,
-edge_epsilon, +edge_alpha, -edge_gamma,
};
static const int edges_J[6] = {
-edge_beta, +edge_gamma, +edge_beta,
+edge_theta, +edge_beta, edge_eta,
};
static const int edges_L[6] = {
-edge_beta, +edge_gamma, +edge_beta,
-edge_epsilon, +edge_alpha, -edge_theta,
};
static const int edges_X[6] = {
-edge_beta, -edge_alpha, +edge_epsilon,
+edge_theta, +edge_beta, edge_eta,
};
static const int edges_P[6] = {
-edge_beta, -edge_alpha, +edge_epsilon,
-edge_epsilon, +edge_alpha, -edge_theta,
};
static const int edges_S[6] = {
+edge_delta, +edge_zeta, +edge_beta,
-edge_epsilon, +edge_alpha, -edge_gamma,
};
static const int edges_F[6] = {
-edge_beta, +edge_gamma, +edge_beta,
-edge_epsilon, +edge_epsilon, edge_eta,
};
static const int edges_Y[6] = {
-edge_beta, -edge_alpha, +edge_epsilon,
-edge_epsilon, +edge_epsilon, edge_eta,
};
/*
* Now specify the actual shape of each edge type, in terms of the
* angles of turns as you traverse the edge.
*
* Edges around the outline of a hex expansion are traversed
* _clockwise_, because each expansion step flips the handedness of
* the whole system.
*
* Each array has one fewer element than the number of sub-edges in
* the edge shape (for the usual reason - n edges in a path have only
* n-1 vertices separating them).
*
* These arrays show the positive version of each edge type. The
* negative version is obtained by reversing the order of the turns
* and also the sign of each turn.
*/
static const int hex_edge_shape_eta[] = { +2, +2, -2, -2 };
static const int hex_edge_shape_alpha[] = { +2, -2 };
static const int hex_edge_shape_beta[] = { -2 };
static const int hex_edge_shape_gamma[] = { +2, -2, -2, +2 };
static const int hex_edge_shape_delta[] = { -2, +2, -2, +2 };
static const int hex_edge_shape_epsilon[] = { +2, -2, -2 };
static const int hex_edge_shape_zeta[] = { -2, +2 };
static const int hex_edge_shape_theta[] = { +2, +2, -2, -2, +2 };
static const int *const hex_edge_shapes[] = {
hex_edge_shape_eta,
hex_edge_shape_alpha,
hex_edge_shape_beta,
hex_edge_shape_gamma,
hex_edge_shape_delta,
hex_edge_shape_epsilon,
hex_edge_shape_zeta,
hex_edge_shape_theta,
};
static const size_t hex_edge_lengths[] = {
lenof(hex_edge_shape_eta) + 1,
lenof(hex_edge_shape_alpha) + 1,
lenof(hex_edge_shape_beta) + 1,
lenof(hex_edge_shape_gamma) + 1,
lenof(hex_edge_shape_delta) + 1,
lenof(hex_edge_shape_epsilon) + 1,
lenof(hex_edge_shape_zeta) + 1,
lenof(hex_edge_shape_theta) + 1,
};
static const int spec_edge_shape_eta[] = { 0 };
static const int spec_edge_shape_alpha[] = { -2, +3 };
static const int spec_edge_shape_beta[] = { +3, -2 };
static const int spec_edge_shape_gamma[] = { +2 };
static const int spec_edge_shape_delta[] = { +2, +3, +2, -3, +2 };
static const int spec_edge_shape_epsilon[] = { +3 };
static const int spec_edge_shape_zeta[] = { -2 };
/* In expansion to Spectres, a theta edge corresponds to just one
* Spectre edge, so its turns array would be completely empty! */
static const int *const spec_edge_shapes[] = {
spec_edge_shape_eta,
spec_edge_shape_alpha,
spec_edge_shape_beta,
spec_edge_shape_gamma,
spec_edge_shape_delta,
spec_edge_shape_epsilon,
spec_edge_shape_zeta,
NULL, /* theta has no turns */
};
static const size_t spec_edge_lengths[] = {
lenof(spec_edge_shape_eta) + 1,
lenof(spec_edge_shape_alpha) + 1,
lenof(spec_edge_shape_beta) + 1,
lenof(spec_edge_shape_gamma) + 1,
lenof(spec_edge_shape_delta) + 1,
lenof(spec_edge_shape_epsilon) + 1,
lenof(spec_edge_shape_zeta) + 1,
1, /* theta is only one edge long */
};
/*
* Each edge type corresponds to a fixed number of edges of the
* hexagon layout in the expansion of each hex, and also to a fixed
* number of edges of the Spectre(s) that each hex expands to in the
* final step.
*/
static const int edgelen_hex[] = {
5, /* edge_eta */
3, /* edge_alpha */
2, /* edge_beta */
5, /* edge_gamma */
5, /* edge_delta */
4, /* edge_epsilon */
3, /* edge_zeta */
6, /* edge_theta */
};
static const int edgelen_spectre[] = {
2, /* edge_eta */
3, /* edge_alpha */
3, /* edge_beta */
2, /* edge_gamma */
6, /* edge_delta */
2, /* edge_epsilon */
2, /* edge_zeta */
1, /* edge_theta */
};
|