51 Commits

Author SHA1 Message Date
14e1e05510 Introduce a new dsf_equivalent() function.
Not very interesting, but the idiom for checking equivalence via two
calls to dsf_canonify is cumbersome enough to be worth abbreviating.
2023-04-20 18:39:35 +01:00
348aac4c85 Remove size parameter from dsf init and copy functions.
Now that the dsf knows its own size internally, there's no need to
tell it again when one is copied or reinitialised.

This makes dsf_init much more about *re*initialising a dsf, since now
dsfs are always allocated using a function that will initialise them
anyway. So I think it deserves a rename.
2023-04-20 17:30:03 +01:00
89c438e149 Declare all dsfs as a dedicated type name 'DSF'.
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.
2023-04-20 17:23:21 +01:00
11a8149d67 Use a dedicated copy function to copy dsfs.
Previously we were duplicating the contents of a dsf using straight-up
memcpy. Now there's a dsf_copy function wrapping the same memcpy.

For the moment, this still has to take a size parameter, because the
size isn't stored inside the dsf itself. But once we make a proper
data type, it will be.
2023-04-20 17:21:54 +01:00
bb561ee3b1 Use a dedicated free function to free dsfs.
No functional change: currently, this just wraps the previous sfree
call.
2023-04-20 17:21:12 +01:00
418cb3a567 Make encode_ui() and decode_ui() optional in back-ends
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.
2023-04-08 20:08:16 +01:00
3b9cafa09f Fall back to <math.h> if <tgmath.h> doesn't work.
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.
2023-04-06 07:08:04 +01:00
2e48ce132e Replace <math.h> with <tgmath.h> throughout
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.
2023-04-04 21:43:25 +01:00
6dac51795e Add an environment variable to control initial cursor visibility
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.
2023-03-22 16:58:22 +00:00
09c15f206e New shared function, getenv_bool()
This provides a standard way to get a boolean from an environment
variable.  It treats the variable as true iff its value begins with 'y'
or 'Y', like most of the current implementations.  The function takes a
default value which it returns if the environment variable is undefined.

This replaces the various ad-hoc tests of environment variable scattered
around and mostly doesn't change their behaviour.  The exceptions are
TOWERS_2D in Towers and DEBUG_PUZZLES in the Windows front end.  Both of
those were treated as true if they were defined at all, but now follow
the same rules as other boolean environment variables.
2023-03-22 16:06:18 +00:00
26c7f3aa28 Miscellaneous const fixes
These are cases where -Wcast-qual complained and the only change needed
was to add or remove a "const" (or sometimes an entire cast).
2023-02-18 23:14:12 +00:00
873d613dd5 Fix missing statics and #includes on variables.
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.
2023-02-18 08:55:13 +00:00
0186d78da9 Mark many more function (and some objects) static
I noticed commit db3b531e2cab765a00475054d2e9046c9d0437d3 in the history
where Simon added a bunch of "static" qualifiers.  That suggested that
consistently marking internal functions "static" is desirable, so I
tried a build using GCC's -Wmissing-declarations, which requires prior
declaration (presumed to be in a header file) of all global functions.

This commit makes the GTK build clean under GCC's
-Wmissing-declarations.  I've also adding "static" to a few obviously
internal objects, but GCC doesn't complain about those so I certainly
haven't got them all.
2023-02-18 00:13:15 +00:00
789e11f8f8 Remove various unused game functions
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.
2023-01-31 23:25:05 +00:00
5c36e1536a Last-ditch maximum size limit for Signpost
This makes sure that width * height <= INT_MAX, which it rather needs
to be.
2023-01-15 16:24:27 +00:00
a3310ab857 New backend function: current_key_label()
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.
2022-12-09 20:48:30 +00:00
c0da615a93 Centralise initial clearing of the puzzle window.
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.
2021-04-25 13:07:59 +01:00
78bc9ea7f7 Add method for frontends to query the backend's cursor location.
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.
2020-12-07 19:40:06 +00:00
5f5b284c0b Use C99 bool within source modules.
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.
2018-11-13 21:48:24 +00:00
a550ea0a47 Replace TRUE/FALSE with C99 true/false throughout.
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.
2018-11-13 21:48:24 +00:00
a76d269cf2 Adopt C99 bool in the game backend API.
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.
2018-11-13 21:34:42 +00:00
60a929a250 Add a request_keys() function with a midend wrapper.
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.
2018-04-22 17:04:50 +01: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
b3243d7504 Return error messages as 'const char *', not 'char *'.
They're never dynamically allocated, and are almost always string
literals, so const is more appropriate.
2017-10-01 16:34:41 +01:00
de67801b0f Use a proper union in struct config_item.
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.
2017-10-01 16:34:41 +01:00
eeb2db283d New name UI_UPDATE for interpret_move's return "".
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.
2017-10-01 15:18:14 +01:00
a7dc17c425 Rework the preset menu system to permit submenus.
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.
2017-04-26 21:51:23 +01:00
b95812963a Clarify conditions to avoid compiler errors
Fix errors pointed out by clang

error: logical not is only applied to the left hand side of this bitwise operator [-Werror,-Wlogical-not-parentheses]
|         if (only_immutable && !copy->flags[i] & FLAG_IMMUTABLE) continue;
|                               ^

Signed-off-by: Khem Raj <raj.khem@gmail.com>
2016-12-06 21:40:24 +00:00
bda4a963f4 Fix an instance generation hang in Signpost.
Also expand the set of permissible parameters (add 1xN, Nx1 and 2x2).
2015-10-03 17:12:20 +01:00
52a0f3c32a Special-case right-dragging of a numbered cell off the grid.
Chris Boyle reports that if you right-drag a numbered cell off the
grid, _all_ numbered cells (except the immutable initial clues) get
reset to blank, because this is treated as an attempt to erase a whole
chain of linked cells (of the form a,a+1,...,a_k) and the cells with
definite numbers are all treated as 'chain 0'.

In that situation, I now substitute the same behaviour you'd get by
left-dragging the numbered cell off the board, i.e. erase _just_ that
cell and not the whole of the rest of the puzzle.

(The previous unintended behaviour was a UI action you surely never
want - and Chris also reports that due to the Android front end's way
of representing right-drags, it's especially easy to hit by mistake.)
2015-05-09 15:38:48 +01:00
7f64f4a50e Sort out abs/fabs confusion.
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.
2015-04-10 07:58:26 +01:00
ffe0aa6a11 Fix a build failure on x32 (time_t printfs).
As that architecture has 64-bit time_t but only 32-bit longs, printf format
causes a warning.  Enter -Werror...
2015-03-09 18:03:20 +00: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
0b93de904a Add 'const' to the game_params arguments in validate_desc and
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]
2013-04-12 17:11:49 +00:00
3b250baa02 New rule: interpret_move() is passed a pointer to the game_drawstate
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]
2012-09-09 18:40:12 +00:00
5e1c11ab69 Trivial and silly patch to allow users to configure the Signpost
victory roll so that adjacent arrows rotate in opposite directions,
giving the impression that they're an interlocking field of gears.
Possibly even more brain-twisting than the original version :-)

[originally from svn r9384]
2012-01-22 15:52:14 +00:00
295fb9fd83 When we run out of background colours for chains and wrap back to the
beginning, we should wrap back to COL_B0+1 rather than COL_B0 itself,
so as not to reuse white. White should be special, and always indicate
a properly numbered square.

[originally from svn r9305]
2011-09-18 07:43:18 +00:00
7f8919952f Patch from Chris Boyle to fix Signpost's labelling when you have more
than 26 separate linked chains of unnumbered squares: we now wrap from
'z' to an Excel-like 'aa', 'ab', ..., instead of falling off z into
punctuation and control characters.

[originally from svn r9304]
2011-09-18 07:43:18 +00:00
73daff3937 Changed my mind about midend_is_solved: I've now reprototyped it as
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]
2011-06-19 13:43:35 +00:00
89bfecaa5a Portability fixes, mostly from James for Palm purposes. Mostly
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]
2011-05-04 18:41:21 +00:00
980880be1f Add a function to every game backend which indicates whether a game
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]
2011-04-02 16:19:12 +00:00
c539872613 A user points out that Signpost doesn't in fact use the numeric
keypad, so it shouldn't have the REQUIRE_NUMPAD flag.

[originally from svn r8939]
2010-05-09 07:22:16 +00:00
0a9b0a7384 Fix incorrect uses of ctype.h (passing it uncast chars, or other
things potentially not in the range 0..255).

[originally from svn r8922]
2010-04-17 13:27:15 +00:00
945d8f0a3a Fix from James H for an assertion failure during Signpost
generation. To reproduce, try 'signpost --generate 1 7x7#12345-162'.

[originally from svn r8921]
2010-04-17 13:27:12 +00:00
8e74bbae6b Dylan O'Donnell reports that Signpost hangs on trying to generate a
2x2 puzzle. Rule it out in validate_params().

[originally from svn r8913]
2010-04-02 07:21:34 +00:00
66aef80d62 Fixes from James H to the numbering of squares, in particular:
- sometimes two regions would get the same letter
 - immutable numbers could sometimes be modified
 - immutable numbers are now not flagged as errors when they clash
   (same as Solo's policy)

[originally from svn r8882]
2010-02-22 23:14:46 +00:00
d54bbdadee Fix build failure on MacOS by initialising a variable which was
reported as potentially-unused. (In fact, as far as I can tell, it's
only ever uninitialised in assertion-failing code paths, so not a
real bug.)

[originally from svn r8873]
2010-02-18 18:12:12 +00:00
7011d13ae7 A proper fix from James H for the negative number issue: the
assertion I crudely commented out has now been replaced with code
that clearly shows what you did wrong in the failing situation.

[originally from svn r8872]
2010-02-17 19:15:04 +00:00
2887a1da69 'Fix' an assertion failure during play: accidentally connecting a
long chain to a square numbered so low that the start of the chain
would have to go into negative numbers should not crash the game,
particularly when it happens as a momentary in-passing illustration.

I've fixed it for the moment just by removing the assertion. There's
probably a better fix which causes something less strange to happen
to the display as a result.

[originally from svn r8867]
2010-02-16 15:13:28 +00:00
b39f9dfb99 Docs and comments fixes from James H.
[originally from svn r8866]
2010-02-16 10:48:25 +00:00