gcc objects to this in -pedantic mode, which means other compilers are
technically entitled to object too if they like. Usually I try to
avoid it by putting a dummy value at the end of the enum, but I forgot
in this case.
(And I didn't notice, because _my_ local builds run without -pedantic,
on the grounds that configure.ac autodetects that my system's GTK
headers are not pedantic-clean. Oh well.)
Thanks to Glen Sawyer for reporting it. This is surely a consequence
of separating interpret_move from execute_move - if I'd done things in
the more obvious way, then this bug would never have happened, because
once the autofollow code had gone once round the loop it would find
that the starting edge was no longer in the same state it was looking
for. But since we don't start changing the states of edges until
execute_move(), it's possible for interpret_move() to go round and
round a cycle for ever.
Fortunately, it can _only_ happen if the edge you clicked on was part
of a loop which is the whole of its connected component - i.e. every
vertex in the cycle has degree 2 - and therefore we don't need O(N)
space to detect it (e.g. by recording whether each edge has been
visited already), but instead we can simply check if we've come back
to the starting edge.
This is mostly intended to make play more convenient for grid types
like the new Great-Great-Dodecagonal, and other grids with very
high-degree faces, in which it's annoying to have to spend half a
dozen mouse clicks on filling in a path of edges round the outside of
one of those faces which clearly have to all be set (or clear) if any
one of them is.
For now, the new feature is enabled by yet another of my hacky
environment variables, called LOOPY_AUTOFOLLOW. You can set it to
"off", "fixed" or "adaptive", where "off" is currently the default
(hence, no user-visible change in the default behaviour from this
change). If set to 'fixed', then toggling the state of any edge will
automatically toggle any further edges which are in the same state and
share a degree-2 vertex of the underlying grid design with the
original one. In 'adaptive' mode, the game goes even further, and will
consider outgoing edges in LINE_NO state not to count for purposes of
deciding if a vertex has degree 2.
This is the game for which I bothered to introduce the feature at all.
Because of the large number of grid types, the presets menu was
getting quite unwieldy; but because the grid dimensions for each grid
type are more or less arbitrary, it's still useful to have at least
one reasonably sized example of each grid type. So I've compromised by
moving some of the grid types into a 'More' submenu.
(I'm not particularly wedded to _which_ settings deserve relegation. I
may change my mind and move things about later on.)
To do this, I've completely replaced the API between mid-end and front
end, so any downstream front end maintainers will have to do some
rewriting of their own (sorry). I've done the necessary work in all
five of the front ends I keep in-tree here - Windows, GTK, OS X,
Javascript/Emscripten, and Java/NestedVM - and I've done it in various
different styles (as each front end found most convenient), so that
should provide a variety of sample code to show downstreams how, if
they should need it.
I've left in the old puzzle back-end API function to return a flat
list of presets, so for the moment, all the puzzle backends are
unchanged apart from an extra null pointer appearing in their
top-level game structure. In a future commit I'll actually use the new
feature in a puzzle; perhaps in the further future it might make sense
to migrate all the puzzles to the new API and stop providing back ends
with two alternative ways of doing things, but this seemed like enough
upheaval for one day.
The use of plain numbers was needlessly confusing, and in particular
made it too easy to make unintended changes to the existing Loopy
presets when inserting a new grid enum value anywhere other than at
the end of the list.
But in the course of doing this I realised that, against all
sensibleness, the numeric indices for grid types in grid.h and in
Loopy itself don't match up! Right now I don't want to get sidetracked
into fixing the structural confusion that made that happen in the
first place, but I've at least materialised Loopy's version of the
enum with clearly identifiable LOOPY_GRID_* names.
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 :-).
In commits 24848706e and adc54741f, I revamped the highlighting of
erroneous connected components of those two puzzles' solution graphs
in cases where a non-solution loop existed, so that the largest
component was considered correct and the smaller ones lit up in red.
I intended this to work in the cases where you have most of a correct
solution as one component and a small spurious loop as another (in
which case the latter lights up red), or conversely where your mostly
correct component was joined into a loop leaving a few edges out (in
which case the left-out edges again light up red). However, a user
points out that I overlooked the case where your mostly correct
solution is not all one component! If you've got lots of separate
pieces of path, and one tiny loop that's definitely wrong, it's silly
to light up all but the longest piece of path as if they're erroneous.
Fixed by treating all the non-loop components as one unit for these
purposes. So if there is at least one loop and it isn't the only thing
on the board, then we _either_ light up all loops (if they're all
smaller than the set of non-loop paths put together), _or_ light up
everything but the largest loop (if that loop is the biggest thing on
the board).
Some people don't bother to use the right-click UI action that marks a
line as 'definitely not' rather than the initial default yellow
'unknown'. Previously, Loopy gave those people a UI annoyance for some
classes of mistake they made during solving: it would reliably
highlight a clue square with too _many_ edges around it, but not one
with too few - because in normal right-click-ful play, a clue with too
few LINE_YES only becomes an error when there aren't enough
LINE_UNKNOWN around it to potentially become the remaining YESes in
future.
This change arranges that once the player closes the loop, _then_ we
light up underfilled clues, on the basis that adding any further edge
would be an obvious error, so it's no longer sensible to assume that
the user might be planning to come back and do so.
(It's not a very timely notification of errors - it's easy to imagine
someone making a mistake like this very near the start of play and
only finding out about it when they close the loop at the very end. I
discuss possible improvements in a comment, but I don't think any
improvement avoids that problem completely, so I think it may just be
a form of annoyance that right-click-less players have to live with.)
Loopy differs from the other recently-reworked puzzles in that it
doesn't disallow loops completely in the solution - indeed, one is
actually required! But not all loops are what you wanted, so you have
to be a bit more subtle in what you highlight as an error. And the new
findloop system doesn't make that easy, because it only answers the
question 'is this edge part of a loop?' and doesn't talk about loops
as a whole, or enumerate them.
But since I was working in this area anyway, I thought I might as well
have a think about it; and I've come up with a strategy that seems
quite sensible to me, which I describe in a big comment added in
loopy.c. In particular, the new strategy should make a more sensible
decision about whether to highlight the loop or the non-loop edges, in
cases where the user has managed to enter a loop plus some extra
stuff.
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]
new_desc. Oddities in the 'make test' output brought to my attention
that a few puzzles have been modifying their input game_params for
various reasons; they shouldn't do that, because that's the
game_params held permanently by the midend and it will affect
subsequent game generations if they modify it. So now those arguments
are const, and all the games which previously modified their
game_params now take a copy and modify that instead.
[originally from svn r9830]
sprintf in both locations (screen and print) that need it. Fixes a bug
in which clues greater than 9 came out as hex digits in printed
puzzles.
[originally from svn r9765]
conditionalised on !ds->started, so that we still do all the looping
over everything even if we know it's all going to be redrawn. This is
because deciding how much needs redrawing is not the only important
thing in those loops - they also set up arrays like ds->clue_error,
which tell the individual redraw functions _what_ to draw.
Fixes a bug in which, if you start a Loopy game and make moves causing
a clue to light up red for an error and then save your game, loading
the same save file at the start of a Loopy run would fail to highlight
the erroneous clue.
(This commit diff looks large, but actually it changes almost nothing
but whitespace.)
[originally from svn r9751]
basically just so that it can divide mouse coordinates by the tile
size, but is definitely not expected to _write_ to it, and it hadn't
previously occurred to me that anyone might try. Therefore,
interpret_move() now gets a pointer to a _const_ game_drawstate
instead of a writable one.
All existing puzzles cope fine with this API change (as long as the
new const qualifier is also added to a couple of subfunctions to which
interpret_move delegates work), except for the just-committed Undead,
which somehow had ds->ascii and ui->ascii the wrong way round but is
otherwise unproblematic.
[originally from svn r9657]
in the 'unfinished' directory for a while, and has now been finished
up thanks to James Harvey putting in some effort and galvanising me to
put in the rest. This is 'Pearl', an implementation of Nikoli's 'Masyu'.
The code in Loopy that generates a random loop along grid edges to use
as the puzzle solution has been abstracted out into loopgen.[ch] so
that Pearl can use it for its puzzle solutions too. I've also
introduced a new utility module called 'tdq' (for 'to-do queue').
[originally from svn r9379]
midend_status(), and given it three return codes for win, (permanent)
loss and game-still-in-play. Depending on what the front end wants to
use it for, it may find any or all of these three states worth
distinguishing from each other.
(I suppose a further enhancement might be to add _non_-permanent loss
as a fourth distinct status, to describe situations in which you can't
play further without pressing Undo but doing so is not completely
pointless. That might reasonably include dead-end situations in Same
Game and Pegs, and blown-self-up situations in Mines and Inertia.
However, I haven't done this at present.)
[originally from svn r9179]
arrays 'textx' and 'texty' to the game_drawstate but failed to
initialise them in the temporary drawstate used by game_print().
Thanks to Arun Giridhar for spotting this.
[originally from svn r9173]
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]
thereafter read. Most of these changes are just removal of pointless
stuff or trivial reorganisations; one change is actually substantive,
and fixes a bug in Keen's clue selection (the variable 'bad' was
unreferenced not because I shouldn't have set it, but because I
_should_ have referenced it!).
[originally from svn r9164]
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]
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]
darker than the background, because the Java front end demonstrates
that it's a bit eyewatering when it _matches_ the background.
[originally from svn r9145]
to have the effect of enabling large Easy-level grids to be
constructed in all grid types. Without this, some generations at Easy
level (e.g. 'loopy --generate 1 7x7t9de') can spin forever because
_even with all clues filled in_ the generated grids can't be solved at
that level.
[originally from svn r9143]
state is in a solved position, and a midend function wrapping it.
(Or, at least, a situation in which further play is pointless. The
point is, given that game state, would it be a good idea for a front
end that does that sort of thing to proactively provide the option to
start a fresh game?)
[originally from svn r9140]
it clears a clipping region that it knows what features will need
redrawing in that region. Instead, I've moved all the clip/unclip/draw
functionality out into a game_redraw_in_rect() function which checks
_everything_ on the grid to see if it lies in the region.
As far as I can tell the effect only shows up in grid types that
aren't checked in, but it makes the code look nicer too.
(It would be nicer still to avoid the brute-force loop over the whole
grid checking it against the bounding box, particularly when we're
drawing in multiple bounding boxes. But this will do for the moment.)
[originally from svn r9138]
drawn in a face: averaging the vertex positions works fine for regular
or roughly regular convex polygons, but it'll start being a pain for
odder or concave ones.
This is a kludgey brute-force algorithm; I have ideas about more
elegant ways of doing this job, but they're more fiddly, so I thought
I'd start with something that basically worked.
[originally from svn r9137]
they meet at sharp enough angles that the thick lines overlap
noticeably outside the circle of the point - redrawing the edges in a
different order each time looks ugly. Arrange to always redraw edges
in order of colour, so that empty lines are drawn before indeterminate
lines which in turn come before filled-in lines.
[originally from svn r9136]
properly antialiasing-safe: all redraws are now done by clearing a
rectangle of the image, clipping to that rectangle, and redrawing
everything in it exactly once.
[originally from svn r8963]
the drawing API, for use by Loopy. It's optional: drawing.c will
construct an acceptable alternative using a filled polygon if the
front end doesn't provide it.
Net and Netslide previously had static functions called
draw_thick_line(), whose claim to the name is less justified and so
they've been renamed.
[originally from svn r8962]
buttons in several games if STYLUS_BASED is defined: in games where
you can set a puzzle element to 'on', 'off' or 'not yet set', when
it's hard to mimic a second mouse button, it's better to have the
one 'button' cycle between all three states rather than from 'on'
back to 'unset'.
[originally from svn r8784]
Loopy mark LINE_NO grid edges with very faint lines, instead of
leaving them totally undrawn. Helps in complex grid types where the
line layout isn't entirely obvious to a player not already familiar
with it. Disableable by setting LOOPY_FAINT_LINES=n in the
environment, just in case anyone turns out to seriously dislike it.
(You could probably disable it via LOOPY_COLOUR_6 too, but you'd
have to know the exact shade of your background to get that right.)
[originally from svn r8597]
people have generally seemed to think Loopy is one of the more
difficult puzzles in the collection. There's a new level called
Tricky, between Normal and Hard, which is equivalent to the old
Normal.
[originally from svn r8398]
doesn't have diagnostics embedded and the ASCII formatter can't
print non-square puzzles anyway; but it can grade difficulty, which
is what I most immediately want it for.
[originally from svn r8397]
particular, Great Hexagonal tilings previously had virtually every
(if not _actually_ every) hexagon on the inside of the path, and now
don't.
[originally from svn r8277]
spins forever, but observes that raising the limit to 4x4 across all
grid types is not good for the complex grids like great-hexagonal.
Introduce per-grid minimum sizes using mad macro trickery.
(In fact, for each grid type I've put in a minimum size which _both_
dimensions must equal or exceed, plus another minimum size which _at
least one_ must equal or exceed; that permits both 3x4 and 4x3 Cairo
while disallowing 3x3.)
[originally from svn r8191]