1531 Commits

Author SHA1 Message Date
091bef1a82 Mosaic: implement game_status. 2021-04-26 18:05:09 +01:00
f2f39af2d3 Mosaic: use signed char for clue values.
Negative numbers are used as a sentinel for an absent clue, so we have
to use a type that's guaranteed to have some negative numbers. char is
unsigned on some platforms. So now Mosaic runs apparently correctly on
Raspbian, for example.
2021-04-26 18:05:00 +01:00
2409a9913e Update copyright years.
They'd got quite out of date, oops.
2021-04-25 22:00:12 +01:00
c0da615a93 Centralise initial clearing of the puzzle window.
I don't know how I've never thought of this before! Pretty much every
game in this collection has to have a mechanism for noticing when
game_redraw is called for the first time on a new drawstate, and if
so, start by covering the whole window with a filled rectangle of the
background colour. This is a pain for implementers, and also awkward
because the drawstate often has to _work out_ its own pixel size (or
else remember it from when its size method was called).

The backends all do that so that the frontends don't have to guarantee
anything about the initial window contents. But that's a silly
tradeoff to begin with (there are way more backends than frontends, so
this _adds_ work rather than saving it), and also, in this code base
there's a standard way to handle things you don't want to have to do
in every backend _or_ every frontend: do them just once in the midend!

So now that rectangle-drawing operation happens in midend_redraw, and
I've been able to remove it from almost every puzzle. (A couple of
puzzles have other approaches: Slant didn't have a rectangle-draw
because it handles even the game borders using its per-tile redraw
function, and Untangle clears the whole window on every redraw
_anyway_ because it would just be too confusing not to.)

In some cases I've also been able to remove the 'started' flag from
the drawstate. But in many cases that has to stay because it also
triggers drawing of static display furniture other than the
background.
2021-04-25 13:07:59 +01:00
c6a48bfc1c Docs: fix Mosaic copy-and-paste error. 2021-04-25 11:17:13 +01:00
0377184510 New puzzle: 'Mosaic'.
This is similar in concept to Minesweeper, in that each clue tells you
the number of things (in this case, just 'black squares') in the
surrounding 3x3 grid section.

But unlike Minesweeper, there's no separation between squares that can
contain clues, and squares that can contain the things you're looking
for - a clue square may or may not itself be coloured black, and if
so, its clue counts itself.

So there's also no hidden information: the clues can all be shown up
front, and the difficulty arises from the game generator choosing
which squares to provide clues for at all.

Contributed by a new author, Didi Kohen. Currently only has one
difficulty level, but harder ones would be possible to add later.
2021-04-25 09:59:15 +01:00
77866e1335 wasm/js/emscripten: Fix page loading race
Using a stunt webserver which artificially introduces a 3s delay just
before the last line of the HTML output, I have reproduced a
uwer-reported loading/startup race bug:

Previously the wasm loading was started by the <script> element,
synchronously. If the wasm loading is fast, and finishes before the
HTML loading, the onRuntimeInitialized event may occur before
initPuzzles.  But initPuzzles sets up the event handler.

Fix this bug, and introduce a new comment containing an argument for
the correctness of the new approach.

Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
2021-04-22 21:22:48 +01:00
56ef86f92b New grid type: compass dodecagonal
A grid based on dodecagons with square symmetry. In between dodecagons
there are 4 triangles around 1 square, which resembles a compass rose.
https://en.wikipedia.org/wiki/3-4-3-12_tiling
2021-04-22 06:24:23 +01:00
3cf0a3b7b0 Suppress too-noisy Visual Studio warnings.
With this and the previous commit's fix for real problems, the Puzzles
build on VS is now warning-free.
2021-04-19 18:12:36 +01:00
7a43cc0ca3 windows.c: fix some 64-bit cleanness warnings.
These came from Visual Studio, and seem to be real problems - we're
casting pointers to 32-bit integers, which surely only works by luck
of address-space allocation.
2021-04-19 18:12:06 +01:00
848a160f2e Add .gitignore rules for in-tree builds.
This set of rules should cover make and ninja on Linux, and all of
nmake, ninja and vcxproj on Windows, so that if someone follows the
README build instructions (by doing 'cmake .' in-tree), it should
generate no debris that .gitignore can't filter out.
2021-04-19 18:11:17 +01:00
8fa545c76c Set ALLOW_MEMORY_GROWTH in the Emscripten build.
How embarrassing. When I updated the Emscripten build to use WASM, a
major reason I bothered to do it at all was that I'd heard that WASM
was capable of reallocating its memory arena larger on the fly. Turns
out that it _can_, but only if you specifically set the option in
Emscripten to allow it.

With this option set, I can finish a 25x25 Galaxies, where previously
the game would crash part way through (and not even a very large part)
with errors about memory growth in the Javascript console.
2021-04-16 18:07:15 +01:00
f8b15bab6b icons.cmake: explicitly search for Perl.
This allows the icons build to automatically disable itself if Perl
can't be found at all (and print a warning explaining that that's
why). It also means that if Perl exists on the system but is somewhere
other than /usr/bin (where our #! lines expect it), the icons build
can still run.
2021-04-13 18:14:54 +01:00
69b5e7513a Another rewrite of the WASM apology message.
Now I've had a chance to collect some more data from browser users,
it's got a list of browsers in which we've definitely seen the WASM
puzzle working (so that if _your_ instance of one of those browsers
fails, you should check it for problems at your end, like
configuration details or overzealous web filtering software), and some
thoughts about what to report.

The result is a lot longer than the previous error message, so I've
put the bulk of it in a <details>. That way it won't look so silly
when it initially flashes up while things are loading.
2021-04-08 18:16:26 +01:00
245e4f8ab4 Reword the apology when web puzzles fail to load.
The old one was totally out of date (it mentioned typed arrays and a
specific set of browser versions against which the previous Emscripten
build had been tested).

Also, a couple of users in the last day or two have reported
mysterious failures of the WASM puzzles, which I haven't been able to
reproduce in the same version of the same browser. So something odd is
going on, and this seems like a good place to put suggestions about
what diagnostic information to send.
2021-04-07 07:16:01 +01:00
8c97ef434f Stop advertising GTK 1 as an option!
When I wrote yesterday's commit c0c64dc1051bcbd I momentarily forgot
which of my projects still support GTK 1 and which don't. Puzzles
doesn't.
2021-04-05 11:00:05 +01:00
c0c64dc105 Advertise user-configurable cmake-time config options.
Various cmake variables that I was informally expecting users to set
on the cmake command line (e.g. cmake -DSTRICT=ON, or cmake
-DPUZZLES_GTK_VERSION=2) are now labelled explicitly with the CACHE
tag, and provided with a documentation string indicating what they're
for.

One effect of this is that GUI-like interfaces to your cmake build
directory, such as ccmake or cmake-gui, will show those variables
explicitly to give you a hint that you might want to change them.

Another is that when you do change them, cmake will recognise that it
needs to redo the rest of its configuration. Previously, if you sat in
an existing cmake build directory and did 'cmake -DSTRICT=ON .'
followed by 'cmake -DSTRICT=OFF .', nothing would happen, even though
you obviously meant it to.
2021-04-04 14:58:39 +01:00
c212b4eda3 WASM: add the correct MIME type to .htaccess.
Only just remembered that this was generated by my build scripts.
2021-04-03 11:47:10 +01:00
b685eee478 Install desktop files and pixmaps from CMake 2021-04-03 10:35:14 +01:00
f6434e8496 Update web puzzles to current WASM-based Emscripten.
I presume this will improve performance. Also, if I've understood
correctly, WASM-based compiled web code is capable of automatically
growing its memory, which the previous asm.js build of the puzzles
could not do, and occasionally caused people to complain that if they
tried to play a _really big_ game in their browser, the JS would
eventually freeze because the emulated memory ran out.

I've been putting off doing this for ages because my previous
Emscripten build setup was so finicky that I didn't like to meddle
with it. But now that the new cmake system in this source tree makes
things generally easier, and particularly since I've just found out
that the up-to-date Emscripten is available as a Docker image (namely
"emscripten/emsdk"), this seemed like a good moment to give it a try.

The source and build changes required for this update weren't too
onerous. I was half expecting a huge API upheaval, and indeed there
was _some_ change, but very little:

 - in the JS initPuzzle function, move the call to Module.callMain()
   into Module.onRuntimeInitialized instead of doing it at the top
   level, because New Emscripten's .js output likes to load the
   accompanying .wasm file asynchronously, so you can't call the WASM
   main() until it actually exists.

 - in the JS-side library code, replace all uses of Emscripten's
   Pointer_stringify() function with the new name UTF8ToString(). (The
   new version also has an ASCIIToString(), so I guess the reason for
   the name change is that now you get to choose which character set
   you meant. I need to use UTF-8, so that the × and ÷ signs in Keen
   will work.)

 - set EXTRA_EXPORTED_RUNTIME_METHODS=[cwrap,callMain] on the emcc
   link command line, otherwise they aren't available for my JS setup
   code to call.

 - (removed -s ASM_JS=1 from the link options, though I'm not actually
   sure it made any difference one way or the other in the new WASM
   world)

 - be prepared for a set of .wasm files to show up as build products
   alongside the .js ones.

 - stop building with -DCMAKE_BUILD_TYPE=Release! I'm not sure why
   that was needed, but if I leave that flag on my cmake command line,
   the output .js file fails to embed my emccpre.js, so the initial
   call to initPuzzle() fails from the HTML wrapper page, meaning
   nothing at all happens.
2021-04-03 09:22:49 +01:00
e1b9047b55 emscripten.cmake: remove a rogue diagnostic.
I somehow left this in while I was trying to get the Emscripten cmake
build to work in the first place.
2021-04-03 08:44:22 +01:00
a1bab40025 Support earlier versions of CMake.
At least, for the Unix build, so as to support Debian stable and a
couple of prior Ubuntu LTSes.

Not much needed to change in the cmake scripts; the only noticeable
difference was that the 'install' command needs an explicit RUNTIME
DESTINATION.
2021-04-03 08:03:25 +01:00
e763b9ead8 Don't try to build the icons when cross-compiling.
The puzzle icons are built by compiling and running a preliminary
set of puzzle binaries. We can't do that if the binaries won't run
on the build host.
2021-04-01 17:55:21 +01:00
dd8164b774 Unix: allow adding a prefix to all the puzzle names.
A distro maintainer reminds me that downstreams often want to rename
my quite generic executable names to avoid clashes in bin directories.
Added a cmake option -DOUTPUT_NAME to make that easy.
2021-03-31 18:44:44 +01:00
306fab356e Stop automatically adding warning flags and -Werror.
It's better to be lax for normal users trying to build the puzzles
from source to actually run them. That way, warning changes in some
particular compiler I haven't seen yet won't break the build.

Instead, I've invented a cmake setting -DSTRICT=ON which turns on all
those flags. So I can build with them myself, to ensure the code is as
portable as possible. And that flag is set in Buildscr, so that my
official builds won't complete until that warning mode is satisfied.
2021-03-31 18:44:44 +01:00
76aa9619c0 Provide pre-built icons in the source tarball.
This reinstates the feature of the previous build system, that the C
icon files for the GTK puzzles were included in the source tarball, so
that users building from that instead of from the raw git repo would
not need to run the fiddly piece of build that regenerates them.

Running that fiddly piece of build is much easier in the CMake world
(because it's integrated with the main makefile), but it has a build
dependency on ImageMagick which is easily avoided.

The makefile will still build the icons if it _can_. But in the case
where it can't, it will use pre-built icon source files if they're
available, and only fall back to no-icon.c if it can't even do that.
(So a user checking out from git and building without ImageMagick
present will still be able to build _something_ playable.)
2021-03-31 18:44:44 +01:00
b05a975fee Make the icons build step optional.
This way, ImageMagick is no longer a hard build dependency. For
developers or users, building puzzles without nice icons is preferable
to not building them at all.

(Also, thanks to Michael Quevillon for pointing out very promptly that
my use of 'REQUIRED' in the find_program command was implicitly
depending on a version of CMake in advance of my minimum_required
specification. This change fixes that too, in passing.)
2021-03-31 18:44:44 +01:00
71c66b6fbd desktop.pl: cope with unfinished puzzles.
If I built with an unfinished puzzle enabled, then it will end up in
the 'unfinished' subdir of the main build directory, so desktop.pl
will need to write out a reference to it there.
2021-03-29 21:32:42 +01:00
0f3c2f7cd4 Filling grid gen: slightly randomise neighbour selection.
This is another modification to the same piece of code as the previous
commit. Previously, a square with a neighbour in a same-sized region
was fixed by choosing a neighbour to merge it with that was part of
the smallest region. Now, it's _usually_ that, but sometimes it can be
a larger neighbour instead.

Partly, I hope this might remove a potential source of regularity in
the random grids. But mostly, it prevents the grid generator from
hanging completely on 2x2 grids (e.g. if you gave "2x2#12345" in the
previous state of the code), because with the previous 'always
minimal' rule, the generator would merge together two squares of the
2x2 grid, then the other two, and then (due to maxsize==3) it would
have no merge remaining to clear the final error. Now, every so often,
it will take the unusual option of making a size-3 region instead,
which allows game generation to succeed.
2021-03-29 21:00:13 +01:00
083de051cb Filling: remove directional bias in grid generation.
The method of generating a solved Filling grid (before winnowing
clues) is to loop over every square of the board, and for each one, if
it has a neighbour which is part of a different region of the same
size (i.e. the board is not currently legal), fix it by merging with
one of its neighbours. We pick a neighbour to merge with based on the
size of its region - but we always loop over the four possible
neighbours in the same order, which introduces a directional bias into
the breaking of ties in that comparison.

Now we iterate over the four directions in random order.
2021-03-29 21:00:13 +01:00
1fcb61cffe Filling: fix assertion failure in 3x1 game generation.
This would come up on the game id "3x1#12345", for example. The
failing assertion was (s->board[f] != EMPTY) in expand(), called in
turn from learn_expand_or_one().

It looks as if the problem was that the #define SENTINEL was set too
small. It was intended to be a value that can't coincide with the true
size of any region - and it was set to precisely the area of the whole
board. But on a 3x1 grid, that _can_ coincide with the size of a
region! So a board entry was set to a real region size, and then
mistaken for SENTINEL by another part of the code.

Easy fix: set SENTINEL to be sz+1. Now it really can't coincide with a
region area.
2021-03-29 20:57:42 +01:00
ff3e762fd0 Remove old Windows CE cruft.
The WinCE version of these puzzles hasn't been built for years, and
the last vestiges of its build system vanished with the migration to
CMake. So this seems like a good moment to lose the rest of it.

So the supporting Perl script wceinf.pl is deleted, and so is all the
unused code under '#ifdef _WIN32_WCE' in windows.c. (I removed that
using unifdef, which did a more reliable job than I would have done by
hand!)
2021-03-29 19:04:55 +01:00
3ff4d64060 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.
2021-03-29 19:04:55 +01:00
cc7f5503dc 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.
2021-03-29 19:02:23 +01:00
72b28b5e71 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.
2021-03-29 18:22:20 +01:00
84cb4c6701 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.
2020-12-07 21:43:54 +00:00
78bc9ea7f7 Add method for frontends to query the backend's cursor location.
The Rockbox frontend allows games to be displayed in a "zoomed-in"
state targets with small displays. Currently we use a modal interface
-- a "viewing" mode in which the cursor keys are used to pan around
the rendered bitmap; and an "interaction" mode that actually sends
keys to the game.

This commit adds a midend_get_cursor_location() function to allow the
frontend to retrieve the backend's cursor location or other "region of
interest" -- such as the player location in Cube or Inertia.

With this information, the Rockbox frontend can now intelligently
follow the cursor around in the zoomed-in state, eliminating the need
for a modal interface.
2020-12-07 19:40:06 +00:00
9aa7b7cdfb 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.
2020-06-09 14:38:33 +01:00
66b9e8c7de 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.
2020-05-23 10:25:38 +01:00
f2aeda7184 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".
2020-05-23 10:03:57 +01:00
8110518c33 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.
2020-05-23 09:48:07 +01:00
6285c44610 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.)
2020-05-23 09:08:25 +01:00
31cb5227e6 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.
2020-05-23 09:08:08 +01:00
f21d3e4c74 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.
2020-05-23 09:08:08 +01:00
8629ef8974 groupsolver: show working when using -v on ambiguous puzzles. 2020-05-22 19:01:52 +01:00
7acc554805 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.
2020-05-20 21:02:04 +01:00
432590a05c 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.
2020-05-20 21:02:04 +01:00
c9b3c3896c 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.
2020-05-12 22:05:52 +01:00
38dd338652 Provide visual guide to the cursor location across the rows and columns. 2020-05-11 11:25:06 +01:00
2a0e91bc76 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.
2020-04-12 14:37:47 +01:00