This adds an extra parameter to move_cursor() that's an optional pointer
to a bool indicating whether the cursor is visible. This allows for
centralising the common idiom of having the keyboard cursor become
visible when a cursor key is pressed. Consistently with the vast
majority of existing puzzles, the cursor moves even if it was invisible
before, and becomes visible even if it can't move.
The function now also returns one of the special constants that can be
returned by interpret_move(), so that the caller can correctly return
MOVE_UI_UPDATE or MOVE_NO_EFFECT without needing to carefully check for
changes itself.
Callers are updated only to the extent that they all pass NULL as the
new argument. Most of them could now be substantially simplified.
A test-build with a modern clang points out a number of 'set but not
used' variables, which clang seems to have got better at recently.
In cases where there's conditioned-out or commented-out code using the
variable, I've left it in and added a warning-suppressing cast to
void. Otherwise I've just deleted the variables.
All the other constants named UI_* are special key names that can be
passed to midend_process_key(), but UI_UPDATE is a special return value
from the back-end interpret_move() function instead. This renaming
makes the distinction clear and provides a naming convention for future
special return values from interpret_move().
Normally, we put two spaces between row clues, but if there are a lot
then even with a smaller font size they might overflow the left edge
of the window. To compensate, go down to one space between clues
instead of two if there are a lot of them. On my laptop the GTK build
demonstrates overflow with "13x1:1//1//1//1//1//1//1/1.1.1.1.1.1.1".
If you have a particularly large number of clues in a row, they can
end up falling off the left edge of the window. This used not to be a
problem because the rendering code would squash them closer together
if necessary. But then I switched to drawing them all as a single
string (so that two-digit row clues would get enough space with a
large font) and that broke the old mechanism.
Now we detect if there are enough clues that our conservative guess at
the string length looks like overflowing in the big font, and switch
to the small one if necessary. If we had a drawing call to measure a
string then we could be cleverer about this, but we don't.
This problem can be demonstrated with "7x1:1//1//1//1/1.1.1.1" in the
GTK port with the fonts my laptop has.
I think overflow can still occur even with a small font, so once I've
demonstrated that I'll try to fix it.
These are similar to the existing pair configure() and custom_params()
in that get_prefs() returns an array of config_item describing a set
of dialog-box controls to present to the user, and set_prefs()
receives the same array with answers filled in and implements the
answers. But where configure() and custom_params() operate on a
game_params structure, the new pair operate on a game_ui, and are
intended to permit GUI configuration of all the settings I just moved
into that structure.
However, nothing actually _calls_ these routines yet. All I've done in
this commit is to add them to 'struct game' and implement them for the
functions that need them.
Also, config_item has new fields, permitting each config option to
define a machine-readable identifying keyword as well as the
user-facing description. For options of type C_CHOICES, each choice
also has a keyword. These keyword fields are only defined at all by
the new get_prefs() function - they're left uninitialised in existing
uses of the dialog system. The idea is to use them when writing out
the user's preferences into a configuration file on disk, although I
haven't actually done any of that work in this commit.
I'm about to move some of the bodgy getenv-based options so that they
become fields in game_ui. So these functions, which could previously
access those options directly via getenv, will now need to be given a
game_ui where they can look them up.
Some nonogram implementations allow zero clues so that a row or column
with a single zero clue is equivalent to one with no clues, that is it
has no black squares in it. Pattern, however, doesn't interpret them
like this and treats a puzzle with a zero clue as insoluble, so it's
not helpful to permit them.
Permitting zero clues also confuses Pattern's memory allocation so
that it can suffer a buffer overrun. As an example, before this
commit a build with AddressSanitizer would report a buffer overrun
with the description "1:0/0.0" because it tries to put two clues in a
row that can have a maximum of one.
The majority of back-ends define encode_ui() to return NULL and
decode_ui() to do nothing. This commit allows them to instead specify
the relevant function pointers as NULL, in which case the mid-end won't
try to call them.
I'm planning to add a parameter to decode_ui(), and if I'm going to have
to touch every back-end's version of decode_ui(), I may as well ensure
that most of them never need to be touched again. And obviously
encode_ui() should go the same way for symmetry.
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.
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.
If you define PUZZLES_INITIAL_CURSOR=y, puzzles that have a keyboard
cursor will default to making it visible rather than invisible at the
start of a new game. Behaviour is otherwise the same, so mouse actions
will cause the cursor to vanish and keyboard actions will cause it to
appear. It's just the default that has changed.
The purpose of this is for use on devices and platforms where the
primary or only means of interaction is keyboard-based. In those cases,
starting with the keyboard cursor invisible is weird and a bit
confusing.
After Ben fixed all the unwanted global functions by using gcc's
-Wmissing-declarations to spot any that were not predeclared, I
remembered that clang has -Wmissing-variable-declarations, which does
the same job for global objects. Enabled it in -DSTRICT=ON, and made
the code clean under it.
Mostly this was just a matter of sticking 'static' on the front of
things. One variable was outright removed ('verbose' in signpost.c)
because after I made it static clang was then able to spot that it was
also unused.
The more interesting cases were the ones where declarations had to be
_added_ to header files. In particular, in COMBINED builds, puzzles.h
now arranges to have predeclared each 'game' structure defined by a
puzzle backend. Also there's a new tiny header file gtk.h, containing
the declarations of xpm_icons and n_xpm_icons which are exported by
each puzzle's autogenerated icon source file and by no-icon.c. Happily
even the real XPM icon files were generated by our own Perl script
rather than being raw xpm output from ImageMagick, so there was no
difficulty adding the corresponding #include in there.
If can_configure is false, then the game's configure() and
custom_params() functions will never be called. If can_solve is false,
solve() will never be called. If can_format_as_text_ever is false,
can_format_as_text_now() and text_format() will never be called. If
can_print is false, print_size() and print() will never be called. If
is_timed is false, timing_state() will never be called.
In each case, almost all puzzles provided a function nonetheless. I
think this is because in Puzzles' early history there was no "game"
structure, so the functions had to be present for linking to work. But
now that everything indirects through the "game" structure, unused
functions can be left unimplemented and the corresponding pointers set
to NULL.
So now where the flags mentioned above are false, the corresponding
functions are omitted and the function pointers in the "game" structures
are NULL.
I'd failed to initialise the row clue string to empty so it got the
contents of the previous row to be displayed. This could only happen
for imported descriptions, or for puzzles with one or two columns.
Thanks to Glen Sawyer for spotting and reporting the bug.
If all the column clues are single digits, then the font can be larger
without adjacent clues getting too close to each other. I've also
slightly increased the font size even with two-digit clues, from
TILE_SIZE/2 to TILE_SIZE/1.8.
Rather than centring each clue in an imaginary box, put equal amounts of
space between them (using space characters) and then right-align the
whole string. This makes for more efficient use of space, and I think
it also looks better when there are two-digit clues.
This does introduce a rather grotty (if large) fixed-size buffer for row
clues. Probably the row clues should be pre-formatted into a string
when the puzzle is set up.
Since the drawing API offers no guarantees about where text drawing
might have effects, it's unsafe to erase text other than by wiping the
clipping rectangle that was in effect when it was drawn. In practice,
this means that all variable (including colour) text should be drawn
with a narrow clipping rectangle.
It wasn't actually a practical problem that Pattern didn't clip its
clues, but I'll like to make its fonts less tiny, which will make it
more likely to need clipping in odd cases.
This also factors out some repeated computations in draw_numbers().
This provides a way for the front end to ask how a particular key should
be labelled right now (specifically, for a given game_state and
game_ui). This is useful on feature phones where it's conventional to
put a small caption above each soft key indicating what it currently
does.
The function currently provides labels only for CURSOR_SELECT and
CURSOR_SELECT2. This is because these are the only keys that need
labelling on KaiOS.
The concept of labelling keys also turns up in the request_keys() call,
but there are quite a few differences. The labels returned by
current_key_label() are dynamic and likely to vary with each move, while
the labels provided by request_keys() are constant for a given
game_params. Also, the keys returned by request_keys() don't generally
include CURSOR_SELECT and CURSOR_SELECT2, because those aren't necessary
on platforms with pointing devices. It might be possible to provide a
unified API covering both of this, but I think it would be quite
difficult to work with.
Where a key is to be unlabelled, current_key_label() is expected to
return an empty string. This leaves open the possibility of NULL
indicating a fallback to button2label or the label specified by
request_keys() in the future.
It's tempting to try to implement current_key_label() by calling
interpret_move() and parsing its output. This doesn't work for two
reasons. One is that interpret_move() is entitled to modify the
game_ui, and there isn't really a practical way to back those changes
out. The other is that the information returned by interpret_move()
isn't sufficient to generate a label. For instance, in many puzzles it
generates moves that toggle the state of a square, but we want the label
to reflect which state the square will be toggled to. The result is
that I've generally ended up pulling bits of code from interpret_move()
and execute_move() together to implement current_key_label().
Alongside the back-end function, there's a midend_current_key_label()
that's a thin wrapper around the back-end function. It just adds an
assertion about which key's being requested and a default null
implementation so that back-ends can avoid defining the function if it
will do nothing useful.
I don't know how I've never thought of this before! Pretty much every
game in this collection has to have a mechanism for noticing when
game_redraw is called for the first time on a new drawstate, and if
so, start by covering the whole window with a filled rectangle of the
background colour. This is a pain for implementers, and also awkward
because the drawstate often has to _work out_ its own pixel size (or
else remember it from when its size method was called).
The backends all do that so that the frontends don't have to guarantee
anything about the initial window contents. But that's a silly
tradeoff to begin with (there are way more backends than frontends, so
this _adds_ work rather than saving it), and also, in this code base
there's a standard way to handle things you don't want to have to do
in every backend _or_ every frontend: do them just once in the midend!
So now that rectangle-drawing operation happens in midend_redraw, and
I've been able to remove it from almost every puzzle. (A couple of
puzzles have other approaches: Slant didn't have a rectangle-draw
because it handles even the game borders using its per-tile redraw
function, and Untangle clears the whole window on every redraw
_anyway_ because it would just be too confusing not to.)
In some cases I've also been able to remove the 'started' flag from
the drawstate. But in many cases that has to stay because it also
triggers drawing of static display furniture other than the
background.
The Rockbox frontend allows games to be displayed in a "zoomed-in"
state targets with small displays. Currently we use a modal interface
-- a "viewing" mode in which the cursor keys are used to pan around
the rendered bitmap; and an "interaction" mode that actually sends
keys to the game.
This commit adds a midend_get_cursor_location() function to allow the
frontend to retrieve the backend's cursor location or other "region of
interest" -- such as the player location in Cube or Inertia.
With this information, the Rockbox frontend can now intelligently
follow the cursor around in the zoomed-in state, eliminating the need
for a modal interface.
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.
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.
encode_params, validate_params and new_desc now take a bool parameter;
fetch_preset, can_format_as_text_now and timing_state all return bool;
and the data fields is_timed, wants_statusbar and can_* are all bool.
All of those were previously typed as int, but semantically boolean.
This commit changes the API declarations in puzzles.h, updates all the
games to match (including the unfinisheds), and updates the developer
docs as well.
This function gives the front end a way to find out what keys the back
end requires; and as such it is mostly useful for ports without a
keyboard. It is based on changes originally found in Chris Boyle's
Android port, though some modifications were needed to make it more
flexible.
This allows me to use different types for the mutable, dynamically
allocated string value in a C_STRING control and the fixed constant
list of option names in a C_CHOICES.
Now midend.c directly tests the returned pointer for equality to this
value, instead of checking whether it's the empty string.
A minor effect of this is that games may now return a dynamically
allocated empty string from interpret_move() and treat it as just
another legal move description. But I don't expect anyone to be
perverse enough to actually do that! The main purpose is that it
avoids returning a string literal from a function whose return type is
a pointer to _non-const_ char, i.e. we are now one step closer to
being able to make this code base clean under -Wwrite-strings.
Now, with an odd grid size, we choose the posterisation threshold so
that half the time it delivers ceil(n/2) black squares and half the
time it delivers floor(n/2). Previously it only did the former, which
meant that asking Pattern to generate a 1x1 puzzle (with the bug in
the previous commit fixed) would always generate the one with a single
black square, and never the one with a single white square. Both are
trivial to solve, of course, but it seemed inelegant!
No change to the number of black squares in the puzzle solution can
constitute a spoiler for the player, of course, because that number is
trivial to determine without doing any difficult reasoning, just by
adding up all the clues in one dimension.
We were filling in a row immediately as all-white if it had no clues
at all, but weren't filling in a row as all-black if it had a single
clue covering the entire row. Now we do both.
In particular, this caused the Pattern solver to be unable to take
advantage of one of the two kinds of totally obvious clue across the
_easy_ dimension of a trivial 1xN puzzle - and a special case of
_that_, as a user pointed out, is that the game generator hangs trying
to create a 1x1 puzzle, which ought to be the easiest thing in the
world!
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.
This utility works basically the same as galaxiespicture: you feed it
a .xbm bitmap on standard input, and it constructs a game ID which
solves to exactly that image. It will pre-fill some squares if that's
necessary to resolve ambiguity, or leave the grid completely blank if
it can.
The game previously only supported numeric clues round the edge; but
if for some reason you really want a puzzle with a specific solution
bitmap and that bitmap doesn't happen to be uniquely soluble from only
its row and column counts, then this gives you a fallback approach of
pre-filling a few grid squares to resolve the ambiguities.
(This also applies if the puzzle is uniquely soluble *in principle*
but not by Pattern's limited solver - for example, Pattern has never
been able to solve 4x4:2/1/2/1/1.1/2/1/1 and still can't, but now it
can solve 4x4:2/1/2/1/1.1/2/1/1,Ap which has the hard part done for
it.)
Immutable squares are protected from modification during play, and
used as initial information by the solver.
The algorithm for deducing how many squares in a row could be filled
in just from the initial clue set was focusing solely on _black_
squares, and forgot that if a row has a totally empty clue square then
everything in it can be filled in as white!
Now the solver can cope with puzzles such as 3x3:/1///1/ , where it
would previously have spuriously considered that it had no idea where
to start.
The game_state now includes a pointer to a game_state_common
containing all the row and column clues, which is reference-counted
and therefore doesn't have to be physically copied in every dup_game.
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]
do_recurse() now prunes early whenever it encounters a branch of the
search tree inconsistent with existing grid data (rather than the
previous naive approach of proceeding to enumerate all possibilities
anyway and then ruling them out one by one); do_recurse also tries to
split the row up into independent sections where possible; finally the
main solver loop (all three copies of which have now been factored out
into a new solve_puzzle function), instead of simply looping round and
round over all the rows and columns, heuristically looks at the ones
most changed since the last time deduction was attempted on them, on
the basis that that will probably yield the most information the
fastest.
[originally from svn r9828]
draw_numbers() was considerably confused between the width of the clue
border at the left and the height of the clue border at the top.
Unconfuse it (I think).
[originally from svn r9737]
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]
that _ought_ to have it but did not.
I've tried to implement it before and found that the most obvious
approach was so effective as to constitute a spoiler, so this is a
deliberately weakened approach which in a bit of play-testing seems to
be a more sensible balance. It won't necessarily tell you at the very
instant you put a foot wrong, but it will at least ensure that (my
usual minimum standard) once you've filled in the whole grid you will
either have seen a victory flash, or an error indicator showing you
why not.
[originally from svn r9445]