aboutsummaryrefslogtreecommitdiff
path: root/galaxies.c (follow)
Commit message (Collapse)AuthorAge
* Galaxies: use new move_cursor() featuresBen Harris2023-08-13
|
* 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 GalaxiesBen Harris2023-06-26
| | | | | | | | The boundary between them for mouse clicks probably wants to be revisited because at the moment it's slightly inside the edge of the grid. I tried using INUI() instead of INGRID() but that just gives a different wrong answer, so I may need to actually understand what's going on here.
* 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.
* Consistently use snew_dsf to allocate dsfs.Simon Tatham2023-04-20
| | | | | All remaining cases where a dsf was allocated via snewn(foo, int) are removed by this change.
* Use a dedicated free function to free dsfs.Simon Tatham2023-04-20
| | | | | No functional change: currently, this just wraps the previous sfree call.
* 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.
* Galaxies: skew grid generation in favour of wiggliness.Simon Tatham2023-03-12
| | | | | | | | | | | | | | | | | | | Ben complained yesterday that Galaxies had a nasty habit of generating games whose solution was a boring set of rectangles. Now that even at Normal mode the solver is better at coping with wiggly tentacled regions, it seems like a good moment to fix that. This change arranges that when we initially generate a filled grid, we try ten times, and pick the wiggliest of the grids we found. This doesn't make any boring rectangle-filled grid _impossible_ - players will still have to stay on their toes, and can't rely 100% on at least a certain number of wiggles existing - but it makes the interesting grids a lot more likely to come up. This skew happens before checking solubility. So it doesn't increase grid generation time by a factor of ten (as it would if we generated ten _soluble_ grids and picked the wiggliest). It's still a speed drop, of course, but a more modest one than that.
* Galaxies: remove 'solver_recurse_depth' in live use.Simon Tatham2023-03-12
| | | | | | | | | | | | | | | | | | | It's horrible to have static mutable state in the live puzzle game. What if some downstream wanted to run the system in multiple threads? For purposes of limiting the recursion depth, we now pass an 'int depth' argument to each call to solver_state_inner(). So in the normal build of the actual puzzle, the static variable isn't needed at all. We only include it in binaries that are going to want to use it for printing indented diagnostics: the CLI solver program, and the live puzzle only if DEBUGGING is defined. The rest of the time, it's absent. A side effect of this change is that when the recursion code makes a guess at a particular tile, the message about that is now indented to the _outer_ level instead of the inner one, because the previous 'depth++' and 'depth--' statements wrapped the whole loop rather than just the recursive call to the solver inside. This makes recursive solving much easier to follow!
* Galaxies: add some higher Unreasonable presets.Simon Tatham2023-03-12
| | | | 10x10 and 15x15 Unreasonable are now feasible, so why not include them?
* Galaxies: remove the 'maxtries' system.Simon Tatham2023-03-12
| | | | | | | | | | | | | | | | | | Most games in this collection don't have one. If you ask them for a hard puzzle, they'll just keep looping round until they actually manage to deliver one. We try to arrange that the standard presets don't take too long to generate, but if the user turns up the game size _and_ uses an expensive difficulty level, our view is that that's up to them. After fixing the bug from the previous commit in which the Galaxies recursion depth limit was not actually doing anything, even 15x15 Unreasonable now generates happily in under a second. So I don't see any reason why Galaxies should be an exception. Hence, now if you ask Galaxies for an Unreasonable puzzle, you _will_ get a puzzle that it grades as Unreasonable, even if that takes a long time to generate.
* Galaxies: fix recursion depth limit in solver.Simon Tatham2023-03-12
| | | | | | | | | | | | | | | | | | | | | The static variable 'solver_recurse_depth' is _mostly_ used by the standalone solver, to appropriately indent the solver diagnostics for the current recursion level. So most uses of it are guarded by an '#ifdef STANDALONE_SOLVER' statement, or some equivalent (such as being inside the solvep() macro). One exception is the check that limits the recursion depth to 5, to avoid getting hung up forever on a too-hard game. Unfortunately, this check depends on the variable actually incrementing when we recurse another level - and it wasn't, because the increment itself was under ifdef! So the generator in live Galaxies could recurse arbitrarily deep, and generate puzzles that the standalone solver found too hard _even_ at Unreasonable mode. Removed the ifdefs, so that solver_recurse_depth is now incremented and decremented. Also, make sure to initialise the depth to 0 at the start of a solver run, just in case it had a bogus value left over from a previous run.
* galaxiessolver: fix soak-test mode.Simon Tatham2023-03-12
| | | | | It called new_game_desc with aux=NULL. But new_game_desc unconditionally writes through aux, expecting it to be valid always.
* Galaxies: new deduction by counting liberties of exclaves.Simon Tatham2023-03-12
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | I've often noticed that Galaxies on 7x7 Unreasonable often generates puzzles that _I_ don't feel as if I had to use recursion and backtracking to solve, suggesting that there's an efficient mode of reasoning available that the puzzle could be using and isn't. One reason for this is that sometimes Galaxies gives up on trying to generate an Unreasonable puzzle (if its MAXTRIES counter runs out) and knowingly falls back to Normal. But that's not the only reason. The other day I got the puzzle 7x7:gsjgzhfedwgzhd, which Galaxies's own solver rates as Unreasonable, and I still think it should be Normal. The full solution to that puzzle is this: +-+-+-+-+-+-+-+ |y x| o | | | + +-+-+-+-+ +o+ | | | | o | | + + o + + +-+-+ | | | | | | | + +-+-+ +-+o+ + | o |o| |o| + +-+-+ +-+-+ + | | | | o | | + + o + +-+-+-+ | | | | | +-+-+-+ + +o+ + | o |x y| | +-+-+-+-+-+-+-+ and Galaxies's Normal-mode solver gets stuck on it at the point where it's managed to deduce that the tiles labelled 'x' can't possibly be associated with any dot other than leftmost dot on the centre row, but is then unable to figure out that the tiles labelled 'y' must also be associated with that dot. But clearly they must, because they're boxed in on all other sides (by the grid edge, and by tiles whose associations are totally obvious), so if either 'x' tile is to find _any_ path back to its home dot, it must go through the neighbouring 'y' tile. So, this commit adds the missing deduction: we use a dsf to identify 'exclaves' (connected sets of tiles all associated to the same dot, but which do not actually contain the dot), and for each exclave we count its 'liberties' (unassociated tiles bordering the exclave, i.e. which would extend the exclave if associated to the same dot). Any exclave with only one liberty must extend into that tile, or else it would be cut off completely from its home dot. In this case, each 'x' tile is an exclave by itself, with 'y' its only liberty. (And once that deduction is done, the pair {x,y} become a larger exclave, which can be deduced in the same way to connect to the next tile.) I think this is a deduction rule simple and obvious enough that it should go in at Normal mode. I've been using it all along in my own play, and was surprised to find the game wasn't already taking it into account. In addition, in a quick cross-test of the two versions, _most_ 7x7 Normal games generated by the modified Galaxies are still rated as Normal by the old less powerful solver. So it doesn't extend the difficulty of Normal mode by very much, if at all. Another benefit is that this should make Normal puzzles more likely to contain twisty regions of this type. Also, of course, the usual effect of adding extra deductions at levels below Unreasonable means that actually Unreasonable puzzles become that much more tricky! I have a couple of ideas for extending this technique to be more powerful still (filled in as comments at the top of the file). For the moment, I've just done the most obvious version. Perhaps the others might need to go in at a higher difficulty level.
* Galaxies: add a missing \n in a diagnostic.Simon Tatham2023-03-12
|
* Galaxies: fix edge coordinates in a diagnostic.Simon Tatham2023-03-10
| | | | | | The coordinates in this 'Setting edge' message from the solver don't match the coordinates of the edge that is actually set. No wonder the solver output was confusing!
* Convert a lot of floating-point constants to single precisionBen Harris2023-02-19
| | | | | | | | | | | | | | | | | | For reasons now lost to history, Puzzles generally uses single-precision floating point. However, C floating-point constants are by default double-precision, and if they're then operated on along with a single-precision variable the value of the variable gets promoted to double precision, then the operation gets done, and then often the result gets converted back to single precision again. This is obviously silly, so I've used Clang's "-Wdouble-promotion" to find instances of this and mark the constants as single-precision as well. This is a bit awkward for PI, which ends up with a cast. Maybe there should be a PIF, or maybe PI should just be single-precision. This doesn't eliminate all warnings from -Wdouble-promotion. Some of the others might merit fixing but adding explicit casts to double just to shut the compiler up would be going too far, I feel.
* 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.
* 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 GalaxiesBen 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.
* galaxies: Use the same code for handling all dropped arrowsBen Harris2022-12-07
| | | | | | | The keyboard code was prone to adding null items to the undo history, and was also unreadable. Rather than fix it, I've replaced it with a jump to the mouse drop handling, lightly enhanced to reject drops on things that aren't tiles.
* Galaxies: store game solution in the aux string.Simon Tatham2021-10-21
| | | | | | | | | Most games store a string in 'aux' during new_game_desc() that saves solve_game() during gameplay from having to reconstruct the solution from scratch. Galaxies had all the facilities available to do that, but apparently just forgot to use them. (Reindents existing code: diff best viewed with whitespace ignored.)
* galaxieseditor: make 'copy to clipboard' give the game id.Simon Tatham2021-05-25
| | | | | | | | | | | | | | | | | | | This seems like a generally helpful design for game editors in general: if we're going to have a helper program that can construct an instance of a game, then one obvious thing you'd want as output from it would be the descriptive game id, suitable for pasting back into the playing UI. So, in the just-re-enabled helper program 'galaxieseditor', I've rewritten game_text_format so that it generates exactly that. Now you can place dots until you have a puzzle you like, then use the 'Copy' menu item to make it into a game id usable in 'galaxies' proper. This doesn't set a precedent that I'm planning to _write_ editors for all the other games, or even any of them (right now). For some, it wouldn't be too hard (especially games where the solution and clues are the same kind of thing, like default-mode Solo); for others, it would be a huge UI nightmare.
* Build a lot of conditioned-out test and helper programs.Simon Tatham2021-05-25
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Most of these aren't especially useful, but if we're going to have them in the code base at all, we should at least ensure they compile: bit-rotted conditioned-out code is of no value. One of the new programs is 'galaxieseditor', which borrows most of the Galaxies code but changes the UI so that you can create and remove _dots_ instead of edges, and then run the solver to see whether it can solve the puzzle you've designed. Unlike the rest, this is a GUI helper tool, using the 'guiprogram' cmake function introduced in the previous commit. The programs are: - 'combi', a test program for the utility module that generates all combinations of n things - 'divvy', a test program for the module that divides a rectangle at random into equally-sized polyominoes - 'penrose-test', a test program for the Penrose-tiling generator used in Loopy, which outputs an SVG of a piece of tiling - 'penrose-vector', a much smaller test program for the vector arithmetic subroutines in that code - 'sort-test', a test of this code base's local array sorting routine - 'tree234-test', the exhaustive test code that's been in tree234.c all along. Not all of them compiled first time. Most of the fixes were the usual kind of thing: fixing compiler warnings by removing unused variables/functions, bringing uses of internal APIs up to date. A notable one was that galaxieseditor's interpret_move() modified the input game state, which was an error all along and is now detected by me having made it a const pointer; I had to replace that with an extra wrinkle in the move-string format, so that now execute_move() makes the modification. The one I'm _least_ proud of is squelching a huge number of format-string warnings in tree234-test by interposing a variadic function without __attribute__((printf)).
* Galaxies: clean up draw/undraw code for dragged arrows.Simon Tatham2021-05-21
| | | | | | | | | | | | | | | | | | | | | The previous code had multiple bugs. We had completely left out the draw_update after drawing each arrow; we omitted the usual precautionary clip() that constrains each arrow draw to the same rectangle we just saved in the blitter; we re-computed the coordinates of the opposite arrow at undraw time, instead of saving the coordinates we _actually_ used after computing them the first time. And we restored from the two blitters in the same order we saved them, instead of reverse order, which was harmless at the time (the drawing happened after both saves), but is generally bad practice, and needed to be fixed when the code was rearranged to fix the rest of these issues. I noticed these issues in passing, while hunting the diagonal-line bug fixed in the previous commit. These fixes by themselves would have prevented any persistent drawing artefact as a result of that bug (the clip() would have constrained the spurious diagonal line to the region saved by the blitter, so it would have been undrawn again afterwards); but it's better to have fixed the root cause as well!
* Galaxies: avoid division by zero in draw_arrow().Simon Tatham2021-05-21
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | During an interactive drag of an arrow, it's possible to put the mouse pointer precisely on the pixel the arrow is pointing at. When that happens, draw_arrow computes the zero-length vector from the pointer to the target pixel, and tries to normalise it to unit length by dividing by its length. Of course, this leads to computing 0/0 = NaN. Depending on the platform, this can cause different effects. Conversion of a floating-point NaN to an integer is not specified by IEEE 754; on some platforms (e.g. Arm) it comes out as 0, and on others (e.g. x86), INT_MIN. If the conversion delivers INT_MIN, one possible effect is that the arrow is drawn as an immensely long diagonal line, pointing upwards and leftwards from the target point. To add to the confusion, that line would not immediately appear on the display in full, because of the draw_update system. But further dragging-around of arrows will gradually reveal it as draw_update rectangles intersect the corrupted display area. However, that diagonal line need not show up at all, because once draw_arrow has accidentally computed a lot of values in the region of INT_MIN, it then adds them together, causing signed integer overflow (i.e. undefined behaviour) to confuse matters further! In fact, this diagonal-line drawing artefact has only been observed on the WebAssembly front end. The x86 desktop platforms might very plausibly have done it too, but in fact they didn't (I'm guessing because of this UB issue, or else some kind of clipping inside the graphics library), which is how we haven't found this bug until now. Having found it, however, the fix is simple. If asked to draw an arrow from a point to itself, take an early return from draw_arrow before dividing by zero, and don't draw anything at all.
* Galaxies: disallow placing an edge touching a dot.Simon Tatham2021-05-20
| | | | | | | | | Trivially, no edge of this kind can be part of any legal solution, so it's a minor UI affordance that doesn't spoil any of the puzzly thinking to prevent the user accidentally placing them in the first place. Suggestion from Larry Hastings, although this is not his patch.
* 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.
* 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.
* 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.
* 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.
* 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.
* 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.
* New name UI_UPDATE for interpret_move's return "".Simon Tatham2017-10-01
| | | | | | | | | | | | | Now midend.c directly tests the returned pointer for equality to this value, instead of checking whether it's the empty string. A minor effect of this is that games may now return a dynamically allocated empty string from interpret_move() and treat it as just another legal move description. But I don't expect anyone to be perverse enough to actually do that! The main purpose is that it avoids returning a string literal from a function whose return type is a pointer to _non-const_ char, i.e. we are now one step closer to being able to make this code base clean under -Wwrite-strings.
* Rework the preset menu system to permit submenus.Simon Tatham2017-04-26
| | | | | | | | | | | | | | | | | | | | To do this, I've completely replaced the API between mid-end and front end, so any downstream front end maintainers will have to do some rewriting of their own (sorry). I've done the necessary work in all five of the front ends I keep in-tree here - Windows, GTK, OS X, Javascript/Emscripten, and Java/NestedVM - and I've done it in various different styles (as each front end found most convenient), so that should provide a variety of sample code to show downstreams how, if they should need it. I've left in the old puzzle back-end API function to return a flat list of presets, so for the moment, all the puzzle backends are unchanged apart from an extra null pointer appearing in their top-level game structure. In a future commit I'll actually use the new feature in a puzzle; perhaps in the further future it might make sense to migrate all the puzzles to the new API and stop providing back ends with two alternative ways of doing things, but this seemed like enough upheaval for one day.