aboutsummaryrefslogtreecommitdiff
Commit message (Collapse)AuthorAge
...
* Dominosa: further forms of set analysis.Simon Tatham2019-04-11
| | | | | | | | | | | | | | | | | | 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.
* Dominosa: be more careful about >= Hard layout.Simon Tatham2019-04-11
| | | | | | 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.
* Dominosa: max-difficulty option in the solver.Simon Tatham2019-04-11
| | | | | | 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.
* Dominosa: more sophisticated grid layout in >= Hard mode.Simon Tatham2019-04-10
| | | | | | | | | | | | | | | | | | | | 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.
* Dominosa: add presets for Hard and Extreme difficulty.Simon Tatham2019-04-05
| | | | | | 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.
* Dominosa: prevent hangs generating tiny hard puzzles.Simon Tatham2019-04-05
| | | | | | 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.
* Dominosa: add an Extreme difficulty, with forcing chains.Simon Tatham2019-04-05
| | | | | | | | | | | | | | | | | | | | | 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.
* Fix a handful of memory leaks in the midend.Simon Tatham2019-04-05
| | | | | I happened to notice these when running dominosa --generate under Leak Sanitiser.
* New utility routine: sort with a context parameter.Simon Tatham2019-04-05
| | | | | | | | | | 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.
* Dominosa: update the to-do list.Simon Tatham2019-04-04
| | | | | | | | 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.
* Dominosa: allow set analysis even with adjacency.Simon Tatham2019-04-04
| | | | | | | | | | | | | | | | | 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.)
* Dominosa: add a Hard difficulty which can do set analysis.Simon Tatham2019-04-04
| | | | | | | | 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).
* Dominosa: new deduction deduce_local_duplicate().Simon Tatham2019-04-04
| | | | | | This is a reasonably simple local deduction I've been using myself for ages, and feel comfortable adding to the existing Basic difficulty level.
* Dominosa: introduce a difficulty system.Simon Tatham2019-04-04
| | | | | | | | | | | 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.
* Dominosa: rewrite the solver.Simon Tatham2019-04-04
| | | | | | | | | | | 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.
* Dominosa: add a command-line solver.Simon Tatham2019-04-04
| | | | | | 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.
* Galaxies: prevent creation of empty undo-chain items.Simon Tatham2019-02-18
| | | | | | | | | | | | | | 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.
* Pegs: clear ui->cur_jumping on undo or redo.Simon Tatham2019-02-10
| | | | | | | | 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.
* benchmark.pl: replace use of Perl <> with <<>>.Simon Tatham2019-01-25
| | | | | | | 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!
* Replace fe->preset_menu when we change midend.Simon Tatham2018-12-12
| | | | | | | | | | | | | | | 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.
* Fix GTK 2 crash introduced by previous commit.Simon Tatham2018-11-25
| | | | | | | | | 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.
* Don't initialise GTK in --screenshot mode.Simon Tatham2018-11-23
| | | | | | | | | | | | | | | | | | | | | | | | | | | | 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.
* Add missing 'static' to game-internal declarations.Simon Tatham2018-11-13
| | | | | | | | | 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.
* Unruly, Group: reference-count the 'immutable' array.Simon Tatham2018-11-13
| | | | | | | | | 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.
* Add missing binary 'matching' to .gitignore.Simon Tatham2018-11-13
|
* Add a missing const in unfinished/sokoban.c.Simon Tatham2018-11-13
| | | | | I noticed this when I temporarily enabled compilation of all the unfinished puzzles while doing the bool trawl.
* Use C99 bool within source modules.Simon Tatham2018-11-13
| | | | | | | | | | 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.
* Replace TRUE/FALSE with C99 true/false throughout.Simon Tatham2018-11-13
| | | | | | 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.
* Adopt C99 bool in the grid.c API.Simon Tatham2018-11-13
| | | | | More or less trivially: the only affected declaration is the has_incentre flag in struct grid_face.
* Adopt C99 bool in the shared Latin-square API.Simon Tatham2018-11-13
| | | | | latin_check now returns bool, and latin_solver_diff_set takes a bool 'extreme' flag. Should be non-disruptive.
* Adopt C99 bool in the tree234 API.Simon Tatham2018-11-13
| | | | | The only affected function here is splitpos234, which I don't think these puzzles are even using at the moment.
* Adopt C99 bool in misc.c functions.Simon Tatham2018-11-13
| | | | | The 'decode' flag to obfuscate_bitmap and the 'wrap' flag to move_cursor are the only ones affected here.
* Adopt C99 bool in the findloop API.Simon Tatham2018-11-13
| | | | | | 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.
* Adopt C99 bool in the edsf API.Simon Tatham2018-11-13
| | | | | | | | | | 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.
* Adopt C99 bool in the printing API.Simon Tatham2018-11-13
| | | | | | | | | | | | | | 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.
* Adopt C99 bool in the midend API.Simon Tatham2018-11-13
| | | | | | | | | | | | | 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.
* Adopt C99 bool in the game backend API.Simon Tatham2018-11-13
| | | | | | | | | | | 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.
* Add a #include of <stdbool.h>.Simon Tatham2018-11-13
| | | | | This is the first commit in a series which will adopt C99 bool throughout the code base where it makes sense to do so.
* Undead: remove an unused structure field.Simon Tatham2018-11-07
| | | | | | | | | | | | 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.
* Fix an inaccurate comment.Simon Tatham2018-11-06
| | | | | | | | | 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.
* Fix a misuse of errno.Simon Tatham2018-11-06
| | | | | | | | | | 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.
* Fix OSX build failure from latest XCode update.Simon Tatham2018-10-06
| | | | | | | | | | | | | | 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 :-)
* Net: highlight more errors in locked tiles.Jacob Nevins2018-09-23
| | | | | If a locked tile has an edge pointing at a barrier, or at another locked tile without a matching edge, colour that edge red.
* Net: rename 'loop' to 'err' in UI code.Jacob Nevins2018-09-23
| | | | | In preparation for highlighting other kinds of errors. No intended functional change.
* Dominosa: some more solver thoughts.Simon Tatham2018-09-21
| | | | | | | 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.)
* cube.c: Prohibit unsolvable single row/column gameMichael Quevillon2018-09-13
| | | | | | 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.
* Fix docs link from the JS Rectangles page.Simon Tatham2018-07-24
| | | | | It pointed to rectangles.html, which doesn't exist, in place of rect.html which does.
* Tracks: stop drawing background for clues in game_print.Simon Tatham2018-07-20
| | | | | This makes the clue numbers actually visible in the printed output, instead of black on black.
* Fix return value from newgame_undo_deserialise_read.Simon Tatham2018-06-21
| | | | | | | | | | | | | 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.
* Fix NUL-termination bug in saving from Javascript.Simon Tatham2018-06-21
| | | | | | | 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.