aboutsummaryrefslogtreecommitdiff
Commit message (Collapse)AuthorAge
...
* Don't try to build the icons when cross-compiling.Simon Tatham2021-04-01
| | | | | | 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.
* Unix: allow adding a prefix to all the puzzle names.Simon Tatham2021-03-31
| | | | | | 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.
* Stop automatically adding warning flags and -Werror.Simon Tatham2021-03-31
| | | | | | | | | | | 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.
* Provide pre-built icons in the source tarball.Simon Tatham2021-03-31
| | | | | | | | | | | | | | | | | 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.)
* Make the icons build step optional.Simon Tatham2021-03-31
| | | | | | | | | | | 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.)
* desktop.pl: cope with unfinished puzzles.Simon Tatham2021-03-29
| | | | | | 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.
* Filling grid gen: slightly randomise neighbour selection.Simon Tatham2021-03-29
| | | | | | | | | | | | | | | | | | 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.
* Filling: remove directional bias in grid generation.Simon Tatham2021-03-29
| | | | | | | | | | | | | 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.
* Filling: fix assertion failure in 3x1 game generation.Simon Tatham2021-03-29
| | | | | | | | | | | | | | | | 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.
* Remove old Windows CE cruft.Simon Tatham2021-03-29
| | | | | | | | | | | 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!)
* Remove winiss.pl.Simon Tatham2021-03-29
| | | | | | | 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.
* Migrate to a CMake-based build system.Simon Tatham2021-03-29
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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.
* Fix bit rot in the 'unfinished' subdir.Simon Tatham2021-03-29
| | | | | | | | | | | | 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.
* Galaxies: fix assertion failure when adding out-of-bounds association.Franklin Wei2020-12-07
| | | | | | | | | | 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.
* Add method for frontends to query the backend's cursor location.Franklin Wei2020-12-07
| | | | | | | | | | | | | | | | 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.
* Group: fix assertion failure in Unreasonable generation.Simon Tatham2020-06-09
| | | | | | | 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.
* Unequal: fill in the latin.c validator function.Simon Tatham2020-05-23
| | | | | | | 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.
* Towers: fill in the latin.c validator function.Simon Tatham2020-05-23
| | | | | Again, this seems to have made no difference in a test generation run with the command "towers --generate 100 6du#12345".
* Keen: fill in the latin.c validator function.Simon Tatham2020-05-23
| | | | | | | 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.
* Group: hard-mode identity deduction.Simon Tatham2020-05-23
| | | | | | | | | | | | | | | | | | | | | | | 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.)
* Group: fill in the latin.c validator function.Simon Tatham2020-05-23
| | | | | | | | | 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.
* latin.c: call a user-provided validator function. [NFC]Simon Tatham2020-05-23
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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.
* groupsolver: show working when using -v on ambiguous puzzles.Simon Tatham2020-05-22
|
* Group: fix loop bounds in the solver.Simon Tatham2020-05-20
| | | | | | | | | | | | | | | | | | 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.
* Group: add a special deduction about the group identity.Simon Tatham2020-05-20
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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.
* unfinished/path: some jottings towards a solver.Simon Tatham2020-05-12
| | | | | | 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.
* Provide visual guide to the cursor location across the rows and columns.Robert Konigsberg2020-05-11
|
* grid.c: fix size miscalculation in Floret tiling.Simon Tatham2020-04-12
| | | | | | | | | | | | | 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.
* GTK 3: handle nontrivial window scale factors.Simon Tatham2020-04-07
| | | | | | | | | | | | | | | 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.
* Mines: add validation for negative mine count.Simon Tatham2020-03-17
| | | | | If this gets through validation, it causes an infinite loop after gameplay begins.
* Tracks: fix a small memory leak.Simon Tatham2020-02-26
| | | | Spotted by Leak Sanitiser while I was testing the standalone solver.
* Tracks: add reverse neighbour deduction in hard mode.Simon Tatham2020-02-26
| | | | | | | | | | | | | | | | | 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.
* Tracks: new parity-based deduction.Simon Tatham2020-02-26
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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.
* Tracks: new neighbour-based deduction.Simon Tatham2020-02-26
| | | | | | | | | | | | | 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.
* Tracks: add standalone solver program.Simon Tatham2020-02-26
| | | | | | | 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.
* Tracks: make solver return max difficulty used.Simon Tatham2020-02-26
| | | | | | | 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.
* Improve const-correctness in printing API.Asher Gordon2019-12-30
| | | | | Most of the functions in printing.c do not modify their 'document *' argument, and therefore can declare them as 'const'.
* Add printing support for GTK.Asher Gordon2019-12-30
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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]
* Update the copyright holders list in puzzles.but.Simon Tatham2019-12-28
| | | | | | 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.
* Don't segfault when no icons are available.Asher Gordon2019-12-25
| | | | | | | | | | 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().
* Make --screenshot work even in (Cairo) GTK2 builds.Simon Tatham2019-11-13
| | | | | | | | | | | | 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.
* .gitignore: add more autotools detritus.Simon Tatham2019-11-13
| | | | | | | 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!
* Fix build failure reported in gcc 9.Simon Tatham2019-09-01
| | | | | | | | | | | 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.
* Fix build failure in C90 mode.Simon Tatham2019-04-14
| | | | Thanks to Anders Höglund for pointing it out.
* Dominosa: move set analysis with doubles into Extreme.Simon Tatham2019-04-13
| | | | | | | | | | | | | | | | | 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.
* Dominosa: add area-parity deductions, at Basic level.Simon Tatham2019-04-13
| | | | | | | | | | | | 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.
* findloop: alternative query function.Simon Tatham2019-04-13
| | | | | | | | | | | | | | | | | | | | | | | | 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.
* Dominosa: another forcing-chain based deduction.Simon Tatham2019-04-13
| | | | | | | | 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.
* Dominosa: another local deduction in Basic level.Simon Tatham2019-04-13
| | | | | | | | | | | | | | 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).
* Javascript frontend: make Shift- and Ctrl-click work.Simon Tatham2019-04-12
| | | | | | 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.