46 Commits

Author SHA1 Message Date
c0da615a93 Centralise initial clearing of the puzzle window.
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.
2021-04-25 13:07:59 +01:00
78bc9ea7f7 Add method for frontends to query the backend's cursor location.
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.
2020-12-07 19:40:06 +00:00
5f5b284c0b Use C99 bool within source modules.
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-13 21:48:24 +00:00
a550ea0a47 Replace TRUE/FALSE with C99 true/false throughout.
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-13 21:48:24 +00:00
a76d269cf2 Adopt C99 bool in the game backend API.
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-11-13 21:34:42 +00:00
60a929a250 Add a request_keys() function with a midend wrapper.
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.
2018-04-22 17:04:50 +01:00
a58c1b216b Make the code base clean under -Wwrite-strings.
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-01 16:35:40 +01:00
b3243d7504 Return error messages as 'const char *', not 'char *'.
They're never dynamically allocated, and are almost always string
literals, so const is more appropriate.
2017-10-01 16:34:41 +01:00
de67801b0f Use a proper union in struct config_item.
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-01 16:34:41 +01:00
eeb2db283d New name UI_UPDATE for interpret_move's return "".
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-10-01 15:18:14 +01:00
a7dc17c425 Rework the preset menu system to permit submenus.
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.
2017-04-26 21:51:23 +01:00
251b21c418 Giant const patch of doom: add a 'const' to every parameter in every
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-13 10:37:32 +00:00
0b93de904a Add 'const' to the game_params arguments in validate_desc and
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]
2013-04-12 17:11:49 +00:00
3b250baa02 New rule: interpret_move() is passed a pointer to the game_drawstate
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]
2012-09-09 18:40:12 +00:00
73daff3937 Changed my mind about midend_is_solved: I've now reprototyped it as
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-06-19 13:43:35 +00:00
980880be1f Add a function to every game backend which indicates whether a game
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]
2011-04-02 16:19:12 +00:00
1d661ec46b Patch from James H providing lots more paranoid casting. Also one
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-13 18:29:20 +00:00
5ead207060 Patch from James H to centralise some generally useful cursor-
handling functionality into misc.c.

[originally from svn r8176]
2008-09-13 18:26:53 +00:00
a7431c0b7c New infrastructure feature. Games are now permitted to be
_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]
2008-09-06 09:27:56 +00:00
7b1f7d3e01 HTML Help support for Puzzles, with the same kind of automatic
fallback behaviour as PuTTY's support.

[originally from svn r7009]
2006-12-24 15:56:47 +00:00
eb2013efc0 Cleanup: it was absolutely stupid for game_wants_statusbar() to be a
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-22 16:52:16 +00:00
40fcf516f4 Cleanup: remove the game_state parameter to game_colours(). No game
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-22 16:44:38 +00:00
b7f192eea3 Cleanup: the `mouse_priorities' field in the back end has been a
more general-purpose flags word for some time now. Rename it to
`flags'.

[originally from svn r6414]
2005-10-22 16:35:23 +00:00
af59dcf685 Substantial infrastructure upheaval. I've separated the drawing API
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-18 17:50:14 +00:00
c321a88408 Cleanups to completion flashes: all four of these games used to
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-05 17:17:23 +00:00
dc74c8b93d Patch from James H: tinker with the presets on SLOW_SYSTEMs.
[originally from svn r6162]
2005-08-04 17:08:26 +00:00
a605a17d05 James H profiled the new Same Game grid generator and discovered it
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-22 11:06:57 +00:00
6bce285027 Until now, Same Game has been the only puzzle in this collection
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-21 18:06:31 +00:00
e33a57b703 Quite a few instances of the Cardinal Error of Ctype were turned up
by a grep I just did. Oops.

[originally from svn r6113]
2005-07-17 17:10:11 +00:00
3d2c442bc4 game_timing_state() now has access to the game_ui. This means that
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]
2005-07-10 10:17:13 +00:00
145301d0dc Change of policy on game_changed_state(). Originally, it was called
by the midend every time the game state changed _other_ than as a
result of make_move(), on the basis that when the game state changed
due to make_move() the game backend had probably noticed anyway.
However, when make_move() split up, this became more fiddly: if the
game_ui had to be updated based on some property of the final game
state, then execute_move() couldn't do it because it didn't have a
pointer to the game_ui, but it was fiddly to do it in
interpret_move() because that didn't directly have a copy of the
finished game state to examine. Same Game (the only game to be
affected) had to deal with this by actually having interpret_move()
_call_ execute_move() to construct a temporary new game state,
update the UI, and then throw it away.

So now, game_changed_state() is called _every_ time the current game
state changes, which means that if anything needs doing to the
game_ui as a result of examining the new game state, it can be done
there and save a lot of effort.

[originally from svn r6087]
2005-07-10 10:06:04 +00:00
f3c95109c7 Add a `full' parameter to validate_params(), analogous to the one in
encode_params(). This is necessary for cases where generation-time parameters
that are normally omitted from descriptive IDs can place restrictions on other
parameters; in particular, when the default value of a relevant generation-time
parameter is not the one used to generate the descriptive ID, validation could
reject self-generated IDs (e.g., Net `5x2w:56182ae7c2', and some cases in
`Pegs').

[originally from svn r6068]
2005-07-05 21:27:19 +00:00
b74dac6de2 Refactored the game_size() interface, which was getting really
unpleasant and requiring lots of special cases to be taken care of
by every single game. The new interface exposes an integer `tile
size' or `scale' parameter to the midend and provides two much
simpler routines: one which computes the pixel window size given a
game_params and a tile size, and one which is given a tile size and
must set up a drawstate appropriately. All the rest of the
complexity is handled in the midend, mostly by binary search, so
grubby special cases only have to be dealt with once.

[originally from svn r6059]
2005-07-05 18:13:31 +00:00
64e114cce1 draw_polygon() and draw_circle() have always had a portability
constraint: because some front ends interpret `draw filled shape' to
mean `including its boundary' while others interpret it to mean `not
including its boundary' (and X seems to vacillate between the two
opinions as it moves around the shape!), you MUST NOT draw a filled
shape only. You can fill in one colour and outline in another, you
can fill or outline in the same colour, or you can just outline, but
just filling is a no-no.

This leads to a _lot_ of double calls to these functions, so I've
changed the interface. draw_circle() and draw_polygon() now each
take two colour arguments, a fill colour (which can be -1 for none)
and an outline colour (which must be valid). This should simplify
code in the game back ends, while also reducing the possibility for
coding error.

[originally from svn r6047]
2005-07-03 09:35:29 +00:00
118abb4fc9 General robustness patch from James Harvey:
- most game_size() functions now work in doubles internally and
   round to nearest, meaning that they have less tendency to try to
   alter a size they returned happily from a previous call
 - couple of fiddly fixes (memory leaks, precautionary casts in
   printf argument lists)
 - midend_deserialise() now constructs an appropriate drawstate,
   which I can't think how I overlooked myself since I _thought_ I
   went through the entire midend structure field by field!

[originally from svn r6041]
2005-06-30 09:07:00 +00:00
ea172a0460 New {en,de}code_ui functions should be static. Oops.
[originally from svn r6031]
2005-06-28 17:43:50 +00:00
89fdc09c29 More serialisation changes: the game_aux_info structure has now been
retired, and replaced with a simple string. Most of the games which
use it simply encode the string in the same way that the Solve move
will also be encoded, i.e. solve_game() simply returns
dupstr(aux_info). Again, this is a better approach than writing
separate game_aux_info serialise/deserialise functions because doing
it this way is self-testing (the strings are created and parsed
during the course of any Solve operation at all).

[originally from svn r6029]
2005-06-28 11:14:09 +00:00
cdb8433c0a Another function pair required for serialisation; these ones save
and restore anything vitally important in the game_ui. Most of the
game_ui is expected to be stuff about cursor positions and currently
active mouse drags, so it absolutely _doesn't_ want to be preserved
over a serialisation; but one or two things would be disorienting or
outright wrong to reset, such as the Net origin position and the
Mines death counter.

[originally from svn r6026]
2005-06-28 07:33:49 +00:00
76d50e6905 Re-architecting of the game backend interface. make_move() has been
split into two functions. The first, interpret_move(), takes all the
arguments that make_move() used to get and may have the usual side
effects of modifying the game_ui, but instead of returning a
modified game_state it instead returns a string description of the
move to be made. This string description is then passed to a second
function, execute_move(), together with an input game_state, which
is responsible for actually producing the new state. (solve_game()
also returns a string to be passed to execute_move().)

The point of this is to work towards being able to serialise the
whole of a game midend into a byte stream such as a disk file, which
will eventually support save and load functions in the desktop
puzzles, as well as restoring half-finished games after a quit and
restart in James Harvey's Palm port. Making each game supply a
convert-to-string function for its game_state format would have been
an unreliable way to do this, since those functions would not have
been used in normal play, so they'd only have been tested when you
actually tried to save and load - a recipe for latent bugs if ever I
heard one. This way, you won't even be able to _make_ a move if
execute_move() doesn't work properly, which means that if you can
play a game at all I can have pretty high confidence that
serialising it will work first time.

This is only the groundwork; there will be more checkins to come on
this theme. But the major upheaval should now be done, and as far as
I can tell everything's still working normally.

[originally from svn r6024]
2005-06-27 19:34:54 +00:00
db88c9b9a4 Redraw glitch: tiles marked black (at game-over time) were not
redrawn as non-black on undo. Introduce a new flag TILE_IMPOSSIBLE,
so that information about those black markers is cached in the
drawstate and we know when we have to erase them.

In the process I've removed the game_state argument completely from
the subfunction tile_redraw(), which gives me some confidence that
it isn't getting any _more_ privileged information out of it.

[originally from svn r5979]
2005-06-19 14:33:06 +00:00
f01f82105e Infrastructure change which I've been thinking about for a while:
the back end function solve_game() now takes the _current_
game_state in addition to the initial one.

[originally from svn r5969]
2005-06-17 18:54:58 +00:00
98c90052c9 Patch from James Harvey to rearrange the Same Game colours.
[originally from svn r5938]
2005-06-10 11:27:26 +00:00
0747ab856b Remove debug output.
[originally from svn r5926]
2005-06-08 09:20:35 +00:00
c7c3058b8b Add Windows help topic
[originally from svn r5923]
2005-06-07 21:05:29 +00:00
c27235cc51 James Harvey's patch to support keyboard control in Same Game.
[originally from svn r5919]
2005-06-07 20:22:25 +00:00
0bcdb7aa03 James Harvey has contributed an implementation of `Same Game', also
known as ksame (KDE) and Same GNOME (GNOME).

[originally from svn r5914]
2005-06-07 19:01:36 +00:00