Check out Symmetric Chess, our featured variant for March, 2024.

A Wizard for GAME-Code Generation

Using the Play-Test Applet to automate Game-Courier presets

When your CV doesn't have extremely exotic rules, making a Game Courier preset enforce the rules and indicate legal moves can be done very easily, using the Play-Test Applet for Chess Variants. This Applet can generate GAME code that would test the entered moves for legality, highlights the moves a piece that you select with the mouse can make, and tests for conditions that should end the game, such as checkmate, stalemate, repetitions or the 50-move rule. This works as follows:

Type the board dimensions and number of ranks of the promotion zone in the text entries above the board diagram. If promotion is not to every non-royal piece, (which is the Applets' default), click that you want to 'specify more rules', and type the (single-letter) IDs of the piece types that should be elegible for promotion in the 'promotion choice' text entry. Click on 'Help' to see what you have to do if not every piece can be chosen in the entire promotion zone at all times. If your variant requires shuffling to randomize the initial position, you can simililarly type the IDs of the pieces that need to be shuffled in the other text entry. (There also is a 'Help' there, which explains how you could specify complex shuffling rules.) The 'more rules' also shows a few checkboxes, which you can tick to indicate the stalemate result, what will happen in the case of multiple Kings, etc. Of most interest is probably the 'Asymmetric setup' checkbox; tick this if the black pieces should not be automatically arranged as the mirror image of the white setup. (This is especially important in shuffle games, where it determines if white and black will be shuffled independently.) After you typed and ticked everything, hit the 'Apply' button to enforce it. The board diagram should then take on the requested dimensions.

The next step is to set up the initial position. Actually, if your only interest is to get GAME code for a preset, (and not a working Interactive Diagram, or a valid FEN code), you only have to place one copy of each participating piece, and it doesn't matter where. To do that, click the pieces you want to place on the board in the table, and then click the squares you want to put them on. If you did not ask for asymmetry, each piece you place will be automatically accompanied by its color-flipped mirror image on the other side. If you misplace a piece, you can move it to another location on the board. You can even capture pieces that you placed by mistake, and want to get rid of, but only through legal moves. After all pieces are placed, you hit the 'Start position' button to let the computer remember it.

When the CV has piece types that are only available from promotion, you would have to place these on the board too, to let the Applet know they participate. You can do that after you pressed 'Start position'. Then they will not spoil the FEN that will be printed when you generate the GAME code, which will be of the start position.

Many piece in the table have predefined moves and names. These might not always be what you need. You can change the name, move and ID of a piece in the table (also after you placed it on the board), by typing the desired values in the text entries under the table, and then clicking on the table cell that holds the move of the piece you want to alter. Data for which you did not enter a new value will remain unchanged. Always use single-letter capitals for the ID that correspond to the piece labels of the preset.

The non-obvious thing here might be to describe the move. You can see what move the piece currently has by clicking on its name in the table; its move diagram will then be temporarily shown on the board. If this is not the move you want, but you want a relatively simple other move (any combination of slides, leaps, hops), you can use the 'move-definition aid' below the board to create the description. By clicking squares you want a piece to be able to move to in the move pane, and then pressing the buttons to the right of it, you can build a description of the move in the 'Betza move description' text entry. And when that is complete, assign it to the piece of choice.

Pay special attention to the King; the default move for this will include a castling, which is automatically adapted (w.r.t. the number of steps taken by the King) to the board width you specified. You might want other, or no castling. In that case you would have to change the isO2 part of the preconfigured move. The number in that represented the number of King steps. If the variant allows several different castling destinations you have to write each of those, e.g. isO2isO3isO4. If castling is not with the piece at the board edge, but with the piece one square closer, add an extra j, e.g. isjO2.

After you corrected and verified all the moves, hit the 'GAME code' button at the bottom of the Applet article. This will make the GAME code that you need to automate a preset for the variant appear in the textbox below it. It will consist of five parts, intended for copy-pasting into the various GAME-code sections of the preset. If you set up the correct initial position, you can also use the FEN code it prints at the bottom to create an entirely new preset.

Invoke the preset, hit the 'Menu' button, and then 'Edit'. Tick the checkbox "Do Not Include Moves in Code" just above the code boxes. THIS IS ESSENTIAL! If you forget it, every move will be rejected as illegal, because the piece you are moving will already be moved away when the code generated by the Applet tries to test the move for legality. Copy the GAME code shown by the Applet into the corresponding GAME-code text boxes of the preset. The Pre-Move sections can remain empty. Then press the 'Save' button at the top of the preset's edit page. In most cases that would complete what you have to do to automate your preset. Some exceptional cases where you have to make some changes or additions to the automatically generated GAME code are discussed below.

Multiple royal or promoting types

The Applet will always assume the piece with the King image is the only royal type. If the variant has several piece types that are royal, you would have to make the GAME code for the preset aware of that. Similarly, the Applet assumes only the first piece type you define can promote. You can configure the GAME code to make several types promote, provided that these all promote in the same way. This would require altering or adding the following lines in the Pre-Game section, adapting the list of pieces they contain. For a game without royal pieces the list with the parentheses has to be replaced by the word array.

set wroyal (K);
set broyal (k);
set promotables (P p);

Customizing check and draw rules

You can for instance disable the check rule (so that Kings can happily wander into check without the preset complaining), by adding the line

set checkrule 0;

at the bottom of the Pre-Game code. If you want to deviate from the orthoChess 50-move or 3-fold-repeat rule, you can do that by adding one or more of the lines below (but with the value altered to your liking):

set repeats 3;           // repetitions to claim game end
set reploses 0;          // repeater loses
set rulemoves 100;       // reversible plies to claim draw
set resetpieces (P p);   // pieces that reset the counter when they move
set nullban 1;           // forbids moves that do not change the board

If you don't want to enforce one of these rules, just specify a ridiculously large number for it. Setting 'reploses' to 1 makes a 3-fold repetition a loss for the player bringing it about. The 'resetpieces' are those whose moves should reset the 50-move counter. By default these are only Pawns, but you can add other pieces IDs between the parentheses. Never forget to mention the pieces for each player (capital and lower case)! If no piece should reset the counter, add the line

set resetpieces array;

Moves with side effects

If your variant involves moves with side effects, such as locust capture, there are two ways to have the preset handle their entering with the mouse. The default manner would be to enter them as two moves, the first to make the capture in a normal way (i.e. by moving to the square that contains the victim), and then move from there to the intended destination. If the normal capture is also legal, and you want to play that, you can indicate this by pressing the Pass button for the second move. The alternative method is used by pieces that you defined as 'shooters', through a line like

set shooters (L l);

where all the shooters are mentioned between parentheses. These pieces then always have to be moved directly to their final destination. When that can cause a side effect on another square, you will be prompted to enter that. You then have to make a 'fake' move of the piece to the square it should affect. The preset will re-interpret that move as a removal of the piece on, or dropping of a piece on the target square, without actually moving the piece you selected for that second move there. This would be a more natural way for entering moves that capture pieces that are not in your path, or for re- positioning something you captured.

Anti-trading rules

It is also possible to activate enforcement of a variety of anti-trading rules, (which hardly any chess variant would need), through any of the lines

set iron (...);          // permanently uncapturable piece types
set counterstrike (...); // uncapturable after opponent's was captured
set protected (...);     // pieces that cannot be traded when protected
set negligible (...);    // side catch of these does not break trade ban

where the ... is the (space-separated) list of IDs of the pieces that you want the rule to be applied to. (Again, always mention both colors!) The 'iron' pieces can never be captured. 'Counterstrike' pieces become uncapturable for one turn, when a piece within the set is captured by a piece outside the set. The pieces listed as 'protected' cannot be captured by other pieces in the same group when recapture is possible; it is like their capturer becomes an absolute royal for one turn. This only counts for normal captures, not when the capture was a side effect. In fact, when something else was captured in addition to the protected piece, as a side effect, the rule does not apply. Unless that extra piece that was captured occurs in the 'negligible' list.

Custom pieces

The interactive diagram supports a lot of different moves, but has its limitations. GAME code, on the other hand, is a Turing-complete programming language, that could describe anything. To not lose that possibility without sacrificing the convenience of using the Applet-generated code, the latter allows you to still provide your own hand-written GAME code for handling a piece. This section explains how to do that. But it would only be understandable for people that know how to program in GAME code.

The first step is to make sure the Applet would reserve some space for your custom piece in the legdefs table. It is best to reserve one line for each direction the piece can start in. To that end you can define the piece with a fake move that has the desired number of directions in the Applet. E.g. a piece with 12 move directions could be given the move NF. The Applet will then reserve 12 lines of 5 numbers for that piece in legdefs. If the piece is not symmetric, you would want to have a separate white and black instance of it, and you can do that by specifying an asymmetric move, like KfhN.

0
1 99  0  1     3 // queen(59)
1 99  1  1     3
1 99  1  0     3
1 99  1 -1     3
1 99  0 -1     3
1 99 -1 -1     3
1 99 -1  0     3
1 99 -1  1     3
0

Next step is to modify the piece its description in legdefs so it will invoke your own code. Above you see a section of a legdefs table describing the moves of an orthodox Queen, and the piece you defined would have something similar. You replace the second number on the line of a move (which normally stands for the range of the move) by the number -3. And you replace the last (5th) number on the line with the name of the GAME-code subroutine that should be called to handle the move. Whenever the Applet-generated code tries to generate that move for the piece, it would call the given subroutine with three arguments: the square the piece is on, and the 3rd and 4th number of the line (which normally represent the leap in x-y form). Your routine could use these numbers for any purpose, and you can change them in the table accordingly; they will not be used for any other purpose than passing to your subroutine. It is suggested, though, that you use them to distinguish the various moves from each other, and have the subroutine you provide not generate all moves for the piece, but just the one move specified by these numbers.

Note that lines in legdefs for which you do not change the range into -3 keep there original meaning. There is nothing against having some of the moves of the piece be generated by your custom routine, but leave the geenration of others to the Applet-generated code. Then you only have to focus on the movesthat were too outlandish for the Applet.

The final step is to provide the subroutine to generate the moves. The code below gives an example for how such a subroutine could look; in this case it would generate a leap over an adjacent friendly Pawn.

sub MyPiece startsqr dx dy:
my destsqr jumpsqr piece;
set destsqr where * 2 #dx * 2 #dy;        // destination of a leap twice the given side
verify onboard #destsqr;                  // make sure it doesn't leave the board
set jumpsqr where #dx #dy;                // leap once the size (automatically on board)
set piece space #jumpsqr;                 // piece that is there
verify samecase #piece space #startsqr;   // must be friend to piece on startsqr
gosub GotMove #startsqr #destsqr 0 0 0 0; // process the move
endsub;

When you would have changed the section of the legdefs table shown above to this:

0
1 99  0  1     3 // queen(59)
1 -3  1  1 MyPiece
1 99  1  0     3
1 -3  1 -1 MyPiece
1 99  0 -1     3
1 -3 -1 -1 MyPiece
1 99 -1  0     3
1 -3 -1  1 MyPiece
0
your 'Queen' would now move as a Rook that would also be able to jump diagonally (as an Alfil) over friendly Pawns. If you wonder what all the zeroes are that are passed to GotMove: these are (respectively) a locust square, a drop square, what is dropped on the latter, and something that you should always leave at 0. If you would have replaced the first 0 by #jumpsqr, the move would have captured the Pawn it jumped over, like in Checkers. Except that it would be your own Pawn, so that would make the move practically useless. OTOH, if you would replace the second 0 by #jumpsqr, and the third by N, jumping over a Pawn would replace it by a Knight. (Always a white Knight, sadly, so if you wanted to use this as a description for the pieces of both colors, you would have to take care to use tolower or toupper to cook the right piece to drop.)

There is one problem with the presented code, though: the legality test for highlighting moves used by the Applet-generated code would not see those moves, and would highlight the square they attack as a possible destination for an enemy King. And when you would already be in check with the move, it would not realize that capturing the Pawn would be a valid evasion, and should be highlighted. The legality test could be made aware of that by adding some extra code, but this is alas not as simple as one could have wished. The code below gives the perfected version:

sub MyPiece startsqr dx dy:
my destsqr jumpsqr piece;
set destsqr where * 2 #dx * 2 #dy;        // destination of a leap twice the given side
verify onboard #destsqr;                  // make sure it doesn't leave the board
set jumpsqr where #dx #dy;                // leap once the size (automatically on board)
set piece space #jumpsqr;                 // piece that is there
verify samecase #piece space #startsqr;   // must be friend to piece on startsqr
if == 9 #task:
setelem #destsqr 0 1;                   // mark destination as attacked
endif;
gosub GotMove #startsqr #destsqr 0 0 0 0; // process the move
endsub;

Task equal to 9 is the code's 'augmented check test', where the moves are not just generated to see if they actually capture a King, but also mark squares where a King could be potentially captured. This cannot be left to GotMove, which is only called for moves that are pseudo-legal. But it can happen that a move that can only capture ends on a square that is empty, e.g. a diagonal Pawn move. Or a non-divergent move that ends on a friendly piece. Those would not be pseudo-legal, so it would not lead to calling GotMove, but we still should mark the destination as being inacessible to the opponent King.

There is yet another thing the augmented check test must do, namely indicating 'potential pins'. These are riding / sliding moves that are blocked by a piece before they exhausted their maximum range. Moving away that piece then would create attacks on the downstream part of the ride, and it would have to be tested whether this exposes your King. Such moves on a stack for the square of the blocker, so that the legality testing can see what moves should be tried to ascertain the moved piece was not pinned. The example above did not involve slides, and thus did not need it. But suppose we change the move to a ride that can only be made by first jumping over an adjacent Pawn, like a Contra-Grasshopper:

sub MyPiece startsqr dx dy:
my destsqr jumpsqr piece tosqrs k;
set jumpsqr where #dx #dy;                  // leap once the size (automatically on board)
set piece space #jumpsqr;                   // piece that is there
verify samecase #piece space #startsqr;     // must be friend to piece on startsqr
set tosqrs ride #jumpsqr #dx #dy;           // array of squares of the ride
set k 0;
do while 
< #k count #tosqrs:                // loop through the ride
set destsqr elem #k #tosqrs;              // next square
if == 9 #task:
setelem #destsqr 0 1;                   // mark destination as attacked
if not empty #destsqr:                  // potentially pinned piece
push #destsqr #ss;                    // remember the move as potentially pinning this piece
push #destsqr #mv;
endif;
endif;
verify not samecase #piece space #destsqr or empty #destsq; // must hold enemy or be empty
gosub GotMove #startsqr #destsqr 0 0 0 0; // process the move
inc k;
loop;
endsub;

The code inserted for the augmented check test now pushes ss and mv, which indicate the square from which the move started and the location of the move in legdefs, onto the stack for destsqr when the latter is occupied. This then enables the legality test to reject moves with the occupant when there happened to be a King behind it. You only have to do that for moves that can capture (a King). If your are defining hopper moves, you would likewise have to push ss and mv on the stack of the empty squares the pre-hop leg of the move passes through, because occupying such squares would alter the hopping move, and thus potentially activate a hopper attack on the King.



This 'user submitted' page is a collaboration between the posting user and the Chess Variant Pages. Registered contributors to the Chess Variant Pages have the ability to post their own works, subject to review and editing by the Chess Variant Pages Editorial Staff.


By H. G. Muller.

Last revised by H. G. Muller.


Web page created: 2020-08-16. Web page last updated: 2020-08-16

Revisions of MSgame-code-generation