chiark / gitweb /
sgt-puzzles.git
4 years agoRemove winiss.pl.
Simon Tatham [Mon, 29 Mar 2021 17:48:07 +0000 (18:48 +0100)]
Remove winiss.pl.

I noticed this while I was overhauling the build system. We haven't
used an Inno Setup based installer for years, so the script that
constructed Inno Setup's input file is well and truly obsolete and
should have been deleted long since.

4 years agoMigrate to a CMake-based build system.
Simon Tatham [Mon, 29 Mar 2021 17:23:11 +0000 (18:23 +0100)]
Migrate to a CMake-based build system.

This completely removes the old system of mkfiles.pl + Recipe + .R
files that I used to manage the various per-platform makefiles and
other build scripts in this code base. In its place is a
CMakeLists.txt setup, which is still able to compile for Linux,
Windows, MacOS, NestedVM and Emscripten.

The main reason for doing this is because mkfiles.pl was a horrible
pile of unmaintainable cruft. It was hard to keep up to date (e.g.
didn't reliably support the latest Visual Studio project files); it
was so specific to me that nobody else could maintain it (or was even
interested in trying, and who can blame them?), and it wasn't even
easy to _use_ if you weren't me. And it didn't even produce very good
makefiles.

In fact I've been wanting to hurl mkfiles.pl in the bin for years, but
was blocked by CMake not quite being able to support my clang-cl based
system for cross-compiling for Windows on Linux. But CMake 3.20 was
released this month and fixes the last bug in that area (it had to do
with preprocessing of .rc files), so now I'm unblocked!

CMake is not perfect, but it's better at mkfiles.pl's job than
mkfiles.pl was, and it has the great advantage that lots of other
people already know about it.

Other advantages of the CMake system:

 - Easier to build with. At least for the big three platforms, it's
   possible to write down a list of build commands that's actually the
   same everywhere ("cmake ." followed by "cmake --build ."). There's
   endless scope for making your end-user cmake commands more fancy
   than that, for various advantages, but very few people _have_ to.

 - Less effort required to add a new puzzle. You just add a puzzle()
   statement to the top-level CMakeLists.txt, instead of needing to
   remember eight separate fiddly things to put in the .R file. (Look
   at the reduction in CHECKLST.txt!)

 - The 'unfinished' subdirectory is now _built_ unconditionally, even
   if the things in it don't go into the 'make install' target. So
   they won't bit-rot in future.

 - Unix build: unified the old icons makefile with the main build, so
   that each puzzle builds without an icon, runs to build its icon,
   then relinks with it.

 - Windows build: far easier to switch back and forth between debug
   and release than with the old makefiles.

 - MacOS build: CMake has its own .dmg generator, which is surely
   better thought out than my ten-line bodge.

 - net reduction in the number of lines of code in the code base. In
   fact, that's still true _even_ if you don't count the deletion of
   mkfiles.pl itself - that script didn't even have the virtue of
   allowing everything else to be done exceptionally concisely.

4 years agoFix bit rot in the 'unfinished' subdir.
Simon Tatham [Mon, 29 Mar 2021 17:13:38 +0000 (18:13 +0100)]
Fix bit rot in the 'unfinished' subdir.

Several of the source files here won't quite compile any more, because
of minor things like const-correctness and the UI_UPDATE change. Now
they should all build again (without prejudice to how useful they are
once they have built).

The biggest change was to remove the fatal() implementation from the
standalone path.c, because my new plan is that basically everything
that's not linked against a true puzzle frontend will be linked
against nullfe.c, which provides that function anyway.

4 years agoGalaxies: fix assertion failure when adding out-of-bounds association.
Franklin Wei [Sun, 5 Jul 2020 23:32:26 +0000 (19:32 -0400)]
Galaxies: fix assertion failure when adding out-of-bounds association.

Adding an association with an out-of-bounds square (i.e. by pressing Return
with a dot selected, and then moving the cursor so the `opposite' arrow was
off the screen) would cause space_opposite_dot() to return NULL, in turn
causing ok_to_add_assoc_with_opposite_internal() to return false, failing
the assertion.

This assertion appears to have been introduced in 68363231.

4 years agoAdd method for frontends to query the backend's cursor location.
Franklin Wei [Tue, 7 Jul 2020 02:06:30 +0000 (22:06 -0400)]
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.

4 years agoGroup: fix assertion failure in Unreasonable generation.
Simon Tatham [Tue, 9 Jun 2020 13:22:31 +0000 (14:22 +0100)]
Group: fix assertion failure in Unreasonable generation.

Generating the game id 6dui#12345 would cause an assertion failure in
a call to latin_solver_place that should never have happened in the
first place, because the "return -1" that ought to have prevented it
was accidentally inside #ifdef STANDALONE_SOLVER.

5 years agoUnequal: fill in the latin.c validator function.
Simon Tatham [Sat, 23 May 2020 09:25:38 +0000 (10:25 +0100)]
Unequal: fill in the latin.c validator function.

This too seems to have made no difference: each of the commands
    unequal --generate 1000 6dr#12345
    unequal --generate 1000 6adr#12345
delivers the same list of puzzles before and after the fix.

5 years agoTowers: fill in the latin.c validator function.
Simon Tatham [Sat, 23 May 2020 09:03:57 +0000 (10:03 +0100)]
Towers: fill in the latin.c validator function.

Again, this seems to have made no difference in a test generation run
with the command "towers --generate 100 6du#12345".

5 years agoKeen: fill in the latin.c validator function.
Simon Tatham [Sat, 23 May 2020 08:20:49 +0000 (09:20 +0100)]
Keen: fill in the latin.c validator function.

This seems to make no difference that I can detect: a test generation
run of the form 'keen --generate 1000 6du#12345' outputs an identical
list of 1000 puzzle ids before and after. So the missing validation in
this puzzle seems to have been benign.

5 years agoGroup: hard-mode identity deduction.
Simon Tatham [Fri, 22 May 2020 17:57:15 +0000 (18:57 +0100)]
Group: hard-mode identity deduction.

This fills in the deduction feature I mentioned in commit 7acc554805,
of determining the identity by elimination, having ruled out all other
candidates.

In fact, it goes further: as soon as we know that an element can't be
the group identity, we rule out every possible entry in its row and
column which would involve it acting as a left- or right-identity for
any individual element.

This noticeably increases the number of puzzles that can be solved at
Hard mode without resorting to Unreasonable-level recursion. In a test
of 100 Hard puzzles generated with this change, 80 of them are
reported as Unreasonable by the previous solver.

(One of those puzzles is 12i:m12b9a1zd9i6d10c3y2l11q4r , the example
case that exposed the latin.c validation bug described by the previous
two commits. That was reported as ambiguous with the validation bug,
as Unreasonable with the validation bug fixed, and now it's merely
Hard, because this identity-based deduction eliminates the need for
recursion.)

5 years agoGroup: fill in the latin.c validator function.
Simon Tatham [Sat, 23 May 2020 07:41:43 +0000 (08:41 +0100)]
Group: fill in the latin.c validator function.

This actually fixes the example game id mentioned in the previous
commit. Now 12i:m12b9a1zd9i6d10c3y2l11q4r is reported as Unreasonable
rather than ambiguous, on the basis that although the solver still
recurses and finds two filled grids, the validator throws out the
nonsense one at the last minute, leaving only one that's actually
legal.

5 years agolatin.c: call a user-provided validator function. [NFC]
Simon Tatham [Sat, 23 May 2020 07:34:58 +0000 (08:34 +0100)]
latin.c: call a user-provided validator function. [NFC]

I've only just realised that there's a false-positive bug in the
latin.c solver framework.

It's designed to solve puzzles in which the solution is a latin square
but with some additional constraints provided by the individual
puzzle, and so during solving, it runs a mixture of its own standard
deduction functions that apply to any latin-square puzzle and extra
functions provided by the client puzzle to do deductions based on the
extra clues or constraints.

But what happens if the _last_ move in the solving process is
performed by one of the latin.c built-in methods, and it causes a
violation of the client puzzle's extra constraints? Nothing will ever
notice, and so the solver will report that the puzzle has a solution
when it actually has none.

An example is the Group game id 12i:m12b9a1zd9i6d10c3y2l11q4r . This
was reported by 'groupsolver -g' as being ambiguous. But if you look
at the two 'solutions' reported in the verbose diagnostics, one of
them is arrant nonsense: it has no identity element at all, and
therefore, it fails associativity all over the place. Actually that
puzzle _does_ have a unique solution.

This bug has been around for ages, and nobody has reported a problem.
For recursive solving, that's not much of a surprise, because it would
cause a spurious accusation of ambiguity, so that at generation time
some valid puzzles would be wrongly discarded, and you'd never see
them. But at non-recursive levels, I can't see a reason why this bug
_couldn't_ have led one of the games to present an actually impossible
puzzle believing it to be soluble.

Possibly this never came up because the other clients of latin.c are
more forgiving of this error in some way. For example, they might all
be very likely to use their extra clues early in the solving process,
so that the requirements are already baked in by the time the final
grid square is filled. I don't know!

Anyway. The fix is to introduce last-minute client-side validation:
whenever the centralised latin_solver thinks it's come up with a
filled grid, it should present it to a puzzle-specific validator
function and check that it's _really_ a legal solution.

This commit does the plumbing for all of that: it introduces the new
validator function as one of the many parameters to latin_solver, and
arranges to call it in an appropriate way during the solving process.
But all the per-puzzle validation functions are empty, for the moment.

5 years agogroupsolver: show working when using -v on ambiguous puzzles.
Simon Tatham [Fri, 22 May 2020 18:00:01 +0000 (19:00 +0100)]
groupsolver: show working when using -v on ambiguous puzzles.

5 years agoGroup: fix loop bounds in the solver.
Simon Tatham [Tue, 19 May 2020 20:02:50 +0000 (21:02 +0100)]
Group: fix loop bounds in the solver.

Applications of the associativity rule were iterating over only n-1 of
the group elements, because I started the loops at 1 rather than 0. So
the solver was a bit underpowered, and would have had trouble with
some perfectly good unambiguous game ids such as 6i:2a5i4a6a1s .

(The latin.c system is very confusing for this, because for historical
reasons due to its ancestry in Solo, grid coordinates run from 0 to
n-1 inclusive, but grid _contents_ run from 1 to n, using 0 as the
'unknown' value. So there's a constant risk of getting confused as to
which kind of value you're dealing with.)

This solver weakness only affects puzzles in 'identity hidden' mode,
because in normal mode, the omitted row and column are those of the
group identity, and applications of associativity involving the
identity never generate anything interesting.

5 years agoGroup: add a special deduction about the group identity.
Simon Tatham [Tue, 19 May 2020 20:02:36 +0000 (21:02 +0100)]
Group: add a special deduction about the group identity.

In identity-hidden mode, as soon as you find any table entry that
matches the element indexing its row or column (i.e. a product of
group elements of the form ab=a or ab=b), then you immediately know
which element is the group identity, and you can fill in the rest of
its row and column trivially.

But the Group solver was not actually able to do this deduction.
Proof: it couldn't solve the game id 4i:1d1d1d1, which is trivial if
you take this into account. (a^2=a, so a is the identity, and once you
fill in ax=xa=x for all x, the rest of the grid is forced.)

So I've added dedicated piece of logic to spot the group identity as
soon as anything in its row and column is filled in. Now that puzzle
can be solved.

(A thing that I _haven't_ done here is the higher-level deduction of
determining the identity by elimination. Any table entry that
_doesn't_ match either its row or column rules out both the row and
the column from being the group identity - so as soon as you have
enough table entries to rule out all but one element, you know the
identity must be the remaining one. At the moment, this is just doing
the simple version of the deduction where a single table entry tells
you what _is_ the identity.)

One slightly tricky part is that because this new identity inference
deduction fills in multiple grid entries at a time, it has to be
careful to avoid triggering an assertion failure if the puzzle is
inconsistent - before filling in each entry, it has to make sure the
value it wants to fill in has not been ruled out by something it
filled in already. Without that care, an insoluble puzzle can cause
the solver to crash - and worse, the same can happen on an insoluble
_branch_ of the guesswork-and-backtracking tree in Unreasonable mode.
In both cases, the answer is to make sure you detect the problem
before hitting the assertion, and return -1 for 'inconsistent puzzle'
if you spot it. Then any guesswork branch that ends up in this
situation is cleanly abandoned, and we move on to another one.

5 years agounfinished/path: some jottings towards a solver.
Simon Tatham [Tue, 12 May 2020 21:05:52 +0000 (22:05 +0100)]
unfinished/path: some jottings towards a solver.

I still don't actually have a solver design, but a recent conversation
sent my brain in some more useful directions than I've come up with
before, so I might as well at least note it all down.

5 years agoProvide visual guide to the cursor location across the rows and columns.
Robert Konigsberg [Sun, 10 May 2020 18:30:43 +0000 (14:30 -0400)]
Provide visual guide to the cursor location across the rows and columns.

5 years agogrid.c: fix size miscalculation in Floret tiling.
Simon Tatham [Sun, 12 Apr 2020 13:37:47 +0000 (14:37 +0100)]
grid.c: fix size miscalculation in Floret tiling.

A Floret grid of height h usually alternates columns of h hexagonal
florets with columns of h-1. An exception is when h=1, in which case
alternating columns of 1 and 0 florets would leave the grid
disconnected. So in that situation all columns have 1 floret in them,
and the starting y-coordinate oscillates to make the grid tile
sensibly.

However, that special case wasn't taken account of when calculating
the grid height. As a result the anomalous extra florets in the
height-1 tiling fell off the bottom of the puzzle window.

5 years agoGTK 3: handle nontrivial window scale factors.
Simon Tatham [Tue, 7 Apr 2020 05:50:20 +0000 (06:50 +0100)]
GTK 3: handle nontrivial window scale factors.

A user pointed out that if you run a GTK 3 puzzles with "GDK_SCALE=2"
in the environment, the main game drawing area is blurred. That's
because we're choosing the size of our backing Cairo surface based on
the number of _logical_ pixels in the window size, not taking into
account the fact that the non-unit scale factor means the number of
physical pixels is larger. Everything 'works' in the basis - Cairo
happily expands the smaller backing surface into the larger window -
but resolution is lost in the process.

Now we detect the window's scale factor, construct the backing surface
appropriately, and compensate for that scaling when drawing to the
surface and when blitting the surface to the window.

5 years agoMines: add validation for negative mine count.
Simon Tatham [Tue, 17 Mar 2020 18:12:33 +0000 (18:12 +0000)]
Mines: add validation for negative mine count.

If this gets through validation, it causes an infinite loop after
gameplay begins.

5 years agoTracks: fix a small memory leak.
Simon Tatham [Wed, 26 Feb 2020 06:19:26 +0000 (06:19 +0000)]
Tracks: fix a small memory leak.

Spotted by Leak Sanitiser while I was testing the standalone solver.

5 years agoTracks: add reverse neighbour deduction in hard mode.
Simon Tatham [Wed, 26 Feb 2020 06:26:36 +0000 (06:26 +0000)]
Tracks: add reverse neighbour deduction in hard mode.

This is the contrapositive of the deduction introduced in the previous
commit. Previously I said: a square A can have some edges blocked in
such a way that you know it can't be filled without a particular one
of its neighbours B also being filled. And then, if you know the row
containing A and B only has one filled square left to find, then it
can't be A.

This commit adds the obvious followup: if you know the row only has
one _empty_ square left, then for the same reason, it can't be B!

I'm putting this in at the new Hard difficulty, mostly out of
guesswork rather than rigorous play-testing, because I don't remember
ever having _observed_ myself making this deduction in the past. I'm
open to changing the settings if someone has a good argument for it.

5 years agoTracks: new parity-based deduction.
Simon Tatham [Wed, 26 Feb 2020 06:18:51 +0000 (06:18 +0000)]
Tracks: new parity-based deduction.

This is another deduction I've known about in principle for ages but
the game didn't implement.

In the simplest case, it's obvious: if you can draw a line across the
grid that separates the track endpoints from each other, and the track
doesn't yet cross that line at all, then it's going to have to cross
it at _some_ point. So when you've narrowed down to only one possible
crossing place, you can fill it in as definite.

IF the track already crosses your line and goes back again, the same
rule still applies: _some_ part of your track is on one side of the
line, and needs to get to the other. A more sensible way of expressing
this is to say that the track must cross the boundary an _odd_ number
of times if the two endpoints are on opposite sides of it.

And conversely, if you've drawn a line across the grid that both
endpoints are on the _same_ side of, then the track must cross it an
_even_ number of times - every time it goes to the 'wrong' side (where
the endpoints aren't), it will have to come back again eventually.

But this doesn't just apply to a _line_ across the grid. You can pick
any subset you like of the squares of the grid, and imagine the closed
loop bounding that subset as your 'line'. (Or the _set_ of closed
loops, in the most general case, because your subset doesn't _have_ to
be simply connected - or even connected at all - to make this argument
valid.) If your boundary is a closed loop, then both endpoints are
always on the same side of that boundary - namely, the outside - and
so the track has to cross the boundary an even number of times. So any
time you can identify such a subset in which all but one boundary edge
is already filled in, you can fill in the last one by parity.

(This most general boundary-based system takes in all the previous
cases as special cases. In the original case where it looks as if you
need odd parity for a line across the grid separating the endpoints,
what you're really doing is drawing a closed loop around one half of
the grid, and considering the actual endpoint itself to be the place
where the track leaves that region again - so, looked at that way, the
parity is back to even.)

The tricky part of implementing this is to avoid having to iterate
over all subsets of the grid looking for one whose boundary has the
right property. Luckily, we don't have to: a nice way to look at it is
to define a graph whose vertices are grid squares, with neighbouring
squares joined by a _graph_ edge if the _grid_ edge between those
squares is not yet in a known state. Then we're looking for an edge of
that graph which if removed would break it up into more separate
components than it's already in. That is, we want a _bridge_ in the
graph - which we can find all of in linear time using Tarjan's
bridge-finding algorithm, conveniently implemented already in this
collection in findloop.c.

Having found a bridge edge of that graph, you imagine removing it, and
find one of the two connected components it's just broken its previous
component up into. That's your subset of grid squares, and now you can
count track crossings around the boundary and fill in the bridge edge
by parity.

When I actually came to implement this, it turned out that the very
first puzzle it generated was actually hard for me to solve, because
as it turns out, this general analysis is much better at identifying
opportunities to use this deduction than I am. A straight line right
across the grid is often obvious: a few squares tucked into a
complicated half-solved piece of the worldl, not so much. So I'm
introducing a new Hard difficulty level, and putting this solution
technique in there.

5 years agoTracks: new neighbour-based deduction.
Simon Tatham [Wed, 26 Feb 2020 06:07:18 +0000 (06:07 +0000)]
Tracks: new neighbour-based deduction.

This is a deduction I've been using in my own head for years: if you
only have one remaining filled square to put in a row, then it can't
be any square that has two adjacent edges blocked, because if that
square contains anything at all then it would have to be a corner
piece, and a corner piece forces the square next to it to be filled as
well.

I ran across a puzzle today that this implementation couldn't solve,
but I solved it fine by hand and found the deduction I was using that
wasn't implemented here. Now it is.

5 years agoTracks: add standalone solver program.
Simon Tatham [Wed, 26 Feb 2020 06:05:00 +0000 (06:05 +0000)]
Tracks: add standalone solver program.

Having one of these makes it much easier to debug what's going on when
the solver can't solve something. Also, now the solver can grade the
difficulty of a puzzle, it's useful to expose that feature in a
command-line tool.

5 years agoTracks: make solver return max difficulty used.
Simon Tatham [Wed, 26 Feb 2020 06:03:35 +0000 (06:03 +0000)]
Tracks: make solver return max difficulty used.

This should speed up game generation, because now we don't have to run
the solver _twice_ whenever we want to check that the grid has exactly
the intended difficulty. Instead, we can just run it once and check
the max_diff output.

5 years agoImprove const-correctness in printing API.
Asher Gordon [Sun, 29 Dec 2019 08:31:34 +0000 (03:31 -0500)]
Improve const-correctness in printing API.

Most of the functions in printing.c do not modify their 'document *'
argument, and therefore can declare them as 'const'.

5 years agoAdd printing support for GTK.
Asher Gordon [Tue, 24 Dec 2019 03:37:27 +0000 (22:37 -0500)]
Add printing support for GTK.

Printing is only available in GTK versions >= 2.10. We can only embed
the page setup dialog on GTK >= 2.18, so on a GTK version less than
that, we must use a separate page setup dialog.

In GTK, printing is usually done one page at a time, so also modify
printing.c to allow printing of a single page at a time.

Create a separate drawing API for drawing to the screen and for
printing. Create a vtable for functions which need to be different
depending on whether they were called from the printing or drawing
API.

When a function is called from the printing API, it is passed a
separate instance of the frontend than if it were called from the
drawing API. In that instance of the frontend, an appropriate vtable
is available depending on whether it was called from the printing or
drawing API.

The low-level functions used for printing are enabled even if printing
is not enabled. This is in case we ever need to use them for something
other than printing with GTK. For example, using Cairo as a printing
backend when printing from the command line. Enabling the low-level
functions even when GTK printing is not available also allows them to
be compiled under as many build settings as possible, and thus lowers
the chance of undetected breakage.

Move the definition of ROOT2 from ps.c to puzzles.h so other files can
use it (gtk.c needs it for hatching).

Also add myself to the copyright list.

[Committer's note: by 'printing', this log message refers to the GTK
GUI printing system, which handles selecting a printer, printing to a
file, previewing and so on. The existing facility to generate
printable puzzles in Postscript form by running the GTK binaries in
command-line mode with the --print option is unaffected. -SGT]

5 years agoUpdate the copyright holders list in puzzles.but.
Simon Tatham [Sat, 28 Dec 2019 09:07:17 +0000 (09:07 +0000)]
Update the copyright holders list in puzzles.but.

Asher Gordon points out that when Michael Quevillon was added to the
LICENCE file in commit 8af0c2961, he didn't also make it in to the
copy of the same list in puzzles.but.

5 years agoDon't segfault when no icons are available.
Asher Gordon [Tue, 24 Dec 2019 05:44:30 +0000 (00:44 -0500)]
Don't segfault when no icons are available.

When no icons are available, n_xpm_icons will be 0, and
menu_about_event() will try to access xpm_icons[n_xpm_icons-1]. Since
n_xpm_icons is 0, this becomes xpm_icons[-1] which is an invalid
value, causing a segfault.

Instead, check if n_xpm_icons is 0, and if so, don't pass any icon to
gtk_show_about_dialog().

5 years agoMake --screenshot work even in (Cairo) GTK2 builds.
Simon Tatham [Wed, 13 Nov 2019 19:23:07 +0000 (19:23 +0000)]
Make --screenshot work even in (Cairo) GTK2 builds.

I had occasion recently to want to take a puzzle screenshot on a
machine that didn't have the GTK3 libraries installed, but is advanced
enough to build the GTK2+Cairo version of the puzzles. That _ought_ to
be good enough to take screenshots using bare Cairo without GTK; I
think the only reason why I didn't bother to support it before is
because on GTK2, frontend_default_colours() queries the widget style
to choose a shade of grey. But we have a fixed fallback shade of grey
to use on GTK3, so it's easy to just use that same fallback in
headless GTK2.

5 years ago.gitignore: add more autotools detritus.
Simon Tatham [Wed, 13 Nov 2019 19:27:41 +0000 (19:27 +0000)]
.gitignore: add more autotools detritus.

One of these days I should sit down and work out exactly when a run of
autoconf generates an autom4te.cache directory, and why it can
suddenly turn up unexpectedly one day after years of never needing to
put it in .gitignore!

5 years agoFix build failure reported in gcc 9.
Simon Tatham [Sun, 1 Sep 2019 21:26:22 +0000 (22:26 +0100)]
Fix build failure reported in gcc 9.

Apparently gcc 9 is clever enough to say 'Hey, runtime field width in
an sprintf targeting a fixed-size buffer!', but not clever enough to
notice that the width was computed earlier as the max of lots of
default-width sprintfs into the same buffer (so _either_ it's safe, or
else - on a hypothetical platform with a 263-bit int - the damage was
already done).

Added a bounds check or two to keep it happy.

6 years agoFix build failure in C90 mode.
Simon Tatham [Sun, 14 Apr 2019 20:24:19 +0000 (21:24 +0100)]
Fix build failure in C90 mode.

Thanks to Anders Höglund for pointing it out.

6 years agoDominosa: move set analysis with doubles into Extreme.
Simon Tatham [Sat, 13 Apr 2019 14:57:28 +0000 (15:57 +0100)]
Dominosa: move set analysis with doubles into Extreme.

This change doesn't alter the overall power of the Dominosa solver; it
just moves the boundary between Hard and Extreme so that fewer puzzles
count as Hard, and more as Extreme. Specifically, either of the two
cases of set analysis potentially involving a double domino with both
squares in the set is now classed as Extreme.

The effects on difficulty are that Hard is now easier, and Extreme is
at least easier _on average_. But the main purpose is the effect on
generation time: before this change, Dominosa Extreme was the slowest
puzzle present to generate in the whole collection, by a factor of
more than three. I think the forcing-chain deductions just didn't make
very many additional grids soluble, so that the generator had to try a
lot of candidates before finding one that could be solved using
forcing chains but not with all the other techniques put together.

6 years agoDominosa: add area-parity deductions, at Basic level.
Simon Tatham [Sat, 13 Apr 2019 12:46:31 +0000 (13:46 +0100)]
Dominosa: add area-parity deductions, at Basic level.

This is a technique I've had on the todo list (and been using by hand)
for years: a domino can't be placed if it would divide the remaining
area of the grid into pieces containing an odd number of squares.

The findloop subsystem is already well set up for finding domino
placements that would divide the grid, and the new is_bridge query
function can now tell me the sizes of the area on each side of the
bridge, which makes it trivial to implement this deduction by simply
running findloop and iterating over the output array.

6 years agofindloop: alternative query function.
Simon Tatham [Sat, 13 Apr 2019 12:12:44 +0000 (13:12 +0100)]
findloop: alternative query function.

This one tells you if a graph edge _is_ a bridge (i.e. it has inverted
sense to the existing is_loop_edge query). But it also returns
auxiliary data, telling you: _if_ this edge were removed, and thereby
disconnected some connected component of the graph, what would be the
sizes of the two new components?

The data structure built up by the algorithm very nearly contained
enough information to answer that already: because we assign
sequential indices to all the vertices in a traversal of our spanning
forest, and any bridge must be an edge of that forest, it follows that
we already know the size of _one_ of the two new components, just by
looking up the (minindex,maxindex) values for the vertex at the child
end of the edge.

To determine the other subcomponent's size, we subtract that from the
size of the full component. That's not quite so easy because we don't
already store that - but it's trivial to annotate every vertex's data
with a pointer back to the topmost node of the spanning forest in its
component, and then we can look at the (minindex,maxindex) pair of
that. So now we know the size of the original component and the size
of one of the pieces it would be split into, so we can just subtract.

6 years agoDominosa: another forcing-chain based deduction.
Simon Tatham [Sat, 13 Apr 2019 10:26:54 +0000 (11:26 +0100)]
Dominosa: another forcing-chain based deduction.

We've already spotted when a domino occurs twice in the _same_ forcing
chain. But now we also spot when it occurs twice in the same _pair_ of
complementary forcing chains, one in each of the two options. Then it
must appear in one of those two places, and hence, can't appear
anywhere else.

6 years agoDominosa: another local deduction in Basic level.
Simon Tatham [Sat, 13 Apr 2019 10:03:36 +0000 (11:03 +0100)]
Dominosa: another local deduction in Basic level.

This is necessary to solve the following test puzzle that someone sent
me in 2006 and I just recovered from my email archive:

6:65111036543150325534405211110064266620632365204324442053

Without this new deduction, the previous solver can't solve that
puzzle even at full power, but the half-solved state it leaves the
grid in has an obvious move in the top right corner (placing the 6-2
domino vertically in that corner forces two 3-0s to its left). Now
that kind of move can be made too, and the solver can handle this
puzzle (grading it as Hard).

6 years agoJavascript frontend: make Shift- and Ctrl-click work.
Simon Tatham [Fri, 12 Apr 2019 22:38:42 +0000 (23:38 +0100)]
Javascript frontend: make Shift- and Ctrl-click work.

In other front ends, Shift-click is an alternative to the middle
button, and Ctrl-click the right button. Apparently I completely
forgot to implement this in the JS front end. Better late than never.

6 years agoDominosa: further forms of set analysis.
Simon Tatham [Thu, 11 Apr 2019 19:30:10 +0000 (20:30 +0100)]
Dominosa: further forms of set analysis.

I realised that even with the extra case for a double domino
potentially using two squares in a set, I'd missed two tricks.

Firstly, if the double domino is _required_ to use two of the squares,
you can rule out any placement in which it only uses one. But I was
only ruling out those in which it used _none_.

Secondly, if you have the same number of squares as dominoes, so that
the double domino _can_ but _need not_ use two of the squares, then I
previously thought there was no deduction you could make at all. But
there is! In that situation, the double does have to use _one_ of the
squares, or else there would be only the n-1 heterogeneous dominoes to
go round the n squares. So you can still rule out placements for the
double which fail to overlap any square in the set, even if you can't
(yet) do anything about the other dominoes involved.

6 years agoDominosa: be more careful about >= Hard layout.
Simon Tatham [Thu, 11 Apr 2019 18:39:03 +0000 (19:39 +0100)]
Dominosa: be more careful about >= Hard layout.

Now we don't just ensure that alloc_try_hard arranged a confounder for
every domino; we also make sure that the full Basic-mode solver can't
place even a single domino with certainty.

6 years agoDominosa: max-difficulty option in the solver.
Simon Tatham [Thu, 11 Apr 2019 18:33:24 +0000 (19:33 +0100)]
Dominosa: max-difficulty option in the solver.

Now, as well as grading a puzzle by the highest difficulty it needed
during its solution, I can check _how much_ of a given puzzle is
soluble if you remove the higher difficulty levels.

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.