aboutsummaryrefslogtreecommitdiff
path: root/samegame.c (unfollow)
Commit message (Collapse)Author
2023-08-09Use move_cursor() for cursor movement in Same GameBen Harris
No significant behavioural change.
2023-08-01Same Game: level-triggered keyboard cursor hidingBen Harris
Same Game doesn't want to show the keyboard cursor when the game is in a state where no move is possible. Previously, it did this by having game_changed_state() hide the cursor on entry to such a state. That meant that reaching a dead end and undoing out of it hid the cursor, which was confusing. Now the cursor is hidden in game_redraw() if the game is in a dead-end state without changing the displaysel flag in the game_ui. That way, if you undo out of a dead end, the cursor becomes visible again if it was visible before. This does mean that you can move the cursor in a dead-end state without being able to see where it's going. I think that's tolerable, but maybe the cursor keys should be disabled in that state as well.
2023-07-31Distinguish MOVE_UNUSED from MOVE_NO_EFFECT in Same GameBen Harris
2023-07-31Same Game: don't hide keyboard cursor on unrecognised keysBen Harris
Pressing "undo", for instance, should leave the keyboard cursor visible if it's visible already. Only mouse clicks should hide it.
2023-07-31Same Game: scale TILE_GAP with tilesizeBen Harris
TILE_GAP represents the gap between the coloured parts of adjacent different-coloured tiles. Rather than a fixed 2 pixels, it's now 1/16 of the tilesize (rounded to nearest). This looks the same at the default tilesize of 32, but behaves better with larger or smaller tilesizes. At tilesizes below 8, the gap disappears altogether, but that seems appropriate: at 7 pixels there's not much space for the inner and outer squares and the cursor, and those are all more important than the gap..
2023-07-30Same Game: more efficient tile_redrawBen Harris
I've rewritten tile_redraw to reduce the number of calls to draw_rect(). Before, it would generally make five calls to draw_rect() when drawing a tile. Now it makes at most three, and usually two. That's one draw_rect() for each colour that appears in the tile, which is as good as it can get. This reduces the time to draw a large puzzle by about 35% on Firefox 102. This is of significance to me because CanvasRenderingContext2D on my test KaiOS device seems to have a limit on the number of fill() and fillRect() calls that it will tolerate in a short time. This means that if you issue more than 1024 fillRect() calls in rapid succession, the later ones are simply ignored. Same Game's largest preset called draw_rect() so much that it hit this limit. That meant that the right-hand side of the grid didn't get properly drawn when starting a new game. Now that it is less profligate with draw_rect() it fits comfortably within the limit and I get to see the entire grid.
2023-07-27Use the standard game_mkhighlight in Same GameBen Harris
This should ensure that the cursor is visible on the background.
2023-07-27Same Game: darken light colours to make keyboard cursor visibleBen Harris
The keyboard cursor in Same Game is white. The default yellow, cyan, and light green were light enough to make the cursor hard to see. I've darkened them all (without changing their hues) so that the cursor is acceptably visible. This doesn't leave an ideal set of colours, but they are at least still adequately distinct from one another.
2023-06-16Fix some unused-variable warnings.Simon Tatham
A test-build with a modern clang points out a number of 'set but not used' variables, which clang seems to have got better at recently. In cases where there's conditioned-out or commented-out code using the variable, I've left it in and added a warning-suppressing cast to void. Otherwise I've just deleted the variables.
2023-06-11Rename UI_UPDATE as MOVE_UI_UPDATEBen Harris
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().
2023-04-23New backend functions: get_prefs and set_prefs.Simon Tatham
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.
2023-04-21Pass a game_ui to compute_size, print_size and print.Simon Tatham
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.
2023-04-08Make encode_ui() and decode_ui() optional in back-endsBen Harris
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.
2023-04-06Fall back to <math.h> if <tgmath.h> doesn't work.Simon Tatham
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.
2023-04-04Replace <math.h> with <tgmath.h> throughoutBen Harris
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.
2023-03-22Add an environment variable to control initial cursor visibilityBen Harris
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.
2023-02-19Convert a lot of floating-point constants to single precisionBen Harris
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.
2023-01-31Remove various unused game functionsBen Harris
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.
2023-01-15Same Game: reject moves with unexpected characters inBen Harris
Previously if a move string starting with "M" contained anything else other than a digit or a comma, execute_move() would spin trying to parse it. Now it returns NULL.
2023-01-15Last-ditch maximum size limit for Same GameBen Harris
This makes sure that width * height <= INT_MAX, which it rather needs to be.
2022-12-09New backend function: current_key_label()Ben Harris
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.
2021-04-25Centralise initial clearing of the puzzle window.Simon Tatham
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.
2020-12-07Add method for frontends to query the backend's cursor location.Franklin Wei
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.
2018-11-13Use C99 bool within source modules.Simon Tatham
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.
2018-11-13Replace TRUE/FALSE with C99 true/false throughout.Simon Tatham
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.
2018-11-13Adopt C99 bool in the game backend API.Simon Tatham
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.
2018-04-22Add a request_keys() function with a midend wrapper.Franklin Wei
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.
2017-10-01Make the code base clean under -Wwrite-strings.Simon Tatham
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.
2017-10-01Return error messages as 'const char *', not 'char *'.Simon Tatham
They're never dynamically allocated, and are almost always string literals, so const is more appropriate.
2017-10-01Use a proper union in struct config_item.Simon Tatham
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.
2017-10-01New name UI_UPDATE for interpret_move's return "".Simon Tatham
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.
2017-04-26Rework the preset menu system to permit submenus.Simon Tatham
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.
2013-04-13Giant const patch of doom: add a 'const' to every parameter in everySimon Tatham
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]
2013-04-12Add 'const' to the game_params arguments in validate_desc andSimon Tatham
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]
2012-09-09New rule: interpret_move() is passed a pointer to the game_drawstateSimon Tatham
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]
2011-06-19Changed my mind about midend_is_solved: I've now reprototyped it asSimon Tatham
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]
2011-04-02Add a function to every game backend which indicates whether a gameSimon Tatham
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]
2008-09-13Patch from James H providing lots more paranoid casting. Also oneSimon Tatham
actual behaviour change: Untangle now permits dragging with the right mouse button, which has exactly the same effect as it does with the left. (Harmless on desktop platforms, but helpful when "right-click" is achieved by press-and-hold; now the drag takes place even if you hesitate first.) [originally from svn r8177]
2008-09-13Patch from James H to centralise some generally useful cursor-Simon Tatham
handling functionality into misc.c. [originally from svn r8176]
2008-09-06New infrastructure feature. Games are now permitted to beSimon Tatham
_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]
2006-12-24HTML Help support for Puzzles, with the same kind of automaticSimon Tatham
fallback behaviour as PuTTY's support. [originally from svn r7009]
2005-10-22Cleanup: it was absolutely stupid for game_wants_statusbar() to be aSimon Tatham
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]
2005-10-22Cleanup: remove the game_state parameter to game_colours(). No gameSimon Tatham
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]
2005-10-22Cleanup: the `mouse_priorities' field in the back end has been aSimon Tatham
more general-purpose flags word for some time now. Rename it to `flags'. [originally from svn r6414]
2005-08-18Substantial infrastructure upheaval. I've separated the drawing APISimon Tatham
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]
2005-08-05Cleanups to completion flashes: all four of these games used toSimon Tatham
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]
2005-08-04Patch from James H: tinker with the presets on SLOW_SYSTEMs.Simon Tatham
[originally from svn r6162]
2005-07-22James H profiled the new Same Game grid generator and discovered itSimon Tatham
was spending 60% of its time in shuffle(). The purpose of the shuffle() call was to go through a largish array in random order until we found an element that worked, so there's no actual need to shuffle the whole array every time and I only did it out of laziness. So I now pick a random element each time I go round the loop, meaning I save a lot of shuffling effort whenever the loop terminates early (which is often). I get about a factor of two speed improvement from this small change. [originally from svn r6125]
2005-07-21Until now, Same Game has been the only puzzle in this collectionSimon Tatham
which is unable to guarantee that every grid it generates can be solved. So I'm eliminating that exception: this checkin contains a more sophisticated grid generator which does guarantee solubility. It's a bit slow (most noticeably on the 15x10c3 preset), and the quality of the generated grids is slightly weird (a tendency toward small regions rather than large sweeping areas of contiguous colour); however, I'm willing to see the latter as a feature for now, since making the game more challenging while simultaneously guaranteeing it to be possible sounds like an all-round win to me. From now on I'm raising my standards for contributions to this collection. I made this fix to Same Game because I heard a user _automatically assume_ that any puzzle in my collection would not be so uncouth as to generate an impossible grid; as of this checkin that's actually true, and I intend to maintain that standard of quality henceforth. (Guaranteeing a _unique_ solution is more of an optional extra, since there are many games for which it isn't a meaningful concept or isn't particularly desirable. Which is not to say that _some_ games wouldn't be of unacceptably low quality if they failed to guarantee uniqueness; it depends on the game.) [originally from svn r6124]
2005-07-17Quite a few instances of the Cardinal Error of Ctype were turned upSimon Tatham
by a grep I just did. Oops. [originally from svn r6113]