Previous | Contents | Next
The Puzzles code base is divided into four parts: a set of interchangeable front ends, a set of interchangeable back ends, a universal ‘middle end’ which acts as a buffer between the two, and a bunch of miscellaneous utility functions. In the following sections I give some general discussion of each of these parts.
The front end is the non-portable part of the code: it's the bit that you replace completely when you port to a different platform. So it's responsible for all system calls, all GUI interaction, and anything else platform-specific.
The current front ends in the main code base are for Windows, GTK and MacOS X; I also know of a third-party front end for PalmOS.
The front end contains
main() or the local platform's equivalent. Top-level control over the application's execution flow belongs to the front end (it isn't, for example, a set of functions called by a universal
main() somewhere else).
The front end has complete freedom to design the GUI for any given port of Puzzles. There is no centralised mechanism for maintaining the menu layout, for example. This has a cost in consistency (when I do want the same menu layout on more than one platform, I have to edit two pieces of code in parallel every time I make a change), but the advantage is that local GUI conventions can be conformed to and local constraints adapted to. For example, MacOS X has strict human interface guidelines which specify a different menu layout from the one I've used on Windows and GTK; there's nothing stopping the OS X front end from providing a menu layout consistent with those guidelines.
Although the front end is mostly caller rather than the callee in its interactions with other parts of the code, it is required to implement a small API for other modules to call, mostly of drawing functions for games to use when drawing their graphics. The drawing API is documented in chapter 3; the other miscellaneous front end API functions are documented in section 4.34.
A ‘back end’, in this collection, is synonymous with a ‘puzzle’. Each back end implements a different game.
At the top level, a back end is simply a data structure, containing a few constants (flag words, preferred pixel size) and a large number of function pointers. Back ends are almost invariably callee rather than caller, which means there's a limitation on what a back end can do on its own initiative.
The persistent state in a back end is divided into a number of data structures, which are used for different purposes and therefore likely to be switched around, changed without notice, and otherwise updated by the rest of the code. It is important when designing a back end to put the right pieces of data into the right structures, or standard midend-provided features (such as Undo) may fail to work.
The functions and variables provided in the back end data structure are documented in chapter 2.
Puzzles has a single and universal ‘middle end’. This code is common to all platforms and all games; it sits in between the front end and the back end and provides standard functionality everywhere.
People adding new back ends or new front ends should generally not need to edit the middle end. On rare occasions there might be a change that can be made to the middle end to permit a new game to do something not currently anticipated by the middle end's present design; however, this is terribly easy to get wrong and should probably not be undertaken without consulting the primary maintainer (me). Patch submissions containing unannounced mid-end changes will be treated on their merits like any other patch; this is just a friendly warning that mid-end changes will need quite a lot of merits to make them acceptable.
Functionality provided by the mid-end includes:
Thus, there's a lot of work done once by the mid-end so that individual back ends don't have to worry about it. All the back end has to do is cooperate in ensuring the mid-end can do its work properly.
The API of functions provided by the mid-end to be called by the front end is documented in chapter 4.
In addition to these three major structural components, the Puzzles code also contains a variety of utility modules usable by all of the above components. There is a set of functions to provide platform-independent random number generation; functions to make memory allocation easier; functions which implement a balanced tree structure to be used as necessary in complex algorithms; and a few other miscellaneous functions. All of these are documented in chapter 5.
There are a number of function call interfaces within Puzzles, and this guide will discuss each one in a chapter of its own. After that, chapter 6 discusses how to design new games, with some general design thoughts and tips.