aboutsummaryrefslogtreecommitdiff
path: root/palisade.c (follow)
Commit message (Collapse)AuthorAge
* Last-ditch maximum size limit for PalisadeBen Harris2023-01-15
| | | | | This makes sure that width * height <= INT_MAX, which it rather needs to be.
* Palisade: forbid moves that remove grid edgesBen Harris2023-01-15
| | | | | | | | | | | | | | | | | | | Without this check, a corrupt save file can include a move that removes an edge of the grid, and then is_solved() walks off the edge of the grid causing a buffer over- or under-run. To demonstrate the bug, load this save file in a build with AddressSanitizer: SAVEFILE:41:Simon Tatham's Portable Puzzle Collection VERSION :1:1 GAME :8:Palisade PARAMS :5:5x5n5 CPARAMS :5:5x5n5 DESC :0: NSTATES :1:2 STATEPOS:1:2 MOVE :6:F0,0,1
* 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.
* Palisade: scale line thickness unboundedly with tile size.Simon Tatham2022-11-18
| | | | | | | | | | The previous expression for WIDTH defined it, curiously, as (1 + (TILESIZE >= 16) + (TILESIZE >= 32) + (TILESIZE >= 64)) which is roughly logarithmic in tile size, but bounded above by a maximum of 4 pixels. On high-DPI displays this isn't really good enough any more. Now I've set the line thickness to a constant fraction of the tile size (but still bounded below by 1), so it's much easier to see the lines when the puzzle is expanded to extra large size.
* Palisade: explicitly use 'signed char' for clues.Simon Tatham2021-12-11
| | | | | | | Previously, the typedef 'clue' was just 'char', but it was used in the expectation that it would be signed. So on platforms that default to unsigned char, such as 32-bit Arm, Palisade would completely fail to function correctly.
* 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.
* 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.
* Add missing casts to unsigned char inside ctype functions.Simon Tatham2016-02-01
| | | | | | These are necessary because the argument to a ctype function cannot be a negative value unless it's EOF. Thanks to Cygwin gcc for pointing out the mistake, and to Patrick Shaughnessy for this patch.
* Fix loophole in Palisade completion checker.Simon Tatham2015-11-03
| | | | | | | | | | | | | | | | | | | | A user pointed out that if you construct a 'solution' in which no clue square has too _many_ borders but at least one has too few, and then bring those clues up to their count by adding extra stray border lines _inside_ a connected component (avoiding actually dividing any component completely into two), then the game checker treats that as solved for victory-flash purposes, on the grounds that (a) the grid is divided into components of the right size and (b) all clues are satisfied. A small example is 4x4n4:22a2b2c33, with the non-solution of dividing the grid into four 2x2 square blocks and then adding a spurious extra edge between the two 3 clues. The old Palisade completion check would flash for victory _at the same time_ as highlighting the spurious edge in COL_ERROR. Fixed by enforcing in is_solved() that every border line must separate two distinct connected components.
* Format Palisade solve-type moves in sensible ASCII.Simon Tatham2015-11-03
| | | | | | | | | | | | | | | The solve move stored in 'aux' by new_game_desc consists of printable characters in the range '@' to 'O', each representing a 4-bit bitmap of edges around a cell. But the one generated on the fly by solve_game() was missing out the 0x40 bit and just returning characters in the range ^@ to ^O - which would not only have been horrible if you found such a string in a save file, but also meant that a game with any completely borderless square would have a solution move string terminating early due to the ^@, causing execute_move() to reject it. Example: ./palisade --test-solve --generate 1 5x5n5#12345-37 now succeeds, where previously it failed an assertion.
* Add a new puzzle: Palisade.Jonas Kölker2015-10-18