mirror of
git://git.tartarus.org/simon/puzzles.git
synced 2025-04-20 07:31:30 -07:00
Files

This uses a tile shape very similar to the hat, but the tiling _structure_ is totally changed so that there aren't any reflected copies of the tile. I'm not sure how much difference this makes to gameplay: the two tilings are very similar for Loopy purposes. But the code was fun to write, and I think the Spectre shape is noticeably prettier, so I'm adding this to the collection anyway. The test programs also generate a pile of SVG images used in the companion article on my website.
710 lines
22 KiB
C
710 lines
22 KiB
C
/*
|
|
* Generate the lookup tables used by the Spectre tiling.
|
|
*/
|
|
|
|
#include <assert.h>
|
|
#include <errno.h>
|
|
#include <math.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#include "puzzles.h"
|
|
#include "tree234.h"
|
|
#include "spectre-internal.h"
|
|
#include "spectre-tables-manual.h"
|
|
#include "spectre-tables-extra.h"
|
|
#include "spectre-help.h"
|
|
|
|
struct HexData {
|
|
const Hex *subhexes;
|
|
const unsigned *orientations;
|
|
const int *edges;
|
|
Point hex_outline_start, hex_outline_direction;
|
|
unsigned spectre_outline_start_spec, spectre_outline_start_vertex;
|
|
};
|
|
|
|
static const struct HexData hexdata[] = {
|
|
#define HEXDATA_ENTRY(x) { subhexes_##x, orientations_##x, edges_##x, \
|
|
HEX_OUTLINE_START_##x, SPEC_OUTLINE_START_##x },
|
|
HEX_LETTERS(HEXDATA_ENTRY)
|
|
#undef HEXDATA_ENTRY
|
|
};
|
|
|
|
/*
|
|
* Store information about an edge of the hexagonal tiling.
|
|
*/
|
|
typedef struct EdgeData {
|
|
/* Edges are regarded as directed, so that we can store
|
|
* information separately about what's on each side of one. The
|
|
* names 'start' and 'finish' indicate a direction of travel,
|
|
* which is taken to be anticlockwise around a hexagon, i.e. if
|
|
* you walk from 'start' to 'finish' then the hexagon in question
|
|
* is the one on your left. */
|
|
Point start, finish;
|
|
|
|
/* Whether this edge is internal (i.e. owned by a hexagon). */
|
|
bool internal;
|
|
|
|
/*
|
|
* High- and low-order parts of the edge identity.
|
|
*
|
|
* If the edge is internal, then 'hi' indexes the hexagon it's an
|
|
* edge of, and 'lo' identifies one of its edges.
|
|
*
|
|
* If it's external, then 'hi' is the index of the edge segment
|
|
* corresponding to a particular edge of the superhex, and 'lo'
|
|
* the sub-index within that segment.
|
|
*/
|
|
unsigned hi, lo;
|
|
} EdgeData;
|
|
|
|
static int edge_cmp(void *av, void *bv)
|
|
{
|
|
const EdgeData *a = (const EdgeData *)av;
|
|
const EdgeData *b = (const EdgeData *)bv;
|
|
size_t i;
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
if (a->start.coeffs[i] < b->start.coeffs[i])
|
|
return -1;
|
|
if (a->start.coeffs[i] > b->start.coeffs[i])
|
|
return +1;
|
|
}
|
|
for (i = 0; i < 4; i++) {
|
|
if (a->finish.coeffs[i] < b->finish.coeffs[i])
|
|
return -1;
|
|
if (a->finish.coeffs[i] > b->finish.coeffs[i])
|
|
return +1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void lay_out_hexagons(Hex h, Graphics *gr, FILE *hdr)
|
|
{
|
|
size_t i, j;
|
|
tree234 *edge_map = newtree234(edge_cmp);
|
|
EdgeData *edge;
|
|
EdgeData *intmap[48], *extmap[22];
|
|
unsigned edgestarts[7];
|
|
const struct HexData *hd = h == NO_HEX ? NULL : &hexdata[h];
|
|
|
|
/*
|
|
* Iterate over all hexagons and enter their edges into the edge
|
|
* map.
|
|
*/
|
|
for (i = 0; i < (h == NO_HEX ? 8 : num_subhexes(h)); i++) {
|
|
Point centre = hex_centres[i];
|
|
Point vrel = {{ -2, 0, 4, 0 }};
|
|
Point vertices[6];
|
|
|
|
if (hd)
|
|
vrel = point_mul(vrel, point_rot(2*hd->orientations[i]));
|
|
for (j = 0; j < 6; j++) {
|
|
Point vrelnext = point_mul(vrel, point_rot(2));
|
|
|
|
edge = snew(EdgeData);
|
|
edge->start = point_add(centre, vrel);
|
|
edge->finish = point_add(centre, vrelnext);
|
|
edge->internal = true;
|
|
edge->hi = i;
|
|
edge->lo = j;
|
|
add234(edge_map, edge);
|
|
intmap[6*i + j] = edge;
|
|
|
|
vertices[j] = edge->start;
|
|
|
|
vrel = vrelnext;
|
|
}
|
|
|
|
gr_draw_hex(gr, gr->jigsaw_mode ? -1 : i,
|
|
hd ? hd->subhexes[i] : NO_HEX, vertices);
|
|
}
|
|
|
|
/*
|
|
* Trace round the exterior outline of the hex expansion,
|
|
* following the list of edge types.
|
|
*/
|
|
if (hd) {
|
|
Point pos, dir;
|
|
size_t mappos = 0;
|
|
|
|
pos = hd->hex_outline_start;
|
|
dir = hd->hex_outline_direction;
|
|
|
|
for (i = 0; i < 6; i++) {
|
|
int edge_type = hd->edges[i];
|
|
int sign = edge_type < 0 ? -1 : +1;
|
|
const int *edge_shape = hex_edge_shapes[abs(edge_type)];
|
|
size_t len = hex_edge_lengths[abs(edge_type)];
|
|
size_t index = sign < 0 ? len-2 : 0;
|
|
|
|
if (gr->vertex_blobs)
|
|
gr_draw_blob(gr, (i == 0 ? "startpoint" : "edgesep"),
|
|
gr_logcoords(pos), (i == 0 ? 0.6 : 0.3));
|
|
|
|
edgestarts[i] = mappos;
|
|
|
|
for (j = 0; j < len; j++) {
|
|
Point posnext = point_add(pos, dir);
|
|
if (j < len-1) {
|
|
dir = point_mul(dir, point_rot(sign * edge_shape[index]));
|
|
index += sign;
|
|
}
|
|
|
|
edge = snew(EdgeData);
|
|
edge->start = pos;
|
|
edge->finish = posnext;
|
|
edge->internal = false;
|
|
edge->hi = i;
|
|
edge->lo = j;
|
|
add234(edge_map, edge);
|
|
|
|
assert(mappos < lenof(extmap));
|
|
extmap[mappos++] = edge;
|
|
|
|
pos = posnext;
|
|
}
|
|
|
|
/*
|
|
* In the hex expansion, every pair of edges meet at a
|
|
* 60-degree left turn.
|
|
*/
|
|
dir = point_mul(dir, point_rot(-2));
|
|
}
|
|
|
|
edgestarts[i] = mappos; /* record end position */
|
|
|
|
for (i = 0; i < 4; i++)
|
|
assert(pos.coeffs[i] == hd->hex_outline_start.coeffs[i]);
|
|
}
|
|
|
|
/*
|
|
* Draw the labels on the edges.
|
|
*/
|
|
if (gr->number_edges) {
|
|
for (i = 0; (edge = index234(edge_map, i)) != NULL; i++) {
|
|
char buf[64];
|
|
double textheight = 0.8, offset = textheight * 0.2;
|
|
GrCoords start = gr_logcoords(edge->start);
|
|
GrCoords finish = gr_logcoords(edge->finish);
|
|
GrCoords len = { finish.x - start.x, finish.y - start.y };
|
|
GrCoords perp = { -len.y, +len.x };
|
|
GrCoords mid = { (start.x+finish.x)/2, (start.y+finish.y)/2 };
|
|
|
|
if (edge->internal) {
|
|
sprintf(buf, "%u", edge->lo);
|
|
} else {
|
|
sprintf(buf, "%u.%u", edge->lo, edge->hi);
|
|
offset = textheight * 0.3;
|
|
}
|
|
|
|
{
|
|
GrCoords pos = {
|
|
mid.x + offset * perp.x,
|
|
mid.y + offset * perp.y,
|
|
};
|
|
gr_draw_text(gr, pos, textheight, buf);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Write out C array declarations for the machine-readable version
|
|
* of the maps we just generated.
|
|
*/
|
|
if (hdr) {
|
|
fprintf(hdr, "static const struct MapEntry hexmap_%s[] = {\n",
|
|
hex_names[h]);
|
|
for (i = 0; i < 6 * num_subhexes(h); i++) {
|
|
EdgeData *our_edge = intmap[i];
|
|
EdgeData key, *rev_edge;
|
|
key.finish = our_edge->start;
|
|
key.start = our_edge->finish;
|
|
rev_edge = find234(edge_map, &key, NULL);
|
|
assert(rev_edge);
|
|
fprintf(hdr, " { %-6s %u, %u }, /* edge %u of hex %u (%s) */\n",
|
|
rev_edge->internal ? "true," : "false,",
|
|
rev_edge->hi, rev_edge->lo,
|
|
our_edge->lo, our_edge->hi,
|
|
hex_names[hd->subhexes[our_edge->hi]]);
|
|
}
|
|
fprintf(hdr, "};\n");
|
|
|
|
fprintf(hdr, "static const struct MapEdge hexedges_%s[] = {\n",
|
|
hex_names[h]);
|
|
for (i = 0; i < 6; i++)
|
|
fprintf(hdr, " { %2u, %u },\n", edgestarts[i],
|
|
edgestarts[i+1] - edgestarts[i]);
|
|
fprintf(hdr, "};\n");
|
|
|
|
fprintf(hdr, "static const struct MapEntry hexin_%s[] = {\n",
|
|
hex_names[h]);
|
|
for (i = 0; i < edgestarts[6]; i++) {
|
|
EdgeData *our_edge = extmap[i];
|
|
EdgeData key, *rev_edge;
|
|
key.finish = our_edge->start;
|
|
key.start = our_edge->finish;
|
|
rev_edge = find234(edge_map, &key, NULL);
|
|
assert(rev_edge);
|
|
fprintf(hdr, " { %-6s %u, %u }, /* subedge %u of edge %u */\n",
|
|
rev_edge->internal ? "true," : "false,",
|
|
rev_edge->hi, rev_edge->lo,
|
|
our_edge->lo, our_edge->hi);
|
|
}
|
|
fprintf(hdr, "};\n");
|
|
}
|
|
|
|
while ((edge = delpos234(edge_map, 0)) != NULL)
|
|
sfree(edge);
|
|
freetree234(edge_map);
|
|
}
|
|
|
|
static void lay_out_spectres(Hex h, Graphics *gr, FILE *hdr)
|
|
{
|
|
size_t i, j;
|
|
tree234 *edge_map = newtree234(edge_cmp);
|
|
EdgeData *edge;
|
|
EdgeData *intmap[28], *extmap[24];
|
|
Point vertices[28];
|
|
unsigned edgestarts[7];
|
|
const struct HexData *hd = (h == NO_HEX ? NULL : &hexdata[h]);
|
|
|
|
/*
|
|
* Iterate over the Spectres in a hex (usually only one), and enter
|
|
* their edges into the edge map.
|
|
*/
|
|
for (i = 0; i < (h == NO_HEX ? 2 : num_spectres(h)); i++) {
|
|
Point start = {{ 0, 0, 0, 0 }};
|
|
Point pos = start;
|
|
Point diag = {{ 2, 0, 0, 2 }};
|
|
Point dir = point_mul(diag, point_rot(5));
|
|
|
|
/*
|
|
* Usually the single Spectre in each map is oriented in the
|
|
* same place. For spectre #1 in the G map, however, we orient
|
|
* it manually in a different location. (There's no point
|
|
* making an organised lookup table for just this one
|
|
* exceptional case.)
|
|
*/
|
|
if (i == 1) {
|
|
Point unusual_start = {{ 2, 6, 2, 0 }};
|
|
pos = unusual_start;
|
|
dir = point_mul(dir, point_rot(+1));
|
|
}
|
|
|
|
for (j = 0; j < 14; j++) {
|
|
edge = snew(EdgeData);
|
|
edge->start = pos;
|
|
edge->finish = point_add(pos, dir);
|
|
edge->internal = true;
|
|
edge->hi = i;
|
|
edge->lo = j;
|
|
add234(edge_map, edge);
|
|
intmap[14*i + j] = edge;
|
|
|
|
vertices[14*i + j] = edge->start;
|
|
|
|
pos = edge->finish;
|
|
dir = point_mul(dir, point_rot(spectre_angles[(j+1) % 14]));
|
|
}
|
|
|
|
gr_draw_spectre(gr, h, i, vertices + 14*i);
|
|
}
|
|
|
|
/*
|
|
* Trace round the exterior outline of the hex expansion,
|
|
* following the list of edge types. Due to the confusing
|
|
* reflection of all the expansions, we end up doing this in the
|
|
* reverse order to the hexes code above.
|
|
*/
|
|
if (hd) {
|
|
Point start, pos, dir;
|
|
size_t mappos = lenof(extmap);
|
|
|
|
start = pos = vertices[14 * hd->spectre_outline_start_spec +
|
|
hd->spectre_outline_start_vertex];
|
|
|
|
edgestarts[6] = mappos;
|
|
|
|
for (i = 0; i < 6; i++) {
|
|
int edge_type = hd->edges[5-i];
|
|
int sign = edge_type < 0 ? -1 : +1;
|
|
const int *edge_shape = spec_edge_shapes[abs(edge_type)];
|
|
size_t len = spec_edge_lengths[abs(edge_type)];
|
|
size_t index = sign < 0 ? len-2 : 0;
|
|
|
|
if (gr->vertex_blobs)
|
|
gr_draw_blob(gr, (i == 0 ? "startpoint" : "edgesep"),
|
|
gr_logcoords(pos), (i == 0 ? 0.6 : 0.3));
|
|
|
|
if (h == HEX_S && i >= 4) {
|
|
/*
|
|
* Two special cases
|
|
*/
|
|
if (i == 4)
|
|
/* leave dir from last time */;
|
|
else
|
|
dir = point_mul(dir, point_rot(6)); /* reverse */
|
|
} else {
|
|
/*
|
|
* Determine the direction of the first sub-edge of
|
|
* this edge expansion, by iterating over all the
|
|
* edges in edge_map starting at this point and
|
|
* finding one whose reverse isn't in the map (hence,
|
|
* it's an exterior edge).
|
|
*/
|
|
EdgeData dummy, *iter, *found = NULL;
|
|
dummy.start = pos;
|
|
for (j = 0; j < 4; j++)
|
|
dummy.finish.coeffs[j] = INT_MIN;
|
|
for (iter = findrel234(edge_map, &dummy, NULL, REL234_GE);
|
|
iter != NULL && point_equal(iter->start, pos);
|
|
iter = findrel234(edge_map, iter, NULL, REL234_GT)) {
|
|
EdgeData *rev;
|
|
|
|
dummy.finish = iter->start;
|
|
dummy.start = iter->finish;
|
|
rev = find234(edge_map, &dummy, NULL);
|
|
if (!rev) {
|
|
found = iter;
|
|
break;
|
|
}
|
|
}
|
|
|
|
assert(found);
|
|
dir = point_sub(found->finish, found->start);
|
|
}
|
|
|
|
for (j = 0; j < len; j++) {
|
|
Point posnext = point_add(pos, dir);
|
|
if (j < len-1) {
|
|
dir = point_mul(dir, point_rot(sign * edge_shape[index]));
|
|
index += sign;
|
|
}
|
|
|
|
edge = snew(EdgeData);
|
|
edge->start = posnext;
|
|
edge->finish = pos;
|
|
edge->internal = false;
|
|
edge->hi = 5-i;
|
|
edge->lo = len-1-j;
|
|
add234(edge_map, edge);
|
|
|
|
assert(mappos > 0);
|
|
extmap[--mappos] = edge;
|
|
|
|
pos = posnext;
|
|
}
|
|
|
|
edgestarts[5-i] = mappos;
|
|
}
|
|
|
|
assert(point_equal(pos, start));
|
|
}
|
|
|
|
/*
|
|
* Draw the labels on the edges.
|
|
*/
|
|
if (gr->number_edges) {
|
|
for (i = 0; (edge = index234(edge_map, i)) != NULL; i++) {
|
|
char buf[64];
|
|
double textheight = 0.8, offset = textheight * 0.2;
|
|
GrCoords start = gr_logcoords(edge->start);
|
|
GrCoords finish = gr_logcoords(edge->finish);
|
|
GrCoords len = { finish.x - start.x, finish.y - start.y };
|
|
GrCoords perp = { +len.y, -len.x };
|
|
GrCoords mid = { (start.x+finish.x)/2, (start.y+finish.y)/2 };
|
|
|
|
if (edge->internal) {
|
|
sprintf(buf, "%u", edge->lo);
|
|
} else {
|
|
sprintf(buf, "%u.%u", edge->lo, edge->hi);
|
|
textheight = 0.6;
|
|
}
|
|
if (strlen(buf) > 1)
|
|
offset = textheight * 0.35;
|
|
|
|
{
|
|
GrCoords pos = {
|
|
mid.x + offset * perp.x,
|
|
mid.y + offset * perp.y,
|
|
};
|
|
gr_draw_text(gr, pos, textheight, buf);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Write out C array declarations for the machine-readable version
|
|
* of the maps we just generated.
|
|
*
|
|
* Also, because it's easier than having a whole extra iteration,
|
|
* draw lines for the extraordinary edges outside the S diagram.
|
|
*/
|
|
if (hdr) {
|
|
fprintf(hdr, "static const struct MapEntry specmap_%s[] = {\n",
|
|
hex_names[h]);
|
|
for (i = 0; i < 14 * num_spectres(h); i++) {
|
|
EdgeData *our_edge = intmap[i];
|
|
EdgeData key, *rev_edge;
|
|
key.finish = our_edge->start;
|
|
key.start = our_edge->finish;
|
|
rev_edge = find234(edge_map, &key, NULL);
|
|
assert(rev_edge);
|
|
fprintf(hdr, " { %-6s %u, %2u }, /* edge %2u of Spectre %u */\n",
|
|
rev_edge->internal ? "true," : "false,",
|
|
rev_edge->hi, rev_edge->lo,
|
|
our_edge->lo, our_edge->hi);
|
|
}
|
|
fprintf(hdr, "};\n");
|
|
|
|
fprintf(hdr, "static const struct MapEdge specedges_%s[] = {\n",
|
|
hex_names[h]);
|
|
for (i = 0; i < 6; i++)
|
|
fprintf(hdr, " { %2u, %u },\n", edgestarts[i] - edgestarts[0],
|
|
edgestarts[i+1] - edgestarts[i]);
|
|
fprintf(hdr, "};\n");
|
|
|
|
fprintf(hdr, "static const struct MapEntry specin_%s[] = {\n",
|
|
hex_names[h]);
|
|
for (i = edgestarts[0]; i < edgestarts[6]; i++) {
|
|
EdgeData *our_edge = extmap[i];
|
|
EdgeData key, *rev_edge;
|
|
key.finish = our_edge->start;
|
|
key.start = our_edge->finish;
|
|
rev_edge = find234(edge_map, &key, NULL);
|
|
assert(rev_edge);
|
|
fprintf(hdr, " { %-6s %u, %2u }, /* subedge %u of edge %u */\n",
|
|
rev_edge->internal ? "true," : "false,",
|
|
rev_edge->hi, rev_edge->lo,
|
|
our_edge->lo, our_edge->hi);
|
|
|
|
if (!our_edge->internal && !rev_edge->internal)
|
|
gr_draw_extra_edge(gr, key.start, key.finish);
|
|
}
|
|
fprintf(hdr, "};\n");
|
|
}
|
|
|
|
while ((edge = delpos234(edge_map, 0)) != NULL)
|
|
sfree(edge);
|
|
freetree234(edge_map);
|
|
}
|
|
|
|
static void draw_base_hex(Hex h, Graphics *gr)
|
|
{
|
|
size_t i;
|
|
Point vertices[6];
|
|
|
|
/*
|
|
* Plot the points of the hex.
|
|
*/
|
|
for (i = 0; i < 6; i++) {
|
|
Point startvertex = {{ -2, 0, 4, 0 }};
|
|
vertices[i] = point_mul(startvertex, point_rot(2*i));
|
|
}
|
|
|
|
/*
|
|
* Draw the hex itself.
|
|
*/
|
|
gr_draw_hex(gr, -1, h, vertices);
|
|
|
|
if (gr->vertex_blobs) {
|
|
/*
|
|
* Draw edge-division blobs on all vertices, to match the ones on
|
|
* the expansion diagrams.
|
|
*/
|
|
for (i = 0; i < 6; i++) {
|
|
gr_draw_blob(gr, (i == 0 ? "startpoint" : "edgesep"),
|
|
gr_logcoords(vertices[i]), (i == 0 ? 0.6 : 0.3));
|
|
}
|
|
}
|
|
|
|
if (gr->number_edges) {
|
|
/*
|
|
* Draw the labels on its edges.
|
|
*/
|
|
for (i = 0; i < 6; i++) {
|
|
char buf[64];
|
|
double textheight = 0.8, offset = textheight * 0.2;
|
|
GrCoords start = gr_logcoords(vertices[i]);
|
|
GrCoords finish = gr_logcoords(vertices[(i+1) % 6]);
|
|
GrCoords len = { finish.x - start.x, finish.y - start.y };
|
|
GrCoords perp = { -len.y, +len.x };
|
|
GrCoords mid = { (start.x+finish.x)/2, (start.y+finish.y)/2 };
|
|
|
|
sprintf(buf, "%zu", i);
|
|
|
|
{
|
|
GrCoords pos = {
|
|
mid.x + offset * perp.x,
|
|
mid.y + offset * perp.y,
|
|
};
|
|
gr_draw_text(gr, pos, textheight, buf);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void draw_one_spectre(Graphics *gr)
|
|
{
|
|
size_t i, j;
|
|
Point vertices[14];
|
|
|
|
{
|
|
Point start = {{ 0, 0, 0, 0 }};
|
|
Point pos = start;
|
|
Point diag = {{ 2, 0, 0, 2 }};
|
|
Point dir = point_mul(diag, point_rot(9));
|
|
|
|
for (j = 0; j < 14; j++) {
|
|
vertices[j] = pos;
|
|
pos = point_add(pos, dir);
|
|
dir = point_mul(dir, point_rot(spectre_angles[(j+1) % 14]));
|
|
}
|
|
|
|
gr_draw_spectre(gr, NO_HEX, -1, vertices);
|
|
}
|
|
|
|
/*
|
|
* Draw the labels on the edges.
|
|
*/
|
|
if (gr->number_edges) {
|
|
for (i = 0; i < 14; i++) {
|
|
char buf[64];
|
|
double textheight = 0.8, offset = textheight * 0.2;
|
|
GrCoords start = gr_logcoords(vertices[i]);
|
|
GrCoords finish = gr_logcoords(vertices[(i+1) % 14]);
|
|
GrCoords len = { finish.x - start.x, finish.y - start.y };
|
|
GrCoords perp = { +len.y, -len.x };
|
|
GrCoords mid = { (start.x+finish.x)/2, (start.y+finish.y)/2 };
|
|
|
|
sprintf(buf, "%zu", i);
|
|
if (strlen(buf) > 1)
|
|
offset = textheight * 0.35;
|
|
|
|
{
|
|
GrCoords pos = {
|
|
mid.x + offset * perp.x,
|
|
mid.y + offset * perp.y,
|
|
};
|
|
gr_draw_text(gr, pos, textheight, buf);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
static void make_parent_tables(FILE *fp)
|
|
{
|
|
size_t i, j, k;
|
|
|
|
for (i = 0; i < 9; i++) {
|
|
fprintf(fp, "static const struct Possibility poss_%s[] = {\n",
|
|
hex_names[i]);
|
|
for (j = 0; j < 9; j++) {
|
|
for (k = 0; k < num_subhexes(j); k++) {
|
|
if (hexdata[j].subhexes[k] == i) {
|
|
fprintf(fp, " { HEX_%s, %zu, PROB_%s },\n",
|
|
hex_names[j], k, hex_names[j]);
|
|
}
|
|
}
|
|
}
|
|
fprintf(fp, "};\n");
|
|
}
|
|
|
|
fprintf(fp, "static const struct Possibility poss_spectre[] = {\n");
|
|
for (j = 0; j < 9; j++) {
|
|
for (k = 0; k < num_spectres(j); k++) {
|
|
fprintf(fp, " { HEX_%s, %zu, PROB_%s },\n",
|
|
hex_names[j], k, hex_names[j]);
|
|
}
|
|
}
|
|
fprintf(fp, "};\n");
|
|
}
|
|
|
|
int main(void)
|
|
{
|
|
size_t i;
|
|
FILE *fp = fopen("spectre-tables-auto.h", "w");
|
|
fprintf(fp,
|
|
"/*\n"
|
|
" * Autogenerated transition tables for the Spectre tiling.\n"
|
|
" * Generated by auxiliary/spectre-gen.c.\n"
|
|
" */\n\n");
|
|
|
|
for (i = 0; i < 9; i++) {
|
|
char buf[64];
|
|
sprintf(buf, "hexmap_%s.svg", hex_names[i]);
|
|
Graphics *gr = gr_new(buf, -11, +11, -20, +4.5, 13);
|
|
lay_out_hexagons(i, gr, fp);
|
|
gr_free(gr);
|
|
}
|
|
for (i = 0; i < 9; i++) {
|
|
char buf[64];
|
|
sprintf(buf, "specmap_%s.svg", hex_names[i]);
|
|
Graphics *gr = gr_new(buf, (i == HEX_S ? -14 : -11.5),
|
|
(i == HEX_G ? +10 : 0.5),
|
|
-2, +12, 15);
|
|
lay_out_spectres(i, gr, fp);
|
|
gr_free(gr);
|
|
}
|
|
for (i = 0; i < 9; i++) {
|
|
char buf[64];
|
|
sprintf(buf, "basehex_%s.svg", hex_names[i]);
|
|
Graphics *gr = gr_new(buf, -4, +4, -4.2, +4.5, 15);
|
|
draw_base_hex(i, gr);
|
|
gr_free(gr);
|
|
}
|
|
for (i = 0; i < 9; i++) {
|
|
char buf[64];
|
|
sprintf(buf, "jigsawhex_%s.svg", hex_names[i]);
|
|
Graphics *gr = gr_new(buf, -4, +4, -4.2, +4.5, 20);
|
|
gr->jigsaw_mode = true;
|
|
gr->vertex_blobs = false;
|
|
gr->number_edges = false;
|
|
draw_base_hex(i, gr);
|
|
gr_free(gr);
|
|
}
|
|
{
|
|
Graphics *gr = gr_new("basehex_null.svg", -4, +4, -4.2, +4.5, 20);
|
|
gr->vertex_blobs = false;
|
|
draw_base_hex(NO_HEX, gr);
|
|
gr_free(gr);
|
|
}
|
|
{
|
|
Graphics *gr = gr_new("basespec_null.svg", -7, +6, -14, +1, 15);
|
|
gr->vertex_blobs = false;
|
|
draw_one_spectre(gr);
|
|
gr_free(gr);
|
|
}
|
|
{
|
|
Graphics *gr = gr_new("hexmap_null.svg", -11, +11, -20, +4.5, 10);
|
|
gr->vertex_blobs = false;
|
|
gr->number_edges = false;
|
|
gr->hex_arrows = false;
|
|
lay_out_hexagons(NO_HEX, gr, NULL);
|
|
gr_free(gr);
|
|
}
|
|
{
|
|
Graphics *gr = gr_new("specmap_null.svg", -11.5, +10, -2, +12, 15);
|
|
gr->vertex_blobs = false;
|
|
gr->number_edges = false;
|
|
gr->hex_arrows = false;
|
|
lay_out_spectres(NO_HEX, gr, NULL);
|
|
gr_free(gr);
|
|
}
|
|
for (i = 0; i < 2; i++) {
|
|
char buf[64];
|
|
sprintf(buf, "jigsawexpand_%s.svg", hex_names[i]);
|
|
Graphics *gr = gr_new(buf, -11, +11, -20, +4.5, 10);
|
|
gr->jigsaw_mode = true;
|
|
gr->vertex_blobs = false;
|
|
gr->number_edges = false;
|
|
lay_out_hexagons(i, gr, fp);
|
|
gr_free(gr);
|
|
}
|
|
make_parent_tables(fp);
|
|
fclose(fp);
|
|
return 0;
|
|
}
|