aboutsummaryrefslogtreecommitdiff
path: root/pearl.c (follow)
Commit message (Collapse)AuthorAge
* Last-ditch maximum size limit for PearlBen Harris2023-01-15
| | | | | This makes sure that width * height <= INT_MAX, which it rather needs to be.
* Pearl: make PEARL_GUI_LOOPY affect printed output.Simon Tatham2022-12-11
| | | | | | This display style is perfectly playable on paper (proof: it works for Loopy), so there's no reason not to support both modes in both output routines.
* 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.
* pearl: Return NULL when Backspace or Escape does nothingBen Harris2022-11-18
| | | | | | When there's no drag in progress, cancelling the drag has no effect. Returning NULL lets the front-end know this, which in particular means the Backspace key can leave the app in KaiOS.
* Pearl: Require width or height to be at least 6 for TrickyBen Hutchings2022-07-31
| | | | | | | | | Josh Triplett reported: > If I ask pearl to generate a 5x5 tricky puzzle, it runs forever. I find that 5x6 or 6x5 works, so set the minimum accordingly. References: https://bugs.debian.org/667963
* Pearl: reorder helper functions.Simon Tatham2022-01-27
| | | | | | interpret_ui_drag is now called from update_ui_drag, so it makes more sense to have the former appear first in the file, together with its comment explaining the expected usage.
* Pearl: permit drawing a whole loop in one drag.Simon Tatham2022-01-27
| | | | | | | | | | | | A user reported recently that they were trying this as an extra challenge (solve the whole puzzle mentally and then draw it in finished form in one UI action). But the backtracking behaviour of Pearl's dragging mode meant that the loop erased itself as soon as the drag came back to a revisited position. In this commit I fix that by making the exception that you can unconditionally return to the start point of the drag, _provided_ that in doing so you don't create a grid cell of degree > 2.
* 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)).
* 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.
* 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.
* 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.
* Fix missing error highlights (+ array underrun!) in Pearl.Simon Tatham2016-12-16
| | | | | | | | | | | | I was accidentally re-checking the value of component_state[comp] after resetting comp to the special value -1, which caused a failure to highlight stray path-shaped components if they existed in addition to a large loop component. (Plus, of course, it's just illegal no matter what visible behaviour it does or doesn't cause in practice.) Fixed by adjusting the code to more closely match the version in Loopy (I wonder how I managed to add two pieces of code in commit b31155b73 without noticing this difference between them).
* Account for disconnected paths in Loopy and Pearl error highlights.Simon Tatham2016-04-28
| | | | | | | | | | | | | | | | | | | | | | | | In commits 24848706e and adc54741f, I revamped the highlighting of erroneous connected components of those two puzzles' solution graphs in cases where a non-solution loop existed, so that the largest component was considered correct and the smaller ones lit up in red. I intended this to work in the cases where you have most of a correct solution as one component and a small spurious loop as another (in which case the latter lights up red), or conversely where your mostly correct component was joined into a loop leaving a few edges out (in which case the left-out edges again light up red). However, a user points out that I overlooked the case where your mostly correct solution is not all one component! If you've got lots of separate pieces of path, and one tiny loop that's definitely wrong, it's silly to light up all but the longest piece of path as if they're erroneous. Fixed by treating all the non-loop components as one unit for these purposes. So if there is at least one loop and it isn't the only thing on the board, then we _either_ light up all loops (if they're all smaller than the set of non-loop paths put together), _or_ light up everything but the largest loop (if that loop is the biggest thing on the board).
* Pearl: revise loop detection similarly to Loopy.Simon Tatham2016-02-24
| | | | | | | | | | | | | | | | | | Pearl has more or less the same attitude to loops as Loopy does, in that a loop is required in the solution but some loops during play want to be highlighted as errors. So it makes sense to use the same strategy for loop highlighting. I've cloned-and-hacked the code from Loopy rather than abstracting it out, because there were some fiddly differences in application (like checking of untouched clues in Pearl). Perhaps some day I can come back and make it all neater. Also, while I'm here, I've cleaned up the loop_length field in game_state, which was carefully set up by check_completion() but never actually used for anything. (If I remember rightly, it was going to be used for a fancy victory flash which never saw the light of day.)
* Pearl: reinstate a conditioned-out assertion.Simon Tatham2016-02-24
| | | | | | | | | I think this assertion must have been put under '#if 0' during early development, and accidentally never taken out once the game started actually working. Putting it back in doesn't cause the self-tests to fail, so I'm reinstating it - if it does fail, I'd like to know about it!
* build fixSimon Tatham2015-10-03
|
* Cancel dragging in Pearl by pressing Escape or Backspace.Jonas Kölker2015-10-03
|
* Change Pearl's cursor logic.Jonas Kölker2015-10-03
| | | | | | Keyboard dragging while holding Control now moves the cursor to the target square. Shift-Control-arrowkey performs the previous behavior of Control-arrowkey.
* Refactor Pearl's mark_in_direction, and invert a parameter.Jonas Kölker2015-10-03
|
* Refactor modifier handling in Pearl's cursor code.Jonas Kölker2015-10-03
|
* Add game_text_format to Pearl.Jonas Kölker2015-10-03
|
* Fix a typo in the comments of Pearl.Jonas Kölker2015-10-03
| | | | Each stone can have 2 lines radiating from its centre, not 3.
* Giant const patch of doom: add a 'const' to every parameter in everySimon Tatham2013-04-13
| | | | | | | | | | | | | | puzzle backend function which ought to have it, and propagate those consts through to per-puzzle subroutines as needed. I've recently had to do that to a few specific parameters which were being misused by particular puzzles (r9657, r9830), which suggests that it's probably a good idea to do the whole lot pre-emptively before the next such problem shows up. [originally from svn r9832] [r9657 == 3b250baa02a7332510685948bf17576c397b8ceb] [r9830 == 0b93de904a98f119b1a95d3a53029f1ed4bfb9b3]
* Add 'const' to the game_params arguments in validate_desc andSimon Tatham2013-04-12
| | | | | | | | | | | | new_desc. Oddities in the 'make test' output brought to my attention that a few puzzles have been modifying their input game_params for various reasons; they shouldn't do that, because that's the game_params held permanently by the midend and it will affect subsequent game generations if they modify it. So now those arguments are const, and all the games which previously modified their game_params now take a copy and modify that instead. [originally from svn r9830]
* Bring Pearl's game-completion handling in line with my usual practice:Simon Tatham2013-01-19
| | | | | | | | | the 'completed' flag is not reset if you make a new move transforming a solved game into an unsolved state, so the game won't flash again if you manually erase and redraw a line segment (though it still will if you undo and redo past the first solved state in the undo history). [originally from svn r9750]
* New rule: interpret_move() is passed a pointer to the game_drawstateSimon Tatham2012-09-09
| | | | | | | | | | | | | | | | basically just so that it can divide mouse coordinates by the tile size, but is definitely not expected to _write_ to it, and it hadn't previously occurred to me that anyone might try. Therefore, interpret_move() now gets a pointer to a _const_ game_drawstate instead of a writable one. All existing puzzles cope fine with this API change (as long as the new const qualifier is also added to a couple of subfunctions to which interpret_move delegates work), except for the just-committed Undead, which somehow had ds->ascii and ui->ascii the wrong way round but is otherwise unproblematic. [originally from svn r9657]
* Add a difficulty exception to prevent Pearl spinning forever whenSimon Tatham2012-04-08
| | | | | | asked to generate a 5x5 Tricky puzzle. (Debian bug #667963) [originally from svn r9454]
* Patch from Jonas Koelker to add keyboard control support to Pearl.Simon Tatham2012-02-19
| | | | [originally from svn r9411]
* Tweak a conditional expression in pearl.c to work around a display bugSimon Tatham2012-02-17
| | | | | | | | | | in the Java build - which turns out to be a JVM bug in OpenJDK 6, causing the NestedVM rendition of the expression (i==1?3:4) to be mis-JITed. OpenJDK 7 appears not to do that any more, but this equivalent (for these purposes) rephrasing should perturb the code just enough to dodge the problem. [originally from svn r9408]
* Fix one-character typo in r9405 which was breaking right-clicks.Simon Tatham2012-02-13
| | | | | [originally from svn r9406] [r9405 == 0c13787c2a17adc891f8e47c06b259f80bc8251a]
* David Nickerson reports odd behaviour involving a drag start pointSimon Tatham2012-02-08
| | | | | | | | | | persisting between separate mouse actions. Revamp all uses of the ndragcoords field in an attempt to stamp that out: we now distinguish between active drags (>0), a valid click but no drag yet (0), and a totally invalid situation in which all mouse activity will be ignored until the next fresh attempt (-1). [originally from svn r9405]
* David Nickerson reports that it's possible to lay a line over a 'noSimon Tatham2012-02-02
| | | | | | | | | | line here' cross mark by dragging, and furthermore, that doing so puts that grid edge into a stuck state that no UI action short of undo can get it back out of. Fix drags to stop at crosses, and fix execute_move to fault any move string that nonetheless somehow managed to try to set a line over a cross without explicitly tagging it 'R'. [originally from svn r9400]
* Move a debug statement at the end of new_clues from the caller (justSimon Tatham2012-01-31
| | | | | | | | | | after return) to the callee (just before). Might print something useful in the soak-test context (where that debug statement will now be printed and previously wasn't), but the main aim is to remove the variable 'ngen' at the main call site, which triggered a set-but-not- used warning if the debug statement that printed it was compiled out. [originally from svn r9392]
* Tweak right-click processing to be less finicky.Simon Tatham2012-01-22
| | | | [originally from svn r9381]
* New puzzle! Or rather, new-ish, because this one has been lying aroundSimon Tatham2012-01-22
in the 'unfinished' directory for a while, and has now been finished up thanks to James Harvey putting in some effort and galvanising me to put in the rest. This is 'Pearl', an implementation of Nikoli's 'Masyu'. The code in Loopy that generates a random loop along grid edges to use as the puzzle solution has been abstracted out into loopgen.[ch] so that Pearl can use it for its puzzle solutions too. I've also introduced a new utility module called 'tdq' (for 'to-do queue'). [originally from svn r9379]