aboutsummaryrefslogtreecommitdiff
path: root/mines.c (follow)
Commit message (Collapse)AuthorAge
* Tighten grid-size limit in MinesBen Harris2023-02-15
| | | | | | | | | | | | | | | | | | | | | | Mines uses random_upto() to decide where to place mines, and random_upto() takes a maximum limit of 2^28-1, so limit the number of grid squares to that (or INT_MAX if someone's still trying to build on a 16-bit system). This avoids an assertion failure: "random_upto: Assertion `bits < 32' failed." which can be demonstrated by this save file: SAVEFILE:41:Simon Tatham's Portable Puzzle Collection VERSION :1:1 GAME :5:Mines PARAMS :5:18090 CPARAMS :5:18090 DESC :11:r9,u,MEdff6 UI :2:D0 TIME :1:0 NSTATES :1:2 STATEPOS:1:2 MOVE :4:O2,1
* Mines: Add assertions to range-check conversions to shortBen Harris2023-02-05
| | | | | I think these should be adequately guarded by the new restrictions on grid size, but I'd prefer to be sure.
* Limit width and height to SHRT_MAX in MinesBen Harris2023-02-05
| | | | | | | | | | | | | | | | | | | | | Mines' "struct set" stores co-ordinates within the grid in a pair of shorts, which leads to very bad behaviour (including heap-based buffer overruns) if the grid is bigger than SHRT_MAX in either dimension. So now we don't allow that. The overrun can be demonstrated by loading this save file, though the precise crash is quite variable. In particular, you seem to get better crashes if the file doesn't have a trailing newline. SAVEFILE:41:Simon Tatham's Portable Puzzle Collection PARAMS :5:06000 CPARAMS :7:6x60000 NSTATES :1:3 STATEPOS:1:2 MOVE :5:C0,00 GAME :5:Mines DESC :22:r8,u,00000000000000000 MOVE ::
* Mines: Don't check if the player has won if they've already lostBen Harris2023-02-01
| | | | | | | | | | | | | | | | | | | | | | | It can't happen in normal play, but if a save file had a "C" (clear around) move that set off a mine, Mines could end up hitting an assertion failure, "ncovered >= nmines". This was because it would check if the player had won by counting covered squares and mines, and of course an uncovered mine is no longer a covered square but is still a mine. Since winning after you're dead isn't possible (at least in Mines), we now skip the check entirely if the player has already died. This save file demonstrates the problem: SAVEFILE:41:Simon Tatham's Portable Puzzle Collection GAME :5:Mines PARAMS :1:7 CPARAMS :1:7 DESC :22:r31,u,0000C000d0000020 NSTATES :1:2 STATEPOS:1:1 MOVE :4:C6,2
* Mines: forbid moves that flag or unflag an exposed squareBen Harris2023-02-01
| | | | | | | interpret_move() couldn't generate them, but execute_move() also needs to forbid them to defend against corrupt save files. I don't think this actually caused any crashes, but it did cause unexpected "1" squares not adjacent to mines.
* 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.
* Limit number of mines in Mines game descriptionBen Harris2023-01-28
| | | | | | | | Without this, it's possible to specify a description that has more mines than there are places on the board to place them, which eventually leads to a division by zero. This can be demonstrated by entering a game description of "3:r8,u," and then clicking anywhere on the board.
* Don't segfault on premature solve moves in MinesBen Harris2023-01-28
| | | | | | | | | | | | | | | | | | | | | If a save file contained a solve move as the first move, Mines would dereference a null pointer trying to look up the (at that point undetermined) mine locations. Now execute_move() politely returns NULL instead. This save file demonstrates the problem: SAVEFILE:41:Simon Tatham's Portable Puzzle Collection VERSION :1:1 GAME :5:Mines PARAMS :5:3x3n0 CPARAMS :5:3x3n0 DESC :127:r0,u,7a142789cabddc3fc4dcb7d2baa4a4937b33c9613ea870ac098e217981ad339930af585557d62048ea745d05b01475d9699596b394cc0adeebf0440a02 UI :2:D0 TIME :1:0 NSTATES :1:2 STATEPOS:1:2 SOLVE :1:S
* Mines: No moving once you're dead!Ben Harris2023-01-15
| | | | | | | If a Mines save file contains a move after the player has already died, this can lead to an assertion failure once there are more mines that covered squares. Better to just reject any move after the player's died.
* Also check for tiny grids in MinesBen Harris2023-01-15
| | | | | A zero-size grid isn't acceptable even if someone has generated it for us.
* Last-ditch maximum size limit for MinesBen Harris2023-01-15
| | | | | | This makes sure that width * height <= INT_MAX, which it rather needs to be. Also a similar check in decode_params when defaulting the number of mines.
* 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.
* mines: Ensure highlights don't vanish at small tile sizesBen Harris2022-11-25
| | | | | | The highlights for covered squares now have a minimum width of 1 pixel, which means that Mines is comfortably playabale down to about 8 pixel tilesize, below which the numbers become unreadable.
* Mines: fix a typo in a comment.Simon Tatham2022-06-12
| | | | A sharp-eyed user just pointed it out.
* 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.
* Mines: add validation for negative mine count.Simon Tatham2020-03-17
| | | | | If this gets through validation, it causes an infinite loop after gameplay begins.
* 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.
* Mines: show the number of safe squares left, if it's small.Simon Tatham2017-09-04
| | | | | | | | | | | | | | | | | | | This is intended to make life easier for the _really_ dense grids in which the generator algorithm falls back to a bare clearing, a tightly packed section round the edges, and a fringe of deductions required in between. In that situation, you can deduce _in principle_ from the remaining- mines counter that there are (say) one, or two, squares left to be uncovered before everything remaining has to be a mine. And often the game will require that deduction in order to solve it all by pure logic. But actually doing it requires counting up the huge number of covered squares in an irregularly shaped area and subtracting the mine count in the status line, which is a real pain. In fact, people failing to do that are the biggest source of (wrong) bug reports about Mines games having no solution, so with any luck this will make my own life easier.
* 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.
* 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]
* 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]
* Vary the behaviour of Mines's solve function depending on whether theSimon Tatham2012-06-10
| | | | | | | | | | | | | | | | | user is already in the 'dead' state when they press it. If so, we reveal the rest of the mines in the grid as if it were the Windows Minesweeper 'you lose' display, which provides information showing what the user got wrong. (Otherwise they have to repeatedly flick back and forth between Solve and Undo if they want to work out which flag they placed wrongly.) If you press Solve while alive, however, the existing behaviour remains unchanged. (This feature was suggested by Clive Jones a couple of weeks after I first wrote Mines, and I've finally got round to doing it!) [originally from svn r9561]
* Changed my mind about midend_is_solved: I've now reprototyped it asSimon Tatham2011-06-19
| | | | | | | | | | | | | | | | midend_status(), and given it three return codes for win, (permanent) loss and game-still-in-play. Depending on what the front end wants to use it for, it may find any or all of these three states worth distinguishing from each other. (I suppose a further enhancement might be to add _non_-permanent loss as a fourth distinct status, to describe situations in which you can't play further without pressing Undo but doing so is not completely pointless. That might reasonably include dead-end situations in Same Game and Pegs, and blown-self-up situations in Mines and Inertia. However, I haven't done this at present.) [originally from svn r9179]
* Fix warnings generated by gcc 4.6.0 about variables set but notSimon Tatham2011-05-04
| | | | | | | | | | thereafter read. Most of these changes are just removal of pointless stuff or trivial reorganisations; one change is actually substantive, and fixes a bug in Keen's clue selection (the variable 'bad' was unreferenced not because I shouldn't have set it, but because I _should_ have referenced it!). [originally from svn r9164]
* Add a function to every game backend which indicates whether a gameSimon Tatham2011-04-02
| | | | | | | | | | | state is in a solved position, and a midend function wrapping it. (Or, at least, a situation in which further play is pointless. The point is, given that game state, would it be a good idea for a front end that does that sort of thing to proactively provide the option to start a fresh game?) [originally from svn r9140]
* Redo Mines and Inertia's mine graphics using an actual circle ratherSimon Tatham2009-09-13
| | | | | | | than an approximating octagon, to improve the look when zoomed to high resolution. [originally from svn r8646]
* Patches from James H to add or improve arrow-key-driven cursors forSimon Tatham2009-01-08
| | | | | | | some puzzles. (Light Up's and Net's are merely polished a bit, but Mines acquires a new one.) [originally from svn r8402]
* New infrastructure feature. Games are now permitted to beSimon Tatham2008-09-06
| | | | | | | | | | | | | | | | | | | | | | _conditionally_ able to format the current puzzle as text to be sent to the clipboard. For instance, if a game were to support playing on a square grid and on other kinds of grid such as hexagonal, then it might reasonably feel that only the former could be sensibly rendered in ASCII art; so it can now arrange for the "Copy" menu item to be greyed out depending on the game_params. To do this I've introduced a new backend function (can_format_as_text_now()), and renamed the existing static backend field "can_format_as_text" to "can_format_as_text_ever". The latter will cause compile errors for anyone maintaining a third-party front end; if any such person is reading this, I apologise to them for the inconvenience, but I did do it deliberately so that they'd know to update their front end. As yet, no checked-in game actually uses this feature; all current games can still either copy always or copy never. [originally from svn r8161]
* Dariusz Olszewski's changes to support compiling for PocketPC. ThisSimon Tatham2007-02-26
| | | | | | | | | | | | is mostly done with ifdefs in windows.c; so mkfiles.pl generates a new makefile (Makefile.wce) and Recipe enables it, but it's hardly any different from Makefile.vc apart from a few definitions at the top of the files. Currently the PocketPC build is not enabled in the build script, but with any luck I'll be able to do so reasonably soon. [originally from svn r7337]
* HTML Help support for Puzzles, with the same kind of automaticSimon Tatham2006-12-24
| | | | | | fallback behaviour as PuTTY's support. [originally from svn r7009]
* Mines's error signalling is highly asymmetric: if you erroneouslySimon Tatham2006-02-20
| | | | | | | | | | | | | believe a square to be empty, you find out instantly and lethally, but if you erroneously believe a square to be full you can occasionally (when it doesn't cause a complementary square to be assumed empty) not notice until you find at the very end of the game that you're one mine heavy. To help with this, here's an error highlighting patch: any number square surrounded by an excess of flags will now light up red. This should be an unintrusive change, because it will never happen unless you make a mistake. [originally from svn r6580]
* Cleanup: remove the `just_used_solve' field from a number of gamesSimon Tatham2005-10-22
| | | | | | | | | | | | | | | which didn't actually need it. It was originally introduced in Fifteen to suppress animation on Solve moves, but midend.c now does that centrally unless the game specifically instructs it otherwise. Therefore, just_used_solve is obsolete in all games which previously used it. (Mines was even worse: it scrupulously maintained the correctness of the field but never used it!) Untangle is exempt from this cleanup: its `just_solved' field is used to change the _length_ of the animation on Solve moves, not to suppress it entirely, and so it has to stay. [originally from svn r6419]
* Cleanup: it was absolutely stupid for game_wants_statusbar() to be aSimon Tatham2005-10-22
| | | | | | | | | function, since it took no parameters by which to vary its decision, and in any case it's hard to imagine a game which only _conditionally_ wants a status bar. Changed it into a boolean data field in the backend structure. [originally from svn r6417]
* Cleanup: remove the game_state parameter to game_colours(). No gameSimon Tatham2005-10-22
| | | | | | | | | | | | was actually using it, and also it wasn't being called again for different game states or different game parameters, so it would have been a mistake to depend on anything in that game state. Games are now expected to commit in advance to a single fixed list of all the colours they will ever need, which was the case in practice already and simplifies any later port to a colour-poor platform. Also this change has removed a lot of unnecessary faff from midend_colours(). [originally from svn r6416]
* Noticed recently that bitcount16() isn't 16-bit clean due to signedSimon Tatham2005-10-22
| | | | | | | | | | shift right. It doesn't actually matter in the current code since the input word only ever uses the bottom 9 bits, but if I ever extended Mines to work in a triangular grid then all 16 bits might be required. Fix this now, while I'm cleaning things up, so that it won't bite me unexpectedly in future. [originally from svn r6415]
* James H has implemented a new `Tricky' difficulty level in Light Up:Simon Tatham2005-09-01
| | | | | | | | | | | | | | | | | | a non-recursive level above Easy, which therefore moves the recursive Hard mode further up still. Play-testing suggests that in fact Tricky is often _harder_ than the old Hard mode, since the latter had limited depth of recursion and would therefore spot complex deductions only if it happened to start a recursion on the right square; Tricky may be limited in the sophistication of its complex deductions, but it never misses one, so its puzzles tend to be hard all over. Also in this checkin, a new source file `nullfe.c', containing all the annoying stub functions required to make command-line solvers link successfully. James wrote this for (the new) lightupsolver, and I've used it to simplify the other stand-alone solvers. [originally from svn r6254]
* Substantial infrastructure upheaval. I've separated the drawing APISimon Tatham2005-08-18
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | as seen by the back ends from the one implemented by the front end, and shoved a piece of middleware (drawing.c) in between to permit interchange of multiple kinds of the latter. I've also added a number of functions to the drawing API to permit printing as well as on-screen drawing, and retired print.py in favour of integrated printing done by means of that API. The immediate visible change is that print.py is dead, and each puzzle now does its own printing: where you would previously have typed `print.py solo 2x3', you now type `solo --print 2x3' and it should work in much the same way. Advantages of the new mechanism available right now: - Map is now printable, because the new print function can make use of the output from the existing game ID decoder rather than me having to replicate all those fiddly algorithms in Python. - the new print functions can cope with non-initial game states, which means each puzzle supporting --print also supports --with-solutions. - there's also a --scale option permitting users to adjust the size of the printed puzzles. Advantages which will be available at some point: - the new API should permit me to implement native printing mechanisms on Windows and OS X. [originally from svn r6190]
* Cleanups to completion flashes: all four of these games used toSimon Tatham2005-08-05
| | | | | | | | | redraw the whole window _every_ time game_redraw() was called during a flash. Now they only redraw the whole window every time the background colour actually changes. Thanks to James H for much of the work. [originally from svn r6166]
* Patches from Ben Hutchings to fix failures of sscanf error checking.Simon Tatham2005-07-29
| | | | [originally from svn r6147]
* game_timing_state() now has access to the game_ui. This means thatSimon Tatham2005-07-10
| | | | | | | | | | | | whether the timer is currently going is no longer solely dependent on the current game_state: it can be dependent on more persistent information stored in the game_ui. In particular, Mines now freezes the timer permanently once you complete a grid for the first time, so that you can then backtrack through your solution process without destroying the information about how long it took you the first time through. [originally from svn r6088]
* Subtle UI change to Mines. Although I mostly find the unified left-Simon Tatham2005-07-10
| | | | | | | | | | | | | button interface (same button to open a closed square or to clear around an open one) to be a massive help, there is one circumstance in which it frequently kills me: if I click down on an open square I want to clear around, then the mouse pointer accidentally drifts over on to the nearest closed square before I release, I'll end up opening that square instead and (usually) dying. So this checkin causes Mines to note which type of square I left-clicked on, and to do nothing if the button release is on the other type. [originally from svn r6086]