aboutsummaryrefslogtreecommitdiff
path: root/dominosa.c (follow)
Commit message (Collapse)AuthorAge
* Dominosa: use new move_cursor() featuresBen Harris2023-08-09
|
* move_cursor(): handle visible flag; return useful valueBen Harris2023-08-09
| | | | | | | | | | | | | | | | | This adds an extra parameter to move_cursor() that's an optional pointer to a bool indicating whether the cursor is visible. This allows for centralising the common idiom of having the keyboard cursor become visible when a cursor key is pressed. Consistently with the vast majority of existing puzzles, the cursor moves even if it was invisible before, and becomes visible even if it can't move. The function now also returns one of the special constants that can be returned by interpret_move(), so that the caller can correctly return MOVE_UI_UPDATE or MOVE_NO_EFFECT without needing to carefully check for changes itself. Callers are updated only to the extent that they all pass NULL as the new argument. Most of them could now be substantially simplified.
* Distinguish MOVE_UNUSED from MOVE_NO_EFFECT in DominosaBen Harris2023-06-24
| | | | | | | | | The only tricky bit is whether clicking precisely on the diagonal of a square (which never has any effect on the game) is MOVE_UNUSED or MOVE_NO_EFFECT. I decided that having single-pixel lines in the middle of the grid causing events to be passed back to the environment would be very confusing, so they're MOVE_NO_EFFECT. Clicking entirely outside the grid, on the other hand, returns MOVE_UNUSED.
* Rename UI_UPDATE as MOVE_UI_UPDATEBen Harris2023-06-11
| | | | | | | | All the other constants named UI_* are special key names that can be passed to midend_process_key(), but UI_UPDATE is a special return value from the back-end interpret_move() function instead. This renaming makes the distinction clear and provides a naming convention for future special return values from interpret_move().
* New backend functions: get_prefs and set_prefs.Simon Tatham2023-04-23
| | | | | | | | | | | | | | | | | | | | | | | | These are similar to the existing pair configure() and custom_params() in that get_prefs() returns an array of config_item describing a set of dialog-box controls to present to the user, and set_prefs() receives the same array with answers filled in and implements the answers. But where configure() and custom_params() operate on a game_params structure, the new pair operate on a game_ui, and are intended to permit GUI configuration of all the settings I just moved into that structure. However, nothing actually _calls_ these routines yet. All I've done in this commit is to add them to 'struct game' and implement them for the functions that need them. Also, config_item has new fields, permitting each config option to define a machine-readable identifying keyword as well as the user-facing description. For options of type C_CHOICES, each choice also has a keyword. These keyword fields are only defined at all by the new get_prefs() function - they're left uninitialised in existing uses of the dialog system. The idea is to use them when writing out the user's preferences into a configuration file on disk, although I haven't actually done any of that work in this commit.
* Pass a game_ui to compute_size, print_size and print.Simon Tatham2023-04-21
| | | | | | | I'm about to move some of the bodgy getenv-based options so that they become fields in game_ui. So these functions, which could previously access those options directly via getenv, will now need to be given a game_ui where they can look them up.
* Reorganise the dsf API into three kinds of dsf.Simon Tatham2023-04-20
| | | | | | | | | | | | | | | | | | This is preparing to separate out the auxiliary functionality, and perhaps leave space for making more of it in future. The previous name 'edsf' was too vague: the 'e' stood for 'extended', and didn't say anything about _how_ it was extended. It's now called a 'flip dsf', since it tracks whether elements in the same class are flipped relative to each other. More importantly, clients that are going to use the flip tracking must say so when they allocate the dsf. And Keen's need to track the minimal element of an equivalence class is going to become a non-default feature, so there needs to be a new kind of dsf that specially tracks those, and Keen will have to call it. While I'm here, I've renamed the three dsf creation functions so that they start with 'dsf_' like all the rest of the dsf API.
* Remove size parameter from dsf init and copy functions.Simon Tatham2023-04-20
| | | | | | | | | Now that the dsf knows its own size internally, there's no need to tell it again when one is copied or reinitialised. This makes dsf_init much more about *re*initialising a dsf, since now dsfs are always allocated using a function that will initialise them anyway. So I think it deserves a rename.
* Declare all dsfs as a dedicated type name 'DSF'.Simon Tatham2023-04-20
| | | | | | | In this commit, 'DSF' is simply a typedef for 'int', so that the new declaration form 'DSF *' translates to the same type 'int *' that dsfs have always had. So all we're doing here is mechanically changing type declarations throughout the code.
* Use a dedicated free function to free dsfs.Simon Tatham2023-04-20
| | | | | No functional change: currently, this just wraps the previous sfree call.
* Stop putting dsfs in existing scratch int arrays.Simon Tatham2023-04-20
| | | | | | | | | | | | | | | | | | | | | | | I'm going to work towards turning 'dsf' into an opaque type, so that I can improve its implementation without breaking clients. The first step is to deal manually with puzzles that currently reuse a single array of ints for multiple purposes, some of which are dsf and some are not. In divvy_rectangle_attempt, 'tmp' was used as an int array and later a dsf, and I've made a new 'tmpdsf' to be the latter. In Dominosa, solver->pc_scratch2 was sometimes a dsf, and now there's a new solver->dsf_scratch. In Map, parse_edge_list() needed a dsf internally and then never exported it; it expected to be passed an array of 2*w*h ints and used the second half as a dsf. Now it expects only w*h ints, and allocates its own dsf internally, freeing it again before returning. And in Tents, find_errors() was allocating a single block of 2*w*h ints and using the second half of it as a dsf, apparently just to save one malloc. Now we malloc and free the dsf separately.
* Make encode_ui() and decode_ui() optional in back-endsBen Harris2023-04-08
| | | | | | | | | | | | The majority of back-ends define encode_ui() to return NULL and decode_ui() to do nothing. This commit allows them to instead specify the relevant function pointers as NULL, in which case the mid-end won't try to call them. I'm planning to add a parameter to decode_ui(), and if I'm going to have to touch every back-end's version of decode_ui(), I may as well ensure that most of them never need to be touched again. And obviously encode_ui() should go the same way for symmetry.
* Fall back to <math.h> if <tgmath.h> doesn't work.Simon Tatham2023-04-06
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This fixes a build failure introduced by commit 2e48ce132e011e8 yesterday. When I saw that commit I expected the most likely problem would be in the NestedVM build, which is currently the thing with the most most out-of-date C implementation. And indeed the NestedVM toolchain doesn't have <tgmath.h> - but much more surprisingly, our _Windows_ builds failed too, with a compile error inside <tgmath.h> itself! I haven't looked closely into the problem yet. Our Windows builds are done with clang, which comes with its own <tgmath.h> superseding the standard Windows one. So you'd _hope_ that clang could make sense of its own header! But perhaps the problem is that this is an unusual compile mode and hasn't been tested. My fix is to simply add a cmake check for <tgmath.h> - which doesn't just check the file's existence, it actually tries compiling a file that #includes it, so it will detect 'file exists but is mysteriously broken' just as easily as 'not there at all'. So this makes the builds start working again, precisely on Ben's theory of opportunistically using <tgmath.h> where possible and falling back to <math.h> otherwise. It looks ugly, though! I'm half tempted to make a new header file whose job is to include a standard set of system headers, just so that that nasty #ifdef doesn't have to sit at the top of almost all the source files. But for the moment this at least gets the build working again.
* Replace <math.h> with <tgmath.h> throughoutBen Harris2023-04-04
| | | | | | | | | | | | | | | C89 provided only double-precision mathematical functions (sin() etc), and so despite using single-precision elsewhere, those are what Puzzles has traditionally used. C99 introduced single-precision equivalents (sinf() etc), and I hope it's been long enough that we can safely use them. Maybe they'll even be faster. Rather than directly use the single-precision functions, though, we use the magic macros from <tgmath.h> that automatically choose the precision of mathematical functions based on their arguments. This has the advantage that we only need to change which header we include, and thus that we can switch back again if some platform has trouble with the new header.
* Add an environment variable to control initial cursor visibilityBen Harris2023-03-22
| | | | | | | | | | | | | If you define PUZZLES_INITIAL_CURSOR=y, puzzles that have a keyboard cursor will default to making it visible rather than invisible at the start of a new game. Behaviour is otherwise the same, so mouse actions will cause the cursor to vanish and keyboard actions will cause it to appear. It's just the default that has changed. The purpose of this is for use on devices and platforms where the primary or only means of interaction is keyboard-based. In those cases, starting with the keyboard cursor invisible is weird and a bit confusing.
* Fix missing statics and #includes on variables.Simon Tatham2023-02-18
| | | | | | | | | | | | | | | | | | | | | | | After Ben fixed all the unwanted global functions by using gcc's -Wmissing-declarations to spot any that were not predeclared, I remembered that clang has -Wmissing-variable-declarations, which does the same job for global objects. Enabled it in -DSTRICT=ON, and made the code clean under it. Mostly this was just a matter of sticking 'static' on the front of things. One variable was outright removed ('verbose' in signpost.c) because after I made it static clang was then able to spot that it was also unused. The more interesting cases were the ones where declarations had to be _added_ to header files. In particular, in COMBINED builds, puzzles.h now arranges to have predeclared each 'game' structure defined by a puzzle backend. Also there's a new tiny header file gtk.h, containing the declarations of xpm_icons and n_xpm_icons which are exported by each puzzle's autogenerated icon source file and by no-icon.c. Happily even the real XPM icon files were generated by our own Perl script rather than being raw xpm output from ImageMagick, so there was no difficulty adding the corresponding #include in there.
* Mark many more function (and some objects) staticBen Harris2023-02-18
| | | | | | | | | | | | | I noticed commit db3b531e2cab765a00475054d2e9046c9d0437d3 in the history where Simon added a bunch of "static" qualifiers. That suggested that consistently marking internal functions "static" is desirable, so I tried a build using GCC's -Wmissing-declarations, which requires prior declaration (presumed to be in a header file) of all global functions. This commit makes the GTK build clean under GCC's -Wmissing-declarations. I've also adding "static" to a few obviously internal objects, but GCC doesn't complain about those so I certainly haven't got them all.
* Dominosa: require the two halves of a domino to be adjacentBen Harris2023-02-02
| | | | | | | | | | | | | | | | | | | Also that a line indicating no domino be between adjacent squares. Without this, execute_move would allow you to place dominos and edges between any pair ot squares, and then generate assertion failures ("execute_move: Assertion `d2 - w >= 0' failed." and "execute_move: Assertion `d1 - w >= 0' failed.") when a domino was placed over an invalid edge. This example save file demonstrates the problem: SAVEFILE:41:Simon Tatham's Portable Puzzle Collection GAME :8:Dominosa PARAMS :1:6 CPARAMS :1:6 DESC :56:55521461210004364611033535444421636022603153156422620503 NSTATES :1:3 STATEPOS:1:3 MOVE :4:E0,2 MOVE :4:D0,2
* Remove various unused game functionsBen Harris2023-01-31
| | | | | | | | | | | | | | | | | | | | If can_configure is false, then the game's configure() and custom_params() functions will never be called. If can_solve is false, solve() will never be called. If can_format_as_text_ever is false, can_format_as_text_now() and text_format() will never be called. If can_print is false, print_size() and print() will never be called. If is_timed is false, timing_state() will never be called. In each case, almost all puzzles provided a function nonetheless. I think this is because in Puzzles' early history there was no "game" structure, so the functions had to be present for linking to work. But now that everything indirects through the "game" structure, unused functions can be left unimplemented and the corresponding pointers set to NULL. So now where the flags mentioned above are false, the corresponding functions are omitted and the function pointers in the "game" structures are NULL.
* Last-ditch grid-size limit for DominosaBen Harris2023-01-15
| | | | At least prevent integer overflow when constructing the grid.
* New backend function: current_key_label()Ben Harris2022-12-09
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This provides a way for the front end to ask how a particular key should be labelled right now (specifically, for a given game_state and game_ui). This is useful on feature phones where it's conventional to put a small caption above each soft key indicating what it currently does. The function currently provides labels only for CURSOR_SELECT and CURSOR_SELECT2. This is because these are the only keys that need labelling on KaiOS. The concept of labelling keys also turns up in the request_keys() call, but there are quite a few differences. The labels returned by current_key_label() are dynamic and likely to vary with each move, while the labels provided by request_keys() are constant for a given game_params. Also, the keys returned by request_keys() don't generally include CURSOR_SELECT and CURSOR_SELECT2, because those aren't necessary on platforms with pointing devices. It might be possible to provide a unified API covering both of this, but I think it would be quite difficult to work with. Where a key is to be unlabelled, current_key_label() is expected to return an empty string. This leaves open the possibility of NULL indicating a fallback to button2label or the label specified by request_keys() in the future. It's tempting to try to implement current_key_label() by calling interpret_move() and parsing its output. This doesn't work for two reasons. One is that interpret_move() is entitled to modify the game_ui, and there isn't really a practical way to back those changes out. The other is that the information returned by interpret_move() isn't sufficient to generate a label. For instance, in many puzzles it generates moves that toggle the state of a square, but we want the label to reflect which state the square will be toggled to. The result is that I've generally ended up pulling bits of code from interpret_move() and execute_move() together to implement current_key_label(). Alongside the back-end function, there's a midend_current_key_label() that's a thin wrapper around the back-end function. It just adds an assertion about which key's being requested and a default null implementation so that back-ends can avoid defining the function if it will do nothing useful.
* Centralise initial clearing of the puzzle window.Simon Tatham2021-04-25
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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.
* 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.
* 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.
* 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).
* 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.
* 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.
* 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 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.
* 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.)
* Add a request_keys() function with a midend wrapper.Franklin Wei2018-04-22
| | | | | | | | This function gives the front end a way to find out what keys the back end requires; and as such it is mostly useful for ports without a keyboard. It is based on changes originally found in Chris Boyle's Android port, though some modifications were needed to make it more flexible.
* Make the code base clean under -Wwrite-strings.Simon Tatham2017-10-01
| | | | | I've also added that warning option and -Werror to the build script, so that I'll find out if I break this property in future.
* Return error messages as 'const char *', not 'char *'.Simon Tatham2017-10-01
| | | | | They're never dynamically allocated, and are almost always string literals, so const is more appropriate.
* Use a proper union in struct config_item.Simon Tatham2017-10-01
| | | | | | This allows me to use different types for the mutable, dynamically allocated string value in a C_STRING control and the fixed constant list of option names in a C_CHOICES.