chiark / gitweb /
sgt-puzzles.git
6 years agoDominosa: more sophisticated grid layout in >= Hard mode.
Simon Tatham [Wed, 10 Apr 2019 06:37:54 +0000 (07:37 +0100)]
Dominosa: more sophisticated grid layout in >= Hard mode.

The new Hard and Extreme difficulty levels allow you to make a start
on a grid even if there is no individual domino that can be easily
placed. So it's more elegant to _enforce_ that, in the same way that
Hard-mode Slant tries to avoid the initial toeholds that Easy mode
depends on.

Hence, I've refactored the domino layout code into several alternative
versions. The new one, enabled at Hard mode and above, arranges that
every domino has more than one possible position, so that you have to
use some kind of hard deduction to even get off the ground.

While I'm at it, the old layout system has had a makeover: in the
course of its refactoring, I've arranged to iterate over the domino
values _and_ locations in random order, instead of going over the
locations in grid order. The idea is that that might eliminate a
directional bias. But more importantly, it changes the previous
meaning of random number seeds.

6 years agoDominosa: add presets for Hard and Extreme difficulty.
Simon Tatham [Fri, 5 Apr 2019 18:41:38 +0000 (19:41 +0100)]
Dominosa: add presets for Hard and Extreme difficulty.

I decided not to go all the way up to order-9 Extreme, because that
takes a lot of CPU to generate. People can select it by hand if they
don't mind that.

6 years agoDominosa: prevent hangs generating tiny hard puzzles.
Simon Tatham [Fri, 5 Apr 2019 18:40:59 +0000 (19:40 +0100)]
Dominosa: prevent hangs generating tiny hard puzzles.

As with several other puzzles, the harder difficulty levels turn out
to be impossible to generate at very small sizes, which I fudge by
replacing them with the hardest level actually feasible.

6 years agoDominosa: add an Extreme difficulty, with forcing chains.
Simon Tatham [Fri, 5 Apr 2019 18:40:42 +0000 (19:40 +0100)]
Dominosa: add an Extreme difficulty, with forcing chains.

This technique borrows its name from the Solo / Map deduction in which
you find a path of vertices in your graph each of which has two
possible values, such that a choice for one end vertex of the chain
forces everything along it. In Dominosa, an approximate analogue is a
path of squares each of which has only two possible domino placements
remaining, and it has the extra-useful property that it's
bidirectional - once you've identified such a path, either all the odd
domino placements along it must be right, or all the even ones. So if
you can find an inconsistency in either set, you can rule out the
whole lot and settle on the other set.

Having done that basic analysis (which turns out to be surprisingly
easy with an edsf to help), there are multiple ways you can actually
rule out one of the same-parity chains. One is if the same domino
would have to appear twice in it; another is if the set of dominoes
that the chain would place would rule out all the choices for some
completely different square. There are probably others too, but those
are the ones I've implemented.

6 years agoFix a handful of memory leaks in the midend.
Simon Tatham [Fri, 5 Apr 2019 18:29:23 +0000 (19:29 +0100)]
Fix a handful of memory leaks in the midend.

I happened to notice these when running dominosa --generate under Leak
Sanitiser.

6 years agoNew utility routine: sort with a context parameter.
Simon Tatham [Fri, 5 Apr 2019 18:23:21 +0000 (19:23 +0100)]
New utility routine: sort with a context parameter.

I'm about to have a need to sort an array based on auxiliary data held
in a variable that's not globally accessible, so I need a sort routine
that accepts an extra parameter and passes it through to the compare
function.

Sorting algorithm is heapsort, because it's the N log N algorithm I
can implement most reliably.

6 years agoDominosa: update the to-do list.
Simon Tatham [Thu, 4 Apr 2019 22:51:35 +0000 (23:51 +0100)]
Dominosa: update the to-do list.

In particular, reorganise the priorities. I think forcing chains are
the most important thing that still wants adding; the parity search
would be easy enough but I don't know how often it would actually be
_useful_; the extended set analysis would be nice but I don't know how
to make it computationally feasible.

6 years agoDominosa: allow set analysis even with adjacency.
Simon Tatham [Wed, 3 Apr 2019 17:26:42 +0000 (18:26 +0100)]
Dominosa: allow set analysis even with adjacency.

I've always had the vague idea that the usual set analysis deduction
goes wrong when there are two adjacent squares, because they might be
opposite ends of the same domino and mess up the count. But I just
realised that actually you can correct for that by adjusting the
required count by one: if you have four 0 squares which between them
can only be parts of 0-0, 0-1 and 0-2, then the only way this can work
is if two of them are able to be the 0-0 - but in that case, you can
still eliminate those dominoes from all placements elsewhere. So set
analysis _can_ work in that situation; you just have to compensate for
the possible double.

(This enhanced form _might_ turn out to be something that needs
promoting into a separate difficulty level, but for the moment, I'll
try leaving it in Hard and seeing if that's OK.)

6 years agoDominosa: add a Hard difficulty which can do set analysis.
Simon Tatham [Wed, 3 Apr 2019 17:16:25 +0000 (18:16 +0100)]
Dominosa: add a Hard difficulty which can do set analysis.

This is another thing I've been doing with my own brain for ages as a
more interesting alternative to scouring the grid for the simpler
deduction that must be there somewhere - but now the solver can
understand it too, so it can generate puzzles that _need_ it (or at
least need something beyond the simpler strategies it understands).

6 years agoDominosa: new deduction deduce_local_duplicate().
Simon Tatham [Tue, 2 Apr 2019 20:32:29 +0000 (21:32 +0100)]
Dominosa: new deduction deduce_local_duplicate().

This is a reasonably simple local deduction I've been using myself for
ages, and feel comfortable adding to the existing Basic difficulty
level.

6 years agoDominosa: introduce a difficulty system.
Simon Tatham [Tue, 2 Apr 2019 20:01:36 +0000 (21:01 +0100)]
Dominosa: introduce a difficulty system.

Currently, there are just two difficulty levels. 'Basic' is the same
as the old solver; 'Trivial' is the subset that guarantees the puzzle
can be solved using only the two simplest deductions of all: 'this
domino can only go in one place' and 'only one domino orientation can
fit in this square'.

The solver has also acquired a -g option, to grade the difficulty of
an input puzzle using this system.

6 years agoDominosa: rewrite the solver.
Simon Tatham [Tue, 2 Apr 2019 20:08:43 +0000 (21:08 +0100)]
Dominosa: rewrite the solver.

The new solver should be equivalent to the previous solver's
intelligence level, but it's more usefully split up into basic
data-structure maintenance and separate deduction routines that you
can omit some of. So it's a better basis to build on when adding
further deductions or dividing the existing ones into tiers.

The new solver also produces much more legible diagnostics, when the
command-line solver is run in -v mode.

6 years agoDominosa: add a command-line solver.
Simon Tatham [Tue, 2 Apr 2019 17:42:01 +0000 (18:42 +0100)]
Dominosa: add a command-line solver.

I've made the existing optional solver diagnostics appear as the
verbose output of the solver program. They're not particularly legible
at the moment, but they're better than nothing.

6 years agoGalaxies: prevent creation of empty undo-chain items.
Simon Tatham [Mon, 18 Feb 2019 21:12:16 +0000 (21:12 +0000)]
Galaxies: prevent creation of empty undo-chain items.

If you drag an arrow on to a square which is already filled in as part
of a completed region, or whose counterpart is filled in, or whose
counterpart is actually a dot, then the game can't actually place a
double arrow. Previously, it didn't find that out until execute_move
time, at which point it was too late to prevent a no-op action from
being placed on the undo chain.

Now we do those checks in interpret_move, before generating the move
string that tries to place the double arrow in the first place. So
execute_move can now enforce by assertion that arrow-placement moves
it gets are valid.

6 years agoPegs: clear ui->cur_jumping on undo or redo.
Simon Tatham [Sun, 10 Feb 2019 14:05:30 +0000 (14:05 +0000)]
Pegs: clear ui->cur_jumping on undo or redo.

Fixes an assertion failure in which you move the keyboard cursor to a
peg, press Enter to indicate that you're about to jump it to
somewhere, and then instead execute an undo or redo action which
replaces the peg with a hole. Thanks to Vitaly Ostrosablin for the
report.

6 years agobenchmark.pl: replace use of Perl <> with <<>>.
Simon Tatham [Fri, 25 Jan 2019 20:27:49 +0000 (20:27 +0000)]
benchmark.pl: replace use of Perl <> with <<>>.

I've only just found out that it has the effect of treating the argv
words not as plain filenames, but as arguments to Perl default 'open',
i.e. if they end in | then the text before that is treated as a
command. That's not what was intended!

6 years agoReplace fe->preset_menu when we change midend.
Simon Tatham [Wed, 12 Dec 2018 22:18:00 +0000 (22:18 +0000)]
Replace fe->preset_menu when we change midend.

Thanks to Rocco Matano for reporting that in the -DCOMBINED version of
the Windows front end, switching games causes a crash because the
presets menu from the old midend is still left over in fe, and its
presence inhibits the setup code from making a new one. Now we throw
it out at the same time as we throw out the old midend itself.

Also, the condition 'if (!fe->preset_menu)' was misguided. I think the
point of that was to avoid pointlessly tearing down and rebuilding the
preset menu when we're _not_ changing game - but that's a cost too
small to worry about if it causes the slightest trouble. Now
fe->preset_menu should always be NULL at that point in the function,
so I've replaced the if with an assert.

6 years agoFix GTK 2 crash introduced by previous commit.
Simon Tatham [Sun, 25 Nov 2018 00:46:48 +0000 (00:46 +0000)]
Fix GTK 2 crash introduced by previous commit.

Moving the snaffle_colours() call earlier is fine in GTK 3, where the
potential call to frontend_default_colour doesn't depend on the window
already having been created. But it falls over in GTK 2 where it does.

Moved the non-headless-mode version of that call back to where it was
before the --screenshot change.

6 years agoDon't initialise GTK in --screenshot mode.
Simon Tatham [Fri, 23 Nov 2018 23:44:17 +0000 (23:44 +0000)]
Don't initialise GTK in --screenshot mode.

I had this idea today and immediately wondered why I'd never had it
before!

To generate the puzzle screenshots used on the website and as program
icons, we run the GTK front end with the --screenshot option, which
sets up GTK, insists on connecting to an X server (or other display),
draws the state of a puzzle on a Cairo surface, writes that surface
out to a .png file, and exits.

But there's no reason we actually need the GTK setup during that
process, especially because the surface we do the drawing on is our
_own_ surface, not even one provided to us by GTK. We could just set
up a Cairo surface by itself, draw on it, and save it to a file.
Calling gtk_init is not only pointless, but actively inconvenient,
because it means the build script depends on having an X server
available for the sole purpose of making gtk_init not complain.

So now I've simplified things, by adding a 'headless' flag in
new_window and the frontend structure, which suppresses all uses of
actual GTK, leaving only the Cairo surface setup and enough supporting
stuff (like colours) to generate the puzzle image. One awkward build
dependency removed.

This means that --screenshot no longer works in GTK 2, which I don't
care about, because it only needs to run on _one_ platform.

6 years agoAdd missing 'static' to game-internal declarations.
Simon Tatham [Tue, 13 Nov 2018 22:06:19 +0000 (22:06 +0000)]
Add missing 'static' to game-internal declarations.

Another thing I spotted while trawling the whole source base was that
a couple of games had omitted 'static' on a lot of their internal
functions. Checking with nm, there turned out to be quite a few more
than I'd spotted by eye, so this should fix them all.

Also added one missing 'const', on the lookup table nbits[] in Tracks.

6 years agoUnruly, Group: reference-count the 'immutable' array.
Simon Tatham [Tue, 13 Nov 2018 21:58:14 +0000 (21:58 +0000)]
Unruly, Group: reference-count the 'immutable' array.

I noticed this during the bool trawl: both of these games have an
array of flags indicating which grid squares are immutable starting
clues, and copy it in every call to dup_game, which is completely
unnecessary because it doesn't change during play. So now each one
lives in a reference-counted structure, as per my usual practice in
similar cases elsewhere.

6 years agoAdd missing binary 'matching' to .gitignore.
Simon Tatham [Tue, 13 Nov 2018 21:54:11 +0000 (21:54 +0000)]
Add missing binary 'matching' to .gitignore.

6 years agoAdd a missing const in unfinished/sokoban.c.
Simon Tatham [Tue, 13 Nov 2018 21:51:49 +0000 (21:51 +0000)]
Add a missing const in unfinished/sokoban.c.

I noticed this when I temporarily enabled compilation of all the
unfinished puzzles while doing the bool trawl.

6 years agoUse C99 bool within source modules.
Simon Tatham [Tue, 13 Nov 2018 21:45:44 +0000 (21:45 +0000)]
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.

6 years agoReplace TRUE/FALSE with C99 true/false throughout.
Simon Tatham [Tue, 13 Nov 2018 21:44:02 +0000 (21:44 +0000)]
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.

6 years agoAdopt C99 bool in the grid.c API.
Simon Tatham [Tue, 13 Nov 2018 21:43:11 +0000 (21:43 +0000)]
Adopt C99 bool in the grid.c API.

More or less trivially: the only affected declaration is the
has_incentre flag in struct grid_face.

6 years agoAdopt C99 bool in the shared Latin-square API.
Simon Tatham [Tue, 13 Nov 2018 21:42:28 +0000 (21:42 +0000)]
Adopt C99 bool in the shared Latin-square API.

latin_check now returns bool, and latin_solver_diff_set takes a bool
'extreme' flag. Should be non-disruptive.

6 years agoAdopt C99 bool in the tree234 API.
Simon Tatham [Tue, 13 Nov 2018 21:41:45 +0000 (21:41 +0000)]
Adopt C99 bool in the tree234 API.

The only affected function here is splitpos234, which I don't think
these puzzles are even using at the moment.

6 years agoAdopt C99 bool in misc.c functions.
Simon Tatham [Tue, 13 Nov 2018 21:40:49 +0000 (21:40 +0000)]
Adopt C99 bool in misc.c functions.

The 'decode' flag to obfuscate_bitmap and the 'wrap' flag to
move_cursor are the only ones affected here.

6 years agoAdopt C99 bool in the findloop API.
Simon Tatham [Tue, 13 Nov 2018 21:40:23 +0000 (21:40 +0000)]
Adopt C99 bool in the findloop API.

This shouldn't be a disruptive change at all: findloop_run and
findloop_is_loop_edge now return bool in place of int, but client code
should automatically adjust without needing any changes.

6 years agoAdopt C99 bool in the edsf API.
Simon Tatham [Tue, 13 Nov 2018 21:39:45 +0000 (21:39 +0000)]
Adopt C99 bool in the edsf API.

Now the flag passed to edsf_merge to say whether two items are the
same or opposite is a bool, and so is the flag returned via a pointer
argument from edsf_canonify.

The latter requires client code to be updated to match (otherwise
you'll get a pointer type error), so I've done that update in Loopy,
which is edsf's only current in-tree client.

6 years agoAdopt C99 bool in the printing API.
Simon Tatham [Tue, 13 Nov 2018 21:38:53 +0000 (21:38 +0000)]
Adopt C99 bool in the printing API.

Not many changes here: the 'dotted' flag passed to print_line_dotted
is bool, and so is the printing_in_colour flag passed to
print_get_colour. Also ps_init() takes a bool.

line_dotted is also a method in the drawing API structure, but it's
not actually filled in for any non-print-oriented implementation of
that API. So only front ends that do platform-specific _printing_
should need to make a corresponding change. In-tree, for example,
windows.c needed a fix because it prints via Windows GDI, but gtk.c
didn't have to do anything, because its CLI-based printing facility
just delegates to ps.c.

6 years agoAdopt C99 bool in the midend API.
Simon Tatham [Tue, 13 Nov 2018 21:37:09 +0000 (21:37 +0000)]
Adopt C99 bool in the midend API.

This changes parameters of midend_size and midend_print_puzzle, the
return types of midend_process_key, midend_wants_statusbar,
midend_can_format_as_text_now and midend_can_{undo,redo}, the 'bval'
field in struct config_item, and finally the return type of the
function pointer passed to midend_deserialise and identify_game.

The last of those changes requires a corresponding fix in clients of
midend_deserialise and identify_game, so in this commit I've also
updated all the in-tree front ends to match. I expect downstream front
ends will need to do the same when they merge this change.

6 years agoAdopt C99 bool in the game backend API.
Simon Tatham [Tue, 13 Nov 2018 21:34:42 +0000 (21:34 +0000)]
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.

6 years agoAdd a #include of <stdbool.h>.
Simon Tatham [Tue, 13 Nov 2018 21:31:32 +0000 (21:31 +0000)]
Add a #include of <stdbool.h>.

This is the first commit in a series which will adopt C99 bool
throughout the code base where it makes sense to do so.

6 years agoUndead: remove an unused structure field.
Simon Tatham [Wed, 7 Nov 2018 19:16:00 +0000 (19:16 +0000)]
Undead: remove an unused structure field.

I noticed that state->common, which is shared between all the game
states in an undo chain, has a 'solved' flag in it. That's not right -
solvedness as a property of a particular state on the chain belongs in
the game_state itself, and having-at-one-point-been-solved-ness as a
persistent property of the whole chain belongs in the game_ui.

Fortunately, the game isn't actually doing it wrong:
state->common->solved is set once and then never read, so it must have
been left in from early abandoned code. Now removed.

6 years agoFix an inaccurate comment.
Simon Tatham [Tue, 6 Nov 2018 18:34:47 +0000 (18:34 +0000)]
Fix an inaccurate comment.

latin_solver_diff_set takes a boolean input parameter to indicate
whether the 'Extreme'-level variant of set elimination is permitted.
But it's commented in the header file as having a boolean _output_
parameter which it sets if it _ended up_ using that variant. Probably
the latter was how it worked in an early draft, and I changed my mind
later without changing the comment.

6 years agoFix a misuse of errno.
Simon Tatham [Tue, 6 Nov 2018 18:33:21 +0000 (18:33 +0000)]
Fix a misuse of errno.

In menu_save_event, we checked ctx.error to see if an errno value had
been left in it by the savefile_write callback, but if so, then we
were passing the _current_ value of errno to strerror() in place of
the saved value in ctx.error.

This may well have been benign, but I spotted it in an eyeball review
just now and thought I'd better fix it before it bit anyone.

6 years agoFix OSX build failure from latest XCode update.
Simon Tatham [Sat, 6 Oct 2018 17:22:42 +0000 (18:22 +0100)]
Fix OSX build failure from latest XCode update.

To begin with, the toolchain no longer lets me build for x86-32 -
apparently MacOS is now 64-bit only.

Also, the linker now gives an error about a missing libgcc_s variant
for -mmacosx-version-min=10.4, and indeed 10.5. So I've bumped the
minimum supported OS version to 10.6.

That in turn required some changes in osx.m itself, because bumping
the min OS version caused some API deprecations to show up. Luckily I
turned out to have left myself a comment some time ago telling me what
I was going to need to do about one of them :-)

6 years agoNet: highlight more errors in locked tiles.
Jacob Nevins [Sun, 23 Sep 2018 15:36:30 +0000 (16:36 +0100)]
Net: highlight more errors in locked tiles.

If a locked tile has an edge pointing at a barrier, or at another
locked tile without a matching edge, colour that edge red.

6 years agoNet: rename 'loop' to 'err' in UI code.
Jacob Nevins [Sun, 23 Sep 2018 15:36:24 +0000 (16:36 +0100)]
Net: rename 'loop' to 'err' in UI code.

In preparation for highlighting other kinds of errors.
No intended functional change.

6 years agoDominosa: some more solver thoughts.
Simon Tatham [Fri, 21 Sep 2018 07:55:21 +0000 (08:55 +0100)]
Dominosa: some more solver thoughts.

I've been playing this game a fair bit recently, and it's probably
time I jotted down some of the deductions I've been doing in my own
brain that the game doesn't know about. (Also I had an algorithmic
thought about the area-parity technique.)

6 years agocube.c: Prohibit unsolvable single row/column game
Michael Quevillon [Thu, 13 Sep 2018 04:19:32 +0000 (00:19 -0400)]
cube.c: Prohibit unsolvable single row/column game

For cube games, the minimum for any dimension should be 2, as there is
no net of the cube that is only one row/column. The previous logic
would permit a 1x7 game (for example) that could never be solved.

6 years agoFix docs link from the JS Rectangles page.
Simon Tatham [Tue, 24 Jul 2018 17:38:00 +0000 (18:38 +0100)]
Fix docs link from the JS Rectangles page.

It pointed to rectangles.html, which doesn't exist, in place of
rect.html which does.

6 years agoTracks: stop drawing background for clues in game_print.
Simon Tatham [Fri, 20 Jul 2018 18:21:52 +0000 (19:21 +0100)]
Tracks: stop drawing background for clues in game_print.

This makes the clue numbers actually visible in the printed output,
instead of black on black.

6 years agoFix return value from newgame_undo_deserialise_read.
Simon Tatham [Thu, 21 Jun 2018 18:02:21 +0000 (19:02 +0100)]
Fix return value from newgame_undo_deserialise_read.

The read function used by midend_deserialise and friends is expected
never to perform a partial read (the main deserialisation code always
knows how many bytes it can expect to see), so it's specified to
return simply TRUE or FALSE for success/failure, rather than the
number of bytes read.

This probably wasn't breaking anything, since in the case of
deserialising from an internal memory buffer a short read could only
arise due to an outright bug constructing the buffer. But now I've
spotted it, I should fix it.

6 years agoFix NUL-termination bug in saving from Javascript.
Simon Tatham [Thu, 21 Jun 2018 17:54:08 +0000 (18:54 +0100)]
Fix NUL-termination bug in saving from Javascript.

The JS code that retrieves the save-file data from emcc.c doesn't
receive a separate length value, but instead expects the data to be in
the form of a NUL-terminated string. But emcc.c wasn't NUL-terminating
it, so the save data could come out with random cruft on the end.

6 years agomisc.c: Fix implementation of free_keys.
Lennard Sprong [Thu, 14 Jun 2018 19:45:26 +0000 (21:45 +0200)]
misc.c: Fix implementation of free_keys.

The previous version attempted to free the first element multiple times.

6 years agoParallelise the build script.
Simon Tatham [Fri, 1 Jun 2018 05:51:17 +0000 (06:51 +0100)]
Parallelise the build script.

Using the new feature I added to bob where it defines the variable
'nproc' to give you a sensible value to use with make -j.

6 years agoFix Makefile.nestedvm so that it works with make -j.
Simon Tatham [Fri, 1 Jun 2018 06:22:55 +0000 (07:22 +0100)]
Fix Makefile.nestedvm so that it works with make -j.

Instead of repeatedly reusing the file name 'PuzzleEngine.class' in
the main build directory, now each puzzle's NestedVM translation is
left in a separate subdirectory so that they don't collide with each
other. A bonus is that we don't have to rename the file back and forth
between the rule that builds it and the one that consumes it.

6 years agoEnable 64-bit osx build and fix a warning.
Josh Lee [Tue, 29 May 2018 12:09:01 +0000 (08:09 -0400)]
Enable 64-bit osx build and fix a warning.

OS X is beginning to show a warning when a 32-bit application is
opened, so it's high time that this gets enabled. Fix a clang warning
exposed by this build.

6 years agoEnable high resolution on osx
Josh Lee [Tue, 29 May 2018 12:08:21 +0000 (08:08 -0400)]
Enable high resolution on osx

This consists of setting a flag in the Info.plist. Everything in the
game is resolution-independent, of course, and has been thoroughly
tested on other platforms. The only issue I found is cosmetic: The
rounded window corners become more dramatic and don't look as good
against the square status bar.

Increasing the resolution also exposes two graphical quirks that I
don't think are new. Curved rails in Tracks seem to be made of short
segments that don't quite connect, but I don't see this on Android,
and on closer inspection this is already present on low resolution in
OS X. Lines in Untangle, and also Galaxies, that are at a multiple of
45 degrees seem thinner than other lines, but I also see this on
Android — I think it's just more obvious on high resolution, and could
be adjusted with antialiasing. Everything else looks as it should, for
example when moving a window between low and high dpi displays.

7 years agoBump the source and target versions used in javac.
Simon Tatham [Mon, 14 May 2018 17:18:28 +0000 (18:18 +0100)]
Bump the source and target versions used in javac.

I've just upgraded my build machine to Ubuntu 18.04, which has come
with a version of javac that complains about both -source 1.3 and
-target 1.3. Both are surely pretty out of date anyway, so the path of
least resistance is to just increase them to the earliest version that
javac doesn't currently complain is deprecated.

7 years agoStop using deprecated gdk_beep().
Simon Tatham [Wed, 9 May 2018 15:08:46 +0000 (16:08 +0100)]
Stop using deprecated gdk_beep().

Switched over to gdk_display_beep(), which should work in any GTK2 or
GTK3 environment. (This code base doesn't care about GTK1 any more.)

7 years agoBuildscr: make long parts of the build conditionalisable.
Simon Tatham [Sat, 28 Apr 2018 11:02:55 +0000 (12:02 +0100)]
Buildscr: make long parts of the build conditionalisable.

If I want to rebuild just the Javascript puzzles (for example) in
circumstances where I don't expect to need a great many
edit-compile-link cycles, it's easier to get bob to do it for me than
to remember how to set up the development tools on my path. But it
takes ages to run the whole build script if I also have to wait for
the Windows, Mac and Java puzzles to be built, not to mention the
initial Unix build that runs for no purpose other than generating the
icon images.

So now I can run the build with various time-consuming parts
conditioned out, for development purposes. Of course, the default is
still to build absolutely everything.

7 years agolatin.c: remove a rogue array overrun.
Simon Tatham [Sat, 28 Apr 2018 11:02:43 +0000 (12:02 +0100)]
latin.c: remove a rogue array overrun.

Oops! This was left over from an early development version of commits
4408476b7 and 000ebc507, in which I initially arranged for each
adjacency list to be terminated with the sentinel value -1 instead of
separately storing an array of the lists' lengths.

I later changed the representation to make randomising the algorithm
easier (it's much easier to shuffle an array uniformly at random if
you _don't_ have to faff endlessly to work out its length). But this
write of a no-longer- needed sentinel value in the client code must
have survived the rewrite by mistake, and also somehow evaded all my
pre-commit testing with valgrind and asan.

A user reported that the Towers Javascript version was crashing on
startup, and I think this is the cause, because it seems to fix it for
me.

7 years agoC89 build fixes.
Simon Tatham [Wed, 25 Apr 2018 18:24:06 +0000 (19:24 +0100)]
C89 build fixes.

Recent changes introduced a couple of non-C89-compatible mixed
declarations and code.

7 years agoMake static keyword come first everywhere.
Franklin Wei [Tue, 24 Apr 2018 22:00:08 +0000 (18:00 -0400)]
Make static keyword come first everywhere.

I somehow missed these instances as well. Oh well.

7 years agoMove `static' keyword to beginning of declaration.
Franklin Wei [Mon, 23 Apr 2018 23:54:43 +0000 (19:54 -0400)]
Move `static' keyword to beginning of declaration.

Rockbox's GCC warns about this with -Wextra.

7 years agoAdd request_keys() to the rest of the unfinished games.
Franklin Wei [Mon, 23 Apr 2018 23:43:14 +0000 (19:43 -0400)]
Add request_keys() to the rest of the unfinished games.

I just realized that only "Group" received the request_keys() field in the
game struct for some reason.

7 years agoBuild fix: stop initialising an auto char array.
Simon Tatham [Mon, 23 Apr 2018 17:42:13 +0000 (18:42 +0100)]
Build fix: stop initialising an auto char array.

Checking with the standards, I think this is legal C99, but not legal
C89 - and we are compiling in C89 mode. Why _every_ version of gcc
didn't object, given all the warning and pedantry options, I'm not
sure, but one did, so I should fix it.

7 years agoAdd a request_keys() function with a midend wrapper.
Franklin Wei [Tue, 17 Apr 2018 20:18:16 +0000 (16:18 -0400)]
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.

7 years agoRemove maxflow completely.
Simon Tatham [Sat, 21 Apr 2018 16:03:10 +0000 (17:03 +0100)]
Remove maxflow completely.

Its ability to solve general network flow problems was never actually
used in this code base; it was _always_ used for the restricted
problem of finding a matching in an unweighted bipartite graph. So now
I've switched all its clients over to the new matching.c, maxflow is
no longer needed.

7 years agoConvert Tents to use matching instead of maxflow.
Simon Tatham [Sat, 21 Apr 2018 15:51:03 +0000 (16:51 +0100)]
Convert Tents to use matching instead of maxflow.

Tents needs to construct maximal matchings in two different
situations. One is the completion check during play, in which the
existence of a perfect matching between tents and trees is part of the
win condition; the other is the initial grid generation, in which we
find a _maximal_ matching between the tents we've already placed and
all the possible neighbouring squares that are candidates for the tree
positions. Both of those are switched over.

7 years agoUse the new matching() for latin.c.
Simon Tatham [Sun, 22 Apr 2018 12:48:07 +0000 (13:48 +0100)]
Use the new matching() for latin.c.

The new client code is a lot smaller and nicer, because we can throw
away the col[] and num[] permutations entirely.

Of course, this also means that every puzzle that incorporated latin.c
now has to link against matching.c instead of maxflow.c - but since I
centralised that secondary dependency into Recipe a few commits ago,
it's trivial to switch them all over at once.

7 years agoImplementation of the Hopcroft-Karp algorithm.
Simon Tatham [Wed, 18 Apr 2018 19:28:17 +0000 (20:28 +0100)]
Implementation of the Hopcroft-Karp algorithm.

This is a dedicated algorithm for finding a maximal matching in a
bipartite graph.

Previously I've been solving that problem in this code base using
maxflow.c, modelling the graph matching problem as a restricted case
of the optimal network flow problem and then using a full-strength
algorithm for the latter. That's overkill, and also algorithmically
wasteful - the H-K algorithm is asymptotically better, because it can
find multiple augmenting paths in each pass (hence getting the maximum
benefit out of each expensive breadth-first search), as a consequence
of not having to worry about lower- or higher-value augmenting paths
in this restricted problem.

So I expect this algorithm to be faster, at least in principle or in
large cases, when it takes over the jobs currently being done by
maxflow. But that's not the only benefit. Another is that the data
representation is better suited to the problems actually being solved,
which should simplify all the call sites; a third is that I've
incorporated randomisation of the generated matching into the H-K
module itself, which will further save effort at each call site
because they will no longer have to worry about permuting the
algorithm's input - they just have to pass it a random_state and it
will take care of that internally.

This commit only introduces the new matching.c and builds a test
utility for it. I haven't yet migrated any clients of maxflow.

7 years agoRecipe: centralise dependencies for latin.c.
Simon Tatham [Sun, 22 Apr 2018 15:45:34 +0000 (16:45 +0100)]
Recipe: centralise dependencies for latin.c.

It's silly to have every puzzle using latin.c separately specify in
its .R file the list of additional modules that latin.c depends on, or
for that matter to have them all have to separately know how to adjust
that for the STANDALONE_SOLVER mode of latin.c.

So I've centralised a new pair of definitions into the core Recipe
file, called LATIN and LATIN_SOLVER, and now a client of latin.c need
only ask for that to get all the necessary dependencies too.

Also, while I'm here, I've moved the non-puzzle-specific 'latincheck'
test program out of unequal.R into the central Recipe.

7 years agoMove fgetline out into misc.c.
Simon Tatham [Sun, 22 Apr 2018 12:58:27 +0000 (13:58 +0100)]
Move fgetline out into misc.c.

I'm about to want to use it outside the GTK front end.

7 years agoGalaxies: clarify wording of completion condition.
Simon Tatham [Tue, 17 Apr 2018 17:30:48 +0000 (18:30 +0100)]
Galaxies: clarify wording of completion condition.

A user mailed me today having found it less than clear from the docs
that Galaxies will only accept a solution if the set of filled-in grid
edges consists of _exactly_ the ones that separate two distinct
regions, rather than consisting of _at least_ those and perhaps others
which neither break rotational symmetry or disconnect any region.

7 years agoFix two bugs in Range's solver_reasoning_recursion().
Stephen Clavering [Thu, 12 Apr 2018 20:15:17 +0000 (21:15 +0100)]
Fix two bugs in Range's solver_reasoning_recursion().

Firstly, it tries to use newstate after freeing it.  I haven't come up
with any way of actually triggering that bug.  I suppose you'd need a
grid that required recursion to solve, which the generator of course
does not normally create.

Secondly, it stores M_BLACK or M_WHITE in the grid before doing the
recursion, whereas it should store BLACK or WHITE.  I believe that since
it tries M_BLACK first, which is zero, and since it's trying it on an
undecided square (also zero), this leads to infinite recursion, and an
eventual crash once you run out of stack space.

You can (sometimes) trigger this by asking for a hint on a grid where
you've already made a mistake.

e.g. on the puzzle desc below there's a "9" at (13,7).  If you place a
black tile to its immediate left and right - (12,7) and (14,7) - then
press 'h', you get a beachball and then crash (on macOS at least - I
presume other OSes are similar).

15x15:i5g4d16a7a7c3b3b11f11_15d3p8b7_8b4h18c4d13b4i7a16k9a9i4b2d10c14h11b10_10b17p6d8_7f9b8b11c10a2a5d5g7i

7 years agoSolo: add a missing params constraint for X puzzles.
Simon Tatham [Sun, 8 Apr 2018 16:55:59 +0000 (17:55 +0100)]
Solo: add a missing params constraint for X puzzles.

Michael Quevillon points out that neither 2x1 nor 3x1 Solo can be made
into an X Sudoku puzzle, on the grounds that whatever number goes in
one corner of the grid is ruled out from both ends (and the centre, if
any) of the opposing diagonal, and hence the X constraint can't be
satisfied.

(Also fixed a spurious full stop on a neighbouring line.)

7 years agoFix false-positive completion detection in X Solo.
Simon Tatham [Sun, 25 Mar 2018 21:27:38 +0000 (22:27 +0100)]
Fix false-positive completion detection in X Solo.

Spotted by Michael Quevillon. After checking the set of digits
appearing in one of the two main grid diagonals, we weren't clearing
the used[] array before using it to check the same thing about the
other diagonal. So if the first diagonal we check has one of
everything, then the second will be misidentified as correct (for the
purposes of game-completion detection, although not error
highlighting) even if it doesn't have one of everything.

7 years agotowerssolver: always print solver diagnostics in -v mode.
Simon Tatham [Mon, 26 Feb 2018 20:49:57 +0000 (20:49 +0000)]
towerssolver: always print solver diagnostics in -v mode.

The branch of the code that claimed the puzzle to be ambiguous was not
also re-running the solver with diagnostics enabled, so that if a user
tries to use this tool to hand-design a puzzle, they do not get
feedback on what the multiple legal solutions actually are.

7 years agolatin.c: dump every solution found during recursion.
Simon Tatham [Mon, 26 Feb 2018 20:49:14 +0000 (20:49 +0000)]
latin.c: dump every solution found during recursion.

In solver_show_working mode, we were logging all the deductions,
guesswork and backtracking, but not printing out the actual solution
(if any) reached at the end of each branch of the tree.

7 years agoCreate 96x96 icons for gnome-shell
Adrian Heine [Sat, 20 Jan 2018 12:05:18 +0000 (13:05 +0100)]
Create 96x96 icons for gnome-shell

7 years agoForbid undo-of-new-game after midend_set_config.
Simon Tatham [Sat, 9 Dec 2017 21:28:41 +0000 (21:28 +0000)]
Forbid undo-of-new-game after midend_set_config.

This is another situation in which the midend's state, at the time
midend_new_game tries to save it, is not such as to generate a viable
serialisation. In this case, it's because after the user enters a game
id into the Game > Specific or Game > Random Seed dialog box,
midend_set_config will have _already_ started overwriting important
fields of the midend such as me->desc and me->seed, before
midend_new_game is even entered.

In fact this caused an assertion failure (thanks to Lennard Sprong for
reporting it), because one of those fields was set to NULL, so the
resulting serialisation buffer was incomplete, leading to a
deserialisation error later. But I was lucky: if I hadn't been, the
serialisation might have been complete, and valid according to the
deserialisation code, but would have contained a mixture of the new
game's description and the old one's move chain, which would surely
have had far stranger results.

For the moment, I'm fixing this by simply not storing a serialisation
in that situation. Perhaps a nicer approach might be to store one
before starting to overwrite midend fields, and then have
midend_new_game swap it in if it's already been generated. That way
you _could_ still undo past an action like this. But preventing the
assertion failure is a good start.

7 years agoMark the 32-bit Windows build as runnable on XP.
Simon Tatham [Wed, 29 Nov 2017 22:27:09 +0000 (22:27 +0000)]
Mark the 32-bit Windows build as runnable on XP.

By the same method I do it in PuTTY: manually set the Windows
subsystem version id to an earlier one than the default.

7 years agoReinstate 32-bit Windows builds of Puzzles.
Simon Tatham [Sun, 26 Nov 2017 20:12:15 +0000 (20:12 +0000)]
Reinstate 32-bit Windows builds of Puzzles.

I've built a set of 32-bit binaries, a 32-bit zip file and a 32-bit
MSI, all delivered into a 'w32' output directory.

7 years agoPermit redoing past an undone New Game action.
Simon Tatham [Sat, 18 Nov 2017 19:54:10 +0000 (19:54 +0000)]
Permit redoing past an undone New Game action.

Now, when we undo a New Game by deserialising the stored version of
the previous game, we start by serialising the _current_ game into a
second serialisation buffer in the midend. Then, if the user tries to
redo back past that undo action, we can re-serialise the earlier game
and re-deserialise the newer one.

A few users had complained (with various degrees of politeness) at the
lack of this ability, because in true xkcd #1172 style, it broke their
workflow. Specifically, if you were a fan of holding down 'u' to undo
all the way back to the start of your current game, you'd have
overshot into the previous game and then have no way to return to the
game you wanted to be at the start of.

This slightly changes the previous interaction of Redo with New Game.
Previously, New Game would save the entire undo chain of the
serialised game, including anything forward of the current position;
so if you took actions move1,move2,undo,newgame then the serialised
game state would include both move1 and move2 with the current
position between them; hence, an undo would restore the old game to a
position just after move1, and then a redo action would re-enact
move2. Now, midend_purge_states is called before serialising the old
game, so in that scenario move2 would be completely lost as a side
effect of the new-game action. (Just as it would be if you made any
_other_ undoable move in that situation.)

Conversely, making a move in the old game after you've undone back
into it will now wipe out the record of the later game, so you can't
redo into it any more.

7 years agoRefactor to make me->newgame_undo a small struct.
Simon Tatham [Sat, 18 Nov 2017 19:36:10 +0000 (19:36 +0000)]
Refactor to make me->newgame_undo a small struct.

The three related buf/len/size fields are now a sub-structure of the
main midend, and the serialise/deserialise functions that address
those fields now take a pointer to that sub-structure rather than to
the midend as a whole. This will make it easy for me to drop in a
second substructure alongside it, for redo, and reuse those read and
write functions by just changing the context pointer.

7 years agoStandardise character encoding of source tree on UTF-8.
Simon Tatham [Sat, 18 Nov 2017 15:22:49 +0000 (15:22 +0000)]
Standardise character encoding of source tree on UTF-8.

Editing LICENCE just now, I happened to notice that the accented
letter in Jonas Kölker's name was encoded in ISO 8859-1, as is the
occurrence of the same name in filling.c - but _not_ the one in
guess.c, which was in UTF-8 already. That seems needlessly confusing,
so let's sort it out. Now every text file in this git repository is
suitable for interpreting as UTF-8.

7 years agoNew grid type: the trihexagonal tiling, or 'kagome lattice'.
Simon Tatham [Sat, 18 Nov 2017 15:16:40 +0000 (15:16 +0000)]
New grid type: the trihexagonal tiling, or 'kagome lattice'.

Regular hexagons and equilateral triangles in strict alternation, with
two of each interleaved around each vertex.
https://en.wikipedia.org/wiki/Trihexagonal_tiling

Thanks to Michael Quevillon for the patch.

7 years agoSolo: remove some overzealous assertions in the solver.
Simon Tatham [Sat, 28 Oct 2017 10:36:47 +0000 (11:36 +0100)]
Solo: remove some overzealous assertions in the solver.

There were a couple of places where we enforced by assertion that our
solver state had not become inconsistent, on the assumption that some
previous piece of solver would have detected that the puzzle was
impossible before getting to that place in the code.

But in fact the combination of Killer and Unreasonable modes falsified
at least two of those assumptions: 'solo --test-solve --generate 100
3x3kdu#12345' triggered an assertion failure in solver_set, and with
that one fixed, the same command triggered a second failure in
solver_killer_sums.

In both cases, the fix is simply to return -1 for 'puzzle is
inconsistent', which will cause the Unreasonable recursive solver to
abandon that branch of its search tree, backtrack, and try a different
guess at some previous square.

Thanks to Anders Höglund for the report.

7 years agoMap: stop storing pixel coordinates in game_ui.
Simon Tatham [Sat, 28 Oct 2017 07:55:33 +0000 (08:55 +0100)]
Map: stop storing pixel coordinates in game_ui.

The fields (ui->dragx,ui->dragy) stored the pixel coordinates of the
visible cursor (if any), no matter whether that cursor was being
displayed in response to a mouse dragging action or arrow-key
activity. But this meant that resizing the window while the keyboard
cursor was visible would cause the cursor to be drawn in totally the
wrong place in the newly resized window: you get a new drawstate with
a fresh blitter (so at least no part of the old-size window is
accidentally 'restored' on to the new-size one), but the ui fields
saying where _next_ to draw the cursor would still have bogus values
left over from the previous window size.

To fix this, I've arranged that we simply don't use ui->dragx and
ui->dragy any more in keyboard cursor mode: instead, we leave it to
game_redraw to spot that the keyboard cursor is visible and compute
its pixel coordinates for display.

A knock-on effect is that when we need to know which region is under
the cursor during interpret_move, we can't use the previous strategy
of just calling region_from_coords(ui->dragx, ui->dragy) regardless of
which kind of cursor is active. So I've split that function up into an
inner section taking a tile and a displacement from the tile's centre
and an outer part which derives those from real pixel coordinates in
the case where the cursor is originating from a mouse drag; then
there's a new alternative outer part which derives the same (tile,
displacement) pair purely from the game_ui keyboard cursor data
without having to explicitly translate into pixels and back in the
middle. Probably a less fragile strategy anyway.

7 years agoBuild fixes for GTK2.
Simon Tatham [Tue, 24 Oct 2017 18:39:11 +0000 (19:39 +0100)]
Build fixes for GTK2.

I had left one mention of the new GTK3-only variable
'awaiting_resize_ack' unprotected by #ifdefs. Also, the GTK2 version
of message_box() was missing some consts in its prototype, presumably
because when I had that #ifdeffed out the compiler didn't warn me
about those ones.

7 years agoUnequal: run check_complete() after a hint move.
Simon Tatham [Thu, 19 Oct 2017 23:33:54 +0000 (00:33 +0100)]
Unequal: run check_complete() after a hint move.

A user sent in the game id
  7:0,0L,0,0,0L,0L,1,0U,0U,0D,0UD,0,0,7,0,0D,0,0D,0,0,0,0,0,0,0,0,0,0D,0,0,3,0,0U,0,0,0,0,2,6,0,0U,0,0,0,7,2,0,0U,5L,
starting from which, one press of 'h' will fill in a 2 in the top left
corner and possibilities 345 to its right; if you then fill in 5 there
and press 'h' again, the hint system fills in the whole of an apparent
solution which isn't the one a proper use of the Solve feature would
give you - except that it's not actually a second solution, because
one < clue on the top row is violated. Without this fix, that < failed
to light up red, making the puzzle look ambiguous if you're not paying
enough attention to spot it.

7 years agofix loop condition
Stefan Bühler [Sat, 7 Oct 2017 21:21:45 +0000 (23:21 +0200)]
fix loop condition

prev[sink] == 0 means there was a path found with the last step being a
forward edge to the sink, and the edge being at index 0 in the array.

This is a valid path (the same as any other path indicated by prev[sink]
> 0).

7 years agoFix assertion failure if you Undo right at startup.
Simon Tatham [Fri, 6 Oct 2017 18:49:05 +0000 (19:49 +0100)]
Fix assertion failure if you Undo right at startup.

The initial call to midend_new_game() was creating a partial
serialisation containing no game states at all, which meant that if
your first UI action was an undo operation, the game would try to
deserialise that and complain that it was incomplete. Now we detect
that in advance and don't create a useless serialisation in the first
place.

7 years agoMake the code base clean under -Wwrite-strings.
Simon Tatham [Sun, 1 Oct 2017 13:45:12 +0000 (14:45 +0100)]
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.

7 years agoAssorted char * -> const char * API changes.
Simon Tatham [Sun, 1 Oct 2017 13:04:47 +0000 (14:04 +0100)]
Assorted char * -> const char * API changes.

I went through all the char * parameters and return values I could see
in puzzles.h by eye and spotted ones that surely ought to have been
const all along.

7 years agoReturn error messages as 'const char *', not 'char *'.
Simon Tatham [Sun, 1 Oct 2017 12:53:24 +0000 (13:53 +0100)]
Return error messages as 'const char *', not 'char *'.

They're never dynamically allocated, and are almost always string
literals, so const is more appropriate.

7 years agoUse a proper union in struct config_item.
Simon Tatham [Sun, 1 Oct 2017 12:38:35 +0000 (13:38 +0100)]
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.

7 years agoNew name UI_UPDATE for interpret_move's return "".
Simon Tatham [Sun, 1 Oct 2017 11:52:12 +0000 (12:52 +0100)]
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.

7 years agoFix an int->pointer cast warning in windows.c.
Simon Tatham [Sun, 1 Oct 2017 13:50:58 +0000 (14:50 +0100)]
Fix an int->pointer cast warning in windows.c.

If I increase clang-cl's warning pickiness, it starts objecting to my
cast to HMENU from a (potentially, in 64 bits) smaller integer type.

Actually I don't think there's a problem there - all the integer ids I
cast to HMENU are nice small numbers and a widening cast is just fine.
But I can suppress the warning by using INT_PTR instead of int in the
prototype for mkctrl, so it's easiest just to do that.

7 years agoMake newgame_undo_buf 'char *', not 'void *'.
Simon Tatham [Sun, 1 Oct 2017 12:52:16 +0000 (13:52 +0100)]
Make newgame_undo_buf 'char *', not 'void *'.

This fixes a compile error under -pedantic at the point where we do
pointer arithmetic on it.

7 years agoForbid undo of new-game if it would change the params.
Simon Tatham [Sun, 1 Oct 2017 09:22:35 +0000 (10:22 +0100)]
Forbid undo of new-game if it would change the params.

The newgame_undo data was being saved on every call to
midend_new_game, including the one just after midend_set_params when a
new puzzle preset was selected. So you could select a new preset from
the menu, and then press 'u', and the midend would _try_ to undo that
operation and restore the previous game with a different set of
parameters.

This would do the wrong thing in the front end, because front ends in
general will not be expecting that a change of game parameters might
result from an arbitrary keyboard event - they won't be expecting to
have to call the function that moves the highlight in the game-type
menu, for example, and they _certainly_ won't be expecting that a
window resize might be necessary in response to a random keystroke.

One possible response would be to fix all the front ends so that they
_are_ prepared for either of those consequences of a keystroke event,
and then it would be possible to undo not only the New Game menu
option and the 'n' key but also undo any selection of a preset from
the game-type menu, or even a full re-customisation of the game
settings. But that would be quite an upheaval even in _my_ front end
collection, and also probably be awkward for downstream front ends, so
until I'm convinced of the value of going to all the effort, the
simpler approach is just to disallow undoing a new game in those
situations.

(This does mean that re-selecting the _already active_ game preset
from the type menu will be treated as an undoable new-game event,
which I think is an acceptable UI oddity.)

7 years agoStyle tweaks to the newgame_undo patch.
Simon Tatham [Sun, 1 Oct 2017 08:15:24 +0000 (09:15 +0100)]
Style tweaks to the newgame_undo patch.

I've renamed the new midend variables to match my usual naming
convention of using 'size' for the total buffer size and 'len' for the
amount of currently used space (and a couple of other variables to
match those in turn), partly for consistency and also because the name
'midend_undo_used' made me half-expect it to be a boolean. The buffer
itself is called 'midend_undo_buf', again to avoid making it sound
like a function or flag.

Buffer growth is still geometric but less aggressive (factor of 5/4
each time instead of 2), in the hope of wasting less memory on low-RAM
platforms; newgame_undo_deserialise_read should have been static, and
now is; newgame_undo_buf is initialised using NULL rather than 0 so it
doesn't look like an integer, and is freed with the rest of the
midend.

And I think we _should_ enforce by assertion that midend_deserialise
didn't return an error, because there's no reason it ever should in
this situation (unlike when reading from a file, where the user might
have provided the wrong file or a corrupted one). This immediately
allowed me to spot a bug in the existing deserialisation code :-)

7 years agomidend: Allow "new game" to be undone
Ian Jackson [Sat, 30 Sep 2017 18:50:49 +0000 (19:50 +0100)]
midend: Allow "new game" to be undone

It is annoying when one intends to choose "restart" and chooses "new
game" instead.  Right now, the puzzle one wanted to try again is
discarded.

To fix this we are going to have to save a lot more information than a
normal game state.  Handily, we already have the serialise/deserialise
machinery.

The advantage of using this is that the previous game is easily saved
in its entirety, including its own undo history, and also probably in
a more compact format.

The (de)serialisation interface is rather clunky for use with a memory
target.  Sadly none of the existing implementations of a resizing
memory array have been conveniently brought out into puzzles.h, and I
think that that's beyond the scope of what I wanted to do here.

We don't serialise the new game undo serialisation data.  So
loading/saving doesn't preserve any "new game" undo, as does "new
game" twice (and as does context switching on a Palm Pilot).

Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
7 years agomidend_deserialise: accept an extra validation function.
Simon Tatham [Sun, 1 Oct 2017 08:59:50 +0000 (09:59 +0100)]
midend_deserialise: accept an extra validation function.

This will let me do a 'conditional deserialisation' operation, in
which we fully decode the serialised data and then (assuming that gave
no errors) decide whether or not to actually install it based on some
arbitrary condition.

I don't think there's any possible use for the extra check function
_outside_ midend.c, so I've left the API for front ends as it is; the
externally visible midend_deserialise() doesn't have the new
parameter, and only midend_deserialise_internal() includes it.

7 years agomidend_deserialise: keep deserialised data in a struct.
Simon Tatham [Sun, 1 Oct 2017 08:50:22 +0000 (09:50 +0100)]
midend_deserialise: keep deserialised data in a struct.

Lots of the local variables in midend_deserialise are now fields of a
structure which contains everything that is _going_ to be written into
the midend once we finish validating it all. This makes it easy to
keep all that data together, and (in future) pass it to other
functions all in one go.

No functional change.