diff options
| author | Simon Tatham <anakin@pobox.com> | 2005-07-28 17:12:18 +0000 |
|---|---|---|
| committer | Simon Tatham <anakin@pobox.com> | 2005-07-28 17:12:18 +0000 |
| commit | f44e4acd4a4216700ef8094cc4ae7251c6f4cdc6 (patch) | |
| tree | 9197be9cb79d693e14ff613a25607663ef44c3c1 /HACKING.but | |
| parent | cc06b70328faf5a9c9806bd1108636f98846cd3b (diff) | |
| download | puzzles-f44e4acd4a4216700ef8094cc4ae7251c6f4cdc6.zip puzzles-f44e4acd4a4216700ef8094cc4ae7251c6f4cdc6.tar.gz puzzles-f44e4acd4a4216700ef8094cc4ae7251c6f4cdc6.tar.bz2 puzzles-f44e4acd4a4216700ef8094cc4ae7251c6f4cdc6.tar.xz | |
Shiny new developer documentation to replace the old sketchy HACKING
guide.
[originally from svn r6142]
Diffstat (limited to 'HACKING.but')
| -rw-r--r-- | HACKING.but | 182 |
1 files changed, 0 insertions, 182 deletions
diff --git a/HACKING.but b/HACKING.but deleted file mode 100644 index 6bf9785..0000000 --- a/HACKING.but +++ /dev/null @@ -1,182 +0,0 @@ -\cfg{text-indent}{0} -\cfg{text-width}{72} -\cfg{text-title-align}{left} -\cfg{text-chapter-align}{left} -\cfg{text-chapter-numeric}{true} -\cfg{text-chapter-suffix}{. } -\cfg{text-chapter-underline}{-} -\cfg{text-section-align}{0}{left} -\cfg{text-section-numeric}{0}{true} -\cfg{text-section-suffix}{0}{. } -\cfg{text-section-underline}{0}{-} -\cfg{text-section-align}{1}{left} -\cfg{text-section-numeric}{1}{true} -\cfg{text-section-suffix}{1}{. } -\cfg{text-section-underline}{1}{-} -\cfg{text-versionid}{0} - -\title Hacking guide for Simon Tatham's puzzle collection - -\C{newpuz} Guide to writing a new puzzle - -Start by copying \cw{nullgame.c}. This contains all the function -definitions and stubs that should be necessary to at least compile. -Some things are fine as they are unless you do something that -requires a change (for example, \cw{dup_params()} can usually be -left as it is since game parameters often don't have any -variable-size elements that need to be dynamically allocated); other -things are sure to need changing (for example, the params structure -is likely to need to contain at least one actual variable). Anything -marked \q{FIXME} really needs changing before you have a working -game. - -\e{DO NOT EDIT THE MAKEFILES.} Edit \c{Recipe} instead, and then -re-run \cw{mkfiles.pl}. The individual makefiles are automatically -generated by this mechanism, so editing them directly will not -produce a usable patch. - -\H{newpuz-arch} General architecture tips - -Think carefully about which data structures need to contain which -parts of the game information. - -\b \c{game_state} should contain everything that holds the current -state of play in a specific game. The mid-end maintains one of these -for every move the player has made, and moves back and forwards -along the list when you use Undo and Redo. So anything you would -expect to have restored when you undo needs to go in this state. - -\b \c{game_params} should contain parameters the user can set before -generating a new game. For example, if the game is played on a grid -of variable size, \cw{game_params} contains the grid size. -(\cw{game_state} will \e{also} need to contain the grid size. You -might even wish to have \cw{game_state} contain a \cw{game_params} -member.) - -\b \c{game_ui} contains aspects of the game's user interface which -are not expected to be restored in an undo operation. For example, -if you have a basically mouse-clicky sort of game (such as Net) but -you want to provide a cursor which can be moved with the arrow keys, -then putting the location of the cursor in \c{game_ui} is -reasonable. Or if the game allows you to drag things around the -display, then the current state of dragging is something that can go -in \c{game_ui}. Simple games don't need a \cw{game_ui} structure at -all. - -\b \c{game_drawstate} contains things you know about the current -state of the game's display. For example, if your display is made up -of tiles and you want to redraw as few as possible, you might want -to have \c{game_drawstate} contain a description of the last tile -you drew at every position, so that you can compare it to the new -tile and avoid redrawing tiles that haven't changed. - -\H{newpuz-params} Notes on parameters - -You need to define a textual format for the game parameters (the part -before the \q{:} or \q{#} in descriptive and random IDs respectively). - -The per-game parameter encoding function \cw{encode_params()} is -passed an argument \c{full}. This serves two purposes: - -\b You can suppress inclusion of parameters that only affect game -generation, and thus would have no effect in a descriptive ID, in the -ID displayed by \q{Game -> Specific} if \c{full} is \cw{FALSE}. - -\b You can ensure that a particular parameter entered as part of a -game ID does not persist when a new puzzle is generated, for instance -if you think that a player would not want it to persist beyond a -single game. An example is the \q{expansion factor} in Rectangles. - -When generating a new puzzle instance, give some thought to the order -in which parameters are processed. For example, the order of grid -generation in Net is: - -\b First the game sets up a valid completed Net grid. - -\b Then it makes a list of every edge with no connection across it. -These edges are eligible to become barriers. - -\b Then the grid is shuffled by randomly rotating every tile. - -\b Then the game multiplies the number of barrier-candidate edges by -the barrier probability in order to decide how many barriers to -create. - -\b Finally, it picks that many edges out of the barrier candidate -list, removing each edge from the list as it selects it. - -The effect of this is that the actual barrier locations are chosen -\e{last}, which means that if you change the barrier rate and then -enter the same random number seed, \e{only} the barriers change. -Furthermore, if you do this, the barrier sets will be nested (i.e. -the version with more barriers will contain every barrier from the -one with fewer), so that selecting 10 barriers and then 20 barriers -will not give a user 30 pieces of information, only 20. - -\H{newpuz-descid} Notes on descriptive IDs - -The descriptive game ID is the part that comes after the colon in the -ID accessed through \q{Game -> Specific}. It does not need to be -especially concise, but it should be designed to remain compatible -with new versions of the puzzle. - -Try to imagine all the things a user might want to use the descriptive -ID for, and build as much capability into it as possible. At a minimum, -you need to be able to generate one of these given a random number -source; however, if auto-generation capability is limited, give some -thought to the possibility of a user making up their own descriptive -IDs. This property is particularly useful if the puzzle is an -implementation of a well-known game, in which case existing instances -of the puzzle might be available which a user might want to transcribe -into game seeds in order to play them conveniently. - -\H{newpuz-redraw} Designing a drawing routine - -Front end implementations are required to remember all data drawn by -the game. That is, a game redraw routine MUST never be called simply -because part of the game window was briefly obscured; the front end -is required to remember what the game last drew in that area of the -window, and redraw it itself without bothering the game module. - -Many games will need some form of animation when transferring -between one \cw{game_state} and the next. This is achieved by having -\cw{game_anim_length()} analyse two adjacent game states, decide how -long the linking animation between them should last, and return this -duration in seconds. Then \cw{game_redraw()} will be passed the two -game states plus an indication of how far through the animation it -is, and can do its drawing appropriately. - -\e{Be aware that you will be required to animate on undo}. If you -are at game state A and the user makes a move creating game state B, -then your redraw function will be passed both states A and B, in -that order, and will be expected to animate between them if your -game needs animation. However, if the user then hits Undo, your -redraw function will be passed states B and A, in \e{that} order, -and will be expected to perform the reverse animation. - -This is easy enough for some games. In Fifteen, for example, it's -simply a matter of examining the two game states to work out what -has changed between them, and drawing each tile some proportion of -the way between its starting and finishing positions. - -In Sixteen, things are more difficult. You could examine the grid to -work out which tiles had been moved and decide which way they had -been moved, but this would be disconcerting to the user in some -cases. In a 2xN game of Sixteen, rotating a two-tile row left or -right has the same end result but should look different during the -enimation; so the Sixteen \cw{game_state} in fact stores an extra -piece of information giving the direction of the last move. So when -making a normal move, \cw{game_redraw()} can know which way round it -is expected to animate a two-tile rotation. - -However, even this doesn't fix the undo case. When -\cw{game_redraw()} is passed a pair of game states in the right -chronological order, the second one contains the direction field -which corresponds to the actual difference between the states. -However, when it is passed a pair of states in the opposite order -due to an undo, it should be looking in the \e{first} one to find -the direction field. - -For this reason, in the redraw functions you are provided with an -extra argument \c{dir} which tells you which state was chronologically -first; \c{dir} is +1 for a normal move and -1 for an undo. |