17 Commits

Author SHA1 Message Date
e6cdd70df8 grid.c: allocate face/edge/dot arrays incrementally.
Previously, the 'faces', 'edges' and 'dots' arrays in a grid structure
were arrays of actual grid_face, grid_edge and grid_dot structures,
physically containing all the data about the grid. But they also
referred to each other by pointers, which meant that they were hard to
realloc larger (you'd have to go through and rewrite all the pointers
whenever the base of an array moved). And _that_ meant that every grid
type had to figure out a reasonably good upper bound on the number of
all those things it was going to need, so that it could allocate those
arrays the right size to begin with, and not have to grow them
painfully later.

For some grid types - particularly the new aperiodic ones - that was
actually a painful part of the job. So I think enough is enough:
counting up how much memory you're going to need before using it is a
mug's game, and we should instead realloc on the fly.

So now g->faces, g->edges and g->dots have an extra level of
indirection. Instead of being arrays of actual structs, they're arrays
of pointers, and each struct in them is individually allocated. Once a
grid_face has been allocated, it never moves again, even if the array
of pointers changes size.

The old code had a common idiom of recovering the array index of a
particular element by subtracting it from the array base, e.g. writing
'f - g->faces' or 'e - g->edges'. To make that lookup remain possible,
I've added an 'index' field to each sub-structure, which is
initialised at the point where we decide what array index it will live
at.

This should involve no functional change, but the code that previously
had to figure out max_faces and max_dots up front for each grid type
is now completely gone, and nobody has to solve those problems in
advance any more.
2023-07-07 18:17:02 +01:00
a33d9fad02 Loopy / grid.c: support the new Spectre monotiling.
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.
2023-06-16 19:15:47 +01:00
8d6647548f Loopy / grid.c: new grid type, 'Hats'.
The big mathematical news this month is that a polygon has been
discovered that will tile the plane but only aperiodically. Penrose
tiles achieve this with two tile types; it's been an open question for
decades whether you could do it with only one tile. Now someone has
announced the discovery of such a thing, so _obviously_ this
mathematically exciting tiling ought to be one of the Loopy grid
options!

The polygon, named a 'hat' by its discoverers, consists of the union
of eight cells of the 'Kites' periodic tiling that Loopy already
implements. So all the vertex coordinates of the whole tiling are
vertices of the Kites grid, which makes handling the coordinates in an
exact manner a lot easier than Penrose tilings.

What's _harder_ than Penrose tilings is that, although this tiling can
be generated by a vaguely similar system of recursive expansion, the
expansion is geometrically distorting, which means you can't easily
figure out which tiles can be discarded early to save CPU. Instead
I've come up with a completely different system for generating a patch
of tiling, by using a hierarchical coordinate system to track a
location within many levels of the expansion process without ever
simulating the process as a whole. I'm really quite pleased with that
technique, and am tempted to try switching the Penrose generator over
to it too - except that we'd have to keep the old generator around to
stop old game ids being invalidated, and also, I think it would be
slightly trickier without an underlying fixed grid and without
overlaps in the tile expansion system.

However, before coming up with that, I got most of the way through
implementing the more obvious system of actually doing the expansions.
The result worked, but was very slow (because I changed approach
rather than try to implement tree-pruning under distortion). But the
code was reusable for two other useful purposes: it generated the
lookup tables needed for the production code, and it also generated a
lot of useful diagrams. So I've committed it anyway as a supporting
program, in a new 'aux' source subdirectory, and in aux/doc is a
writeup of the coordinate system's concepts, with all those diagrams.
(That's the kind of thing I'd normally put in a huge comment at the
top of the file, but doing all those diagrams in ASCII art would be
beyond miserable.)

From a gameplay perspective: the hat polygon has 13 edges, but one of
them has a vertex of the Kites tiling in the middle, and sometimes two
other tile boundaries meet at that vertex. I've chosen to represent
every hat as having degree 14 for Loopy purposes, because if you only
included that extra vertex when it was needed, then people would be
forever having to check whether this was a 13-hat or a 14-hat and it
would be nightmarish to play.

Even so, there's a lot of clicking involved to turn all those fiddly
individual edges on or off. This grid is noticeably nicer to play in
'autofollow' mode, by setting LOOPY_AUTOFOLLOW in the environment to
either 'fixed' or 'adaptive'. I'm tempted to make 'fixed' the default,
except that I think it would confuse players of ordinary square Loopy!
2023-03-26 20:32:38 +01:00
d71bba1a17 Limit maximum grid size in Loopy
Every grid shape has its own limit, so this involved adding a new
interface between loopy.c and grid.c.  The limits are based on ensuring
that the co-ordinate system of the grid doesn't overflow INT_MAX and
neither do the lengths of the face and dot arrays.

Though now I come to look at it I think the actual limits of grid.c are
much lower.  Hmm.
2023-01-15 16:24:27 +00:00
56ef86f92b New grid type: compass dodecagonal
A grid based on dodecagons with square symmetry. In between dodecagons
there are 4 triangles around 1 square, which resembles a compass rose.
https://en.wikipedia.org/wiki/3-4-3-12_tiling
2021-04-22 06:24:23 +01:00
064da87682 Adopt C99 bool in the grid.c API.
More or less trivially: the only affected declaration is the
has_incentre flag in struct grid_face.
2018-11-13 21:48:24 +00:00
8af0c29615 New grid type: the trihexagonal tiling, or 'kagome lattice'.
Regular hexagons and equilateral triangles in strict alternation, with
two of each interleaved around each vertex.
https://en.wikipedia.org/wiki/Trihexagonal_tiling

Thanks to Michael Quevillon for the patch.
2017-11-18 15:26:13 +00:00
a58c1b216b Make the code base clean under -Wwrite-strings.
I've also added that warning option and -Werror to the build script,
so that I'll find out if I break this property in future.
2017-10-01 16:35:40 +01:00
e37d915f44 New Loopy tiling: 'Great Great Dodecagonal'.
Officially known as the '3-4-6-12 tiling', according to, e.g.,
https://en.wikipedia.org/wiki/3-4-6-12_tiling .

Thanks to Michael Quevillon for contributing this patch (and for
choosing a less hard-to-remember name for the tiling :-).
2017-04-24 17:09:39 +01:00
251b21c418 Giant const patch of doom: add a 'const' to every parameter in every
puzzle backend function which ought to have it, and propagate those
consts through to per-puzzle subroutines as needed.

I've recently had to do that to a few specific parameters which were
being misused by particular puzzles (r9657, r9830), which suggests
that it's probably a good idea to do the whole lot pre-emptively
before the next such problem shows up.

[originally from svn r9832]
[r9657 == 3b250baa02a7332510685948bf17576c397b8ceb]
[r9830 == 0b93de904a98f119b1a95d3a53029f1ed4bfb9b3]
2013-04-13 10:37:32 +00:00
62c20496bf From James Harvey (via a period of collaborative polishing), a patch
to add two kinds of Penrose tiling to the grid types supported by
Loopy.

This has involved a certain amount of infrastructure work, because of
course the whole point of Penrose tilings is that they don't have to
be the same every time: so now grid.c has grown the capacity to
describe its grids as strings, and reconstitute them from those string
descriptions. Hence a Penrose Loopy game description consists of a
string identifying a particular piece of Penrose tiling, followed by
the normal Loopy clue encoding.

All the existing grid types decline to provide a grid description
string, so their Loopy game descriptions have not changed encoding.

[originally from svn r9159]
2011-04-24 09:10:52 +00:00
5e3de7d95b Move most of face_text_pos() into grid.c, leaving in loopy.c only the
part that converts from abstract grid coordinates into screen
coordinates. This should speed up window-resizing by eliminating
pointless reiteration of the complicated part of the algorithm: now
when a game_drawstate is renewed, only the conversion into screen
coordinates has to be redone.

[originally from svn r9157]
2011-04-23 11:44:43 +00:00
7b2b742be8 Another patch from Chris Moore implementing two more grid types, both
involving dodecagons.

[originally from svn r9109]
2011-02-24 19:06:49 +00:00
621649491d Retire the 'middle_face' field in 'struct grid', together with the
overly complicated algorithm that uses it to home in on the grid edge
closest to a mouse click. That algorithm is being stressed beyond its
limit by the new grid type, and it's unnecessary anyway given that no
sensibly sized puzzle grid is going to be big enough to make it
prohibitively expensive just to do the trivial approach of iterating
over all edges and finding the closest of the eligible ones.

[originally from svn r9108]
2011-02-24 19:06:48 +00:00
53f6e4c6cb Patch from Chris Moore to implement an extra grid type, the 'floret'
pentagonal tiling.

[originally from svn r9107]
2011-02-23 20:05:42 +00:00
4033458aff How did I manage to check this in without actually trying to build
on Windows at all?! Fix some departures from the C standard, mostly
declaring variables after a statement has already been issued in the
same block. MSVC is picky about this where gcc is forgiving, and TBH
I'd change the latter given the choice.

[originally from svn r8166]
2008-09-07 08:35:52 +00:00
f38b711c73 Completely re-engineered version of Loopy, courtesy of Lambros
Lambrou. Now capable of handling triangular and hexagonal grids as
well as square ones, and then a number of semiregular plane tilings
and duals of semiregular ones. In fact, most of the solver code
supports an _arbitrary_ planar graph (well, provided both the graph
and its dual have no self-edges), so it could easily be extended
further with only a little more effort.

[originally from svn r8162]
2008-09-06 15:19:47 +00:00