aboutsummaryrefslogtreecommitdiff
path: root/grid.c (follow)
Commit message (Collapse)AuthorAge
* grid_edge_bydots_cmpfn: remove dangerous pointer comparison.Simon Tatham2023-07-14
| | | | | | | | | | | Commit e6cdd70df867f06 made the grid_dot structures for a grid no longer be elements of the same array. But I didn't notice that grid_edge_bydots_cmpfn was doing pointer subtraction on them on the assumption that they were. Fixed by comparing the dots' new index fields, which should correspond exactly to their previous positions in the single array, so the behaviour should be just what it was before the change.
* grid.c: new and improved Penrose tiling generator.Simon Tatham2023-07-07
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The new generator works on the same 'combinatorial coordinates' system as the more recently written Hats and Spectre generators. When I came up with that technique for the Hats tiling, I was already tempted to rewrite the Penrose generator on the same principle, because it has a lot of advantages over the previous technique of picking a randomly selected patch out of the subdivision of a huge starting tile. It generates the exact limiting distribution of possible tiling patches rather than an approximation based on how big a tile you subdivided; it doesn't use any overly large integers or overly precise floating point to suffer overflow or significance loss, because it never has to even _think_ about the coordinates of any point not in the actual output area. But I resisted the temptation to throw out our existing Penrose generator and move to the shiny new algorithm, for just one reason: backwards compatibility. There's no sensible way to translate existing Loopy game IDs into the new notation, so they would stop working, unless we kept the old generator around as well to interpret the previous system. And although _random seeds_ aren't guaranteed to generate the same result from one build of Puzzles to the next, I do try to keep existing descriptive game IDs working. So if we had to keep the old generator around anyway, it didn't seem worth writing a new one... ... at least, until we discovered that the old generator has a latent bug. The function that decides whether each tile is within the target area, and hence whether to make it part of the output grid, is based on floating-point calculation of the tile's vertices. So a change in FP rounding behaviour between two platforms could cause them to interpret the same grid description differently, invalidating a Loopy game on that grid. This is _unlikely_, as long as everyone uses IEEE 754 double, but the C standard doesn't actually guarantee that. We found this out when I started investigating a slight distortion in large instances of Penrose Loopy. For example, the Loopy random seed "40x40t11#12345", as of just before this commit, generates a game description beginning with the Penrose grid string "G-4944,5110,108", in which you can see a star shape of five darts a few tiles down the left edge, where two of the radii of the star don't properly line up with edges in the surrounding shell of kites that they should be collinear with. This turns out to be due to FP error: not because _double precision_ ran out, but because the definitions of COS54, SIN54, COS18 and SIN18 in penrose.c were specified to only 7 digits of precision. And when you expand a patch of tiling that large, you end up with integer combinations of those numbers with coefficients about 7 digits long, mostly cancelling out to leave a much smaller output value, and the inaccuracies in those constants start to be noticeable. But having noticed that, it then became clear that these badly computed values were also critical to _correctness_ of the grid. So they can't be fixed without invalidating old game IDs. _And_ then we realised that this also means existing platforms might disagree on a game ID's validity. So if we have to break compatibility anyway, we should go all the way, and instead of fixing the old system, introduce the shiny new system that gets all of this right. Therefore, the new penrose.c uses the more reliable combinatorial-coordinates system which doesn't deal in integers that large in the first place. Also, there's no longer any floating point at all in the calculation of tile vertex coordinates: the combinations of 1 and sqrt(5) are computed exactly by the n_times_root_k function. So now a large Penrose grid should never have obvious failures of alignment like that. The old system is kept for backwards compatibility. It's not fully reliable, because that bug hasn't been fixed - but any Penrose Loopy game ID that was working before on _some_ platform should still work on that one. However, new Penrose Loopy game IDs are based on combinatorial coordinates, computed in exact arithmetic, and should be properly stable. The new code looks suspiciously like the Spectre code (though considerably simpler - the Penrose coordinate maps are easy enough that I just hand-typed them rather than having an elaborate auxiliary data-generation tool). That's because they were similar enough in concept to make it possible to clone and hack. But there are enough divergences that it didn't seem like a good idea to try to merge them again afterwards - in particular, the fact that output Penrose tiles are generated by merging two triangular metatiles while Spectres are subdivisions of their metatiles.
* grid.c: add dot coordinates to debugging dumps.Simon Tatham2023-07-07
| | | | | | | I wanted these in order to try to check whether all the faces of a grid were being traversed in the right orientation. That turned out not to be the cause of my problem, but it's still useful information to put in diagnostics.
* grid.c: allocate face/edge/dot arrays incrementally.Simon Tatham2023-07-07
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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.
* Move mul_root3 out into misc.c and generalise it.Simon Tatham2023-07-07
| | | | I'm going to want to reuse it for sqrt(5) as well as sqrt(3) soon.
* Loopy / grid.c: support the new Spectre monotiling.Simon Tatham2023-06-16
| | | | | | | | | | | | | | 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.
* Reorganise the dsf API into three kinds of dsf.Simon Tatham2023-04-20
| | | | | | | | | | | | | | | | | | This is preparing to separate out the auxiliary functionality, and perhaps leave space for making more of it in future. The previous name 'edsf' was too vague: the 'e' stood for 'extended', and didn't say anything about _how_ it was extended. It's now called a 'flip dsf', since it tracks whether elements in the same class are flipped relative to each other. More importantly, clients that are going to use the flip tracking must say so when they allocate the dsf. And Keen's need to track the minimal element of an equivalence class is going to become a non-default feature, so there needs to be a new kind of dsf that specially tracks those, and Keen will have to call it. While I'm here, I've renamed the three dsf creation functions so that they start with 'dsf_' like all the rest of the dsf API.
* Declare all dsfs as a dedicated type name 'DSF'.Simon Tatham2023-04-20
| | | | | | | In this commit, 'DSF' is simply a typedef for 'int', so that the new declaration form 'DSF *' translates to the same type 'int *' that dsfs have always had. So all we're doing here is mechanically changing type declarations throughout the code.
* Use a dedicated free function to free dsfs.Simon Tatham2023-04-20
| | | | | No functional change: currently, this just wraps the previous sfree call.
* Fall back to <math.h> if <tgmath.h> doesn't work.Simon Tatham2023-04-06
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This fixes a build failure introduced by commit 2e48ce132e011e8 yesterday. When I saw that commit I expected the most likely problem would be in the NestedVM build, which is currently the thing with the most most out-of-date C implementation. And indeed the NestedVM toolchain doesn't have <tgmath.h> - but much more surprisingly, our _Windows_ builds failed too, with a compile error inside <tgmath.h> itself! I haven't looked closely into the problem yet. Our Windows builds are done with clang, which comes with its own <tgmath.h> superseding the standard Windows one. So you'd _hope_ that clang could make sense of its own header! But perhaps the problem is that this is an unusual compile mode and hasn't been tested. My fix is to simply add a cmake check for <tgmath.h> - which doesn't just check the file's existence, it actually tries compiling a file that #includes it, so it will detect 'file exists but is mysteriously broken' just as easily as 'not there at all'. So this makes the builds start working again, precisely on Ben's theory of opportunistically using <tgmath.h> where possible and falling back to <math.h> otherwise. It looks ugly, though! I'm half tempted to make a new header file whose job is to include a standard set of system headers, just so that that nasty #ifdef doesn't have to sit at the top of almost all the source files. But for the moment this at least gets the build working again.
* Replace <math.h> with <tgmath.h> throughoutBen Harris2023-04-04
| | | | | | | | | | | | | | | C89 provided only double-precision mathematical functions (sin() etc), and so despite using single-precision elsewhere, those are what Puzzles has traditionally used. C99 introduced single-precision equivalents (sinf() etc), and I hope it's been long enough that we can safely use them. Maybe they'll even be faster. Rather than directly use the single-precision functions, though, we use the magic macros from <tgmath.h> that automatically choose the precision of mathematical functions based on their arguments. This has the advantage that we only need to change which header we include, and thus that we can switch back again if some platform has trouble with the new header.
* Require a grid description for hats gridBen Harris2023-03-31
| | | | | Without this, you can cause a null-pointer dereference by passing Loopy a game description with no grid description, like "10x10t16:".
* Loopy / grid.c: new grid type, 'Hats'.Simon Tatham2023-03-26
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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!
* Limit maximum grid size in LoopyBen Harris2023-01-15
| | | | | | | | | | 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.
* New grid type: compass dodecagonalMichael Quevillon2021-04-22
| | | | | | 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
* grid.c: fix size miscalculation in Floret tiling.Simon Tatham2020-04-12
| | | | | | | | | | | | | A Floret grid of height h usually alternates columns of h hexagonal florets with columns of h-1. An exception is when h=1, in which case alternating columns of 1 and 0 florets would leave the grid disconnected. So in that situation all columns have 1 floret in them, and the starting y-coordinate oscillates to make the grid tile sensibly. However, that special case wasn't taken account of when calculating the grid height. As a result the anomalous extra florets in the height-1 tiling fell off the bottom of the puzzle window.
* Use C99 bool within source modules.Simon Tatham2018-11-13
| | | | | | | | | | This is the main bulk of this boolification work, but although it's making the largest actual change, it should also be the least disruptive to anyone interacting with this code base downstream of me, because it doesn't modify any interface between modules: all the inter-module APIs were updated one by one in the previous commits. This just cleans up the code within each individual source file to use bool in place of int where I think that makes things clearer.
* Replace TRUE/FALSE with C99 true/false throughout.Simon Tatham2018-11-13
| | | | | | This commit removes the old #defines of TRUE and FALSE from puzzles.h, and does a mechanical search-and-replace throughout the code to replace them with the C99 standard lowercase spellings.
* New grid type: the trihexagonal tiling, or 'kagome lattice'.Simon Tatham2017-11-18
| | | | | | | | 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.
* Make the code base clean under -Wwrite-strings.Simon Tatham2017-10-01
| | | | | 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.
* New Loopy tiling: 'Great Great Dodecagonal'.Simon Tatham2017-04-24
| | | | | | | | 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 :-).
* Sort out abs/fabs confusion.Simon Tatham2015-04-10
| | | | | | | | | | | | | | My Mac has just upgraded itself to include a version of clang which warns if you use abs() on a floating-point value, or fabs() on an integer. Fixed the two occurrences that came up in this build (and which were actual build failures, because of -Werror), one in each direction. I think both were benign. The potentially dangerous one was using abs in place of fabs in grid_find_incentre(), because that could actually lose precision, but I think that function had plenty of precision to spare (grid point separation being of the order of tens of pixels) so nothing should have gone seriously wrong with the old code.
* Fix grid generation crashes at Penrose 3x3 sizes. What seemed to beSimon Tatham2013-05-10
| | | | | | | | | | | | | | | happening was that at the point of calling grid_make_consistent, the grid had no faces or vertices, probably because grid_trim_vigorously had removed them all, causing grid_make_consistent to try to allocate a negative amount of memory and die in snewn. Fixed by detecting this case in new_desc_penrose and retrying until generation is successful. (It wasn't happening 100% of the time, just _most_ of the time.) The same verification step is also used in validate_desc_penrose in case a user manages to manually construct a set of parameters leading to this failure mode. [originally from svn r9840]
* Giant const patch of doom: add a 'const' to every parameter in everySimon Tatham2013-04-13
| | | | | | | | | | | | | | 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]
* Revamp the triangular grid generation in Loopy, which I've beenSimon Tatham2013-04-11
| | | | | | | | | | | | | | | | meaning to revisit for a while. The new version generates more nicely symmetric grids (best at even heights, but still improved even at odd heights), and avoids any 'ears' on the grid (triangles at the corners connected to only one other triangle, which tend to be boringly easy places to start solving). I've reused the grid-description-string mechanism invented for the Penrose tilings as a versioning mechanism for the triangular grids, so that old game descriptions should still be valid, and new triangular- grid game descriptions begin with an "0_" prefix to indicate that they are based on the new-style construction. [originally from svn r9824]
* Greg Hewgill points out a code path on which the angle parameter toSimon Tatham2013-04-01
| | | | | | the Penrose grid generation function can fail to be initialised. [originally from svn r9798]
* Apply the rotation in Penrose grid descriptions by rotating in theSimon Tatham2011-05-06
| | | | | | | | | | | | | | | | | | | | 4-vector representation, rather than mucking about with sines and cosines after grid generation. _Should_ make no difference in the generated grids (there's a theoretical risk of an unlucky rounding error just about managing to push some point in or out of bounds, but I think it's vanishingly small), but simplifies the coordinate- flattening procedure, and in particular increases its chance of getting vertical lines actually vertical. (Prior to this change, the game ID 10x10t12:G2554,-31,108_a3b12h0a212a3d102b2a23a2e3b01b0a2c2a0c0 was generating a not-quite-vertical edge at top left, in the Java port but not on Linux; I suspect differences in sin and cos as the cause of the discrepancy. With the rotation done like this, the points' x-coordinates are now computed without reference to their y-coordinates.) [originally from svn r9168]
* Portability fixes, mostly from James for Palm purposes. MostlySimon Tatham2011-05-04
| | | | | | | | additions of missing 'static' and explicit 'void' in parameter lists, plus one or two other things like explicitly casting chars in variadic argument lists to int and using DBL_MAX if HUGE_VAL isn't available. [originally from svn r9166]
* Fix two memory leaks reported by Tiago Dionizio in recent LoopySimon Tatham2011-04-26
| | | | | | development. [originally from svn r9163]
* Forgot to set 'has_incentre' on triangular grids, which don't useSimon Tatham2011-04-25
| | | | | | grid_face_add_new(). Oops. [originally from svn r9161]
* From James Harvey (via a period of collaborative polishing), a patchSimon Tatham2011-04-24
| | | | | | | | | | | | | | | | | | 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]
* Oops: initialise that new 'has_incentre' flag to false, otherwise theSimon Tatham2011-04-23
| | | | | | | game will sometimes pick random incentres in place of the carefully computed ones. Ahem. [originally from svn r9158]
* Move most of face_text_pos() into grid.c, leaving in loopy.c only theSimon Tatham2011-04-23
| | | | | | | | | | 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]
* Another patch from Chris Moore implementing two more grid types, bothSimon Tatham2011-02-24
| | | | | | involving dodecagons. [originally from svn r9109]
* Retire the 'middle_face' field in 'struct grid', together with theSimon Tatham2011-02-24
| | | | | | | | | | | 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]
* Patch from Chris Moore to implement an extra grid type, the 'floret'Simon Tatham2011-02-23
| | | | | | pentagonal tiling. [originally from svn r9107]
* Patch from Chris Moore to improve the generality ofSimon Tatham2011-02-23
| | | | | | | grid_nearest_edge(), by having it search harder for a better dot to move to in the first loop. [originally from svn r9106]
* Since the lack of this has caused portability issues in the past:Simon Tatham2008-09-13
| | | | | | | add "-ansi -pedantic" to the main Unix makefile, and clean up a few minor problems pointed out thereby. [originally from svn r8175]
* Patch from James H to make new-Loopy port more easily.Simon Tatham2008-09-10
| | | | [originally from svn r8174]
* How did I manage to check this in without actually trying to buildSimon Tatham2008-09-07
| | | | | | | | | 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]
* Completely re-engineered version of Loopy, courtesy of LambrosSimon Tatham2008-09-06
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]