The Chess Variant Pages
Custom Search



Game Courier Developer's Guide

Game Courier is a versatile web-based system for playing Chess variants on-line. It can automatically generate the boards used for most variants, and it can handle the rest by using predrawn graphic files. It can automate complex moves, and it can be programmed to enforce the rules of games. It is an open-ended system that can be made to support almost any Chess variant, but it still takes human effort to design and program the presets it uses for the games it supports. This guide describes how to design and program games for Game Courier. If all you want to do is play games that have already been made available for Game Courier, you don't need to know anything in this guide. But if you want to do anything from customizing an existing preset to designing and programming new presets from scratch, this guide tells you how.

The material in this guide is presented roughly in order of difficulty. It begins with information useful for casual users who just wish to change the appearance of a preset, and it ends with information for power users who wish to design and program their own presets. Most users won't need to go beyond the material in the first section. Also, you may want to gradually go through the sections, taking time to master each one before moving on.

Definitions

Let's start by introducing some of the basic terminology surrounding Game Courier. This will help you better understand this guide when I start explaining how to do things.

Preset
A modification to Game Courier's default values, provided through a form or a query string.
Settings File
A file on the website that specifies details for a particular game by changing what count as default values.
Customization
A preset that changes the appearance of a game that has already been defined in a settings file.

Preset

By default, Game Courier simulates a Chess board, allowing two people to play Chess (or any game using the same equipment) without any rule enforcement, using a piece set of my own design. Go to play.php to see what this looks like.

To play other games with Game Courier, or to change the appearance of the board it displays, all you have to do is change some of its default values. This is done by passing form data to the script that provides new values for some of the variables Game Courier uses to construct a board. This can be done in one of two ways.

Here is an example of using a form to pass new values to some of Game Courier's variables. This will change the name of the game, expand the board to ten columns, and change the setup and piece set.

HTMLTry It
<FORM ACTION="http://play.chessvariants.com/pbm/play.php">
<INPUT TYPE="submit" NAME="game" VALUE="Univers Chess">
<INPUT TYPE="hidden" NAME="cols" VALUE=10>
<INPUT TYPE="hidden" NAME="code" VALUE="rbnmqkanbr/pppppppppp/****/PPPPPPPPPP/RBNMQKANBR">
<INPUT TYPE="hidden" NAME="set" VALUE="magnetic">
</FORM>

If you look at the URL for the page, it looks like this:

http://play.chessvariants.com/pbm/play.php?game=Univers+Chess&cols=10&code=rbnmqkanbr%2Fpppppppppp%2F****%2FPPPPPPPPPP%2FRBNMQKANBR&set=magnetic

This shows how form data can be passed through a query string in an URL.

The passing of form data to Game Courier to change some of its default values is called a preset. You have just seen two ways of posting a preset to a webpage. You may write it as a form, or you may write it as an URL with a query string. The form method is most appropriate when you change many values or want to provide options. To avoid a long query string when using a form, you may add the METHOD=POST attribute to the form, like so:

HTMLTry It

Settings File

Another way to change the default values is to change what the defaults are. Instead of changing the variables directly, a settings file changes the values of the $default array, which Game Courier uses to store default values in. Using the same example of Univers Chess, here is what the same changes to the defaults look like as a settings file:

<?php
$author 'fergus';
$default['code'] = <<<'NOW'
rbnmqkanbr/pppppppppp/****/PPPPPPPPPP/RBNMQKANBR
NOW;
$default['cols'] = <<<'NOW'
10
NOW;
$default['game'] = <<<'NOW'
Univers Chess
NOW;
$default['set'] = <<<'NOW'
magnetic
NOW;
?>

As you may notice, this is a series of variable assignments in nowdoc format. This format allows quotation marks to appear in a string without being escaped. Many older settings files use the heredoc format, which might be less secure but hasn't proven to be a problem. You should notice that $author is the only variable that is set aside from elements of $default. This is because there is no default value for $author, and this value is mainly used to keep other people from overwriting a settings file. A settings file is stored on the website, and putting changes to the default values into a settings file allows us to write much shorter presets, using only the name of the game and the name of the settings file as the parameters of the query string or form. For example, this settings file is saved under the name of sample, and it can be accessed with the following query string:

http://play.chessvariants.com/pbm/play.php?game=Univers+Chess&settings=sample

Now a lot more can be done with a settings file than just the few things I have changed in this example. The following link uses the official settings file for this game, and it includes more.

http://play.chessvariants.com/pbm/play.php?game=Univers+Chess&settings=default

To show you what this larger settings file looks like, you can view a syntax highlighted copy of its PHP code with the showsource.php script. Give it the name of a game and of a settings file, and it will display the contents of the settings file for you.

http://play.chessvariants.com/pbmsettings/showsource.php?game=Univers+Chess&settings=default

Customization

A customization is a preset that includes modifications to the default values defined in a settings file. For example:

http://play.chessvariants.com/pbm/play.php?game=Univers+Chess&settings=default&set=alfaerie

In this example, I have specified a particular settings file. This settings file uses the magnetic set by default, but I have added the assignment "set=alfaerie". So, this preset will now display pieces with the alfaerie set.

The purpose behind using customizations is to save you work and keep things more organized. The alternative to customizing a settings file is to clone a settings file and modify it to appear different. This is a very bad idea, because a clone does not inherit future changes to the original settings file, and if the original needs to be changed, the clone could get out of date. By making one settings file and providing customizations of it, all the customizations inherit changes to the original settings file, and all you have to edit if you fix anything is that one file.

Moreover, if all you want to do is change the appearance of a game someone else has provided a settings file for, it can be an even worse idea to clone and modify it, since the author of the original file would not even be able to update your clone. But if you just make a customization, it will inherit any changes the original author makes to the original settings file.

Look at the page for the programmed version of Chess for an example of several customizations of the same settings file. If you look at the source code for that page, you will see that they all use a settings file called default, but each one (except the first) changes some parameters. You will also notice several buttons under each. Putting one of the changeable parameters in a submit button allows the same form to offer different options.

Customizing a Settings File

There is no distinction between customizing a preset and editing one, since the only way to modify a preset is to make a new preset. This is because presets are not named and saved, and the only way to change one is to change its values. But settings files are named and saved, and this allows you to use the same settings file with different presets. With this in mind, Game Courier makes it easy for you to make customizations of a particular settings file with its Customize mode. To use it, go to the main menu for a particular game with a settings file, such as the Univers Chess example given above, and click on its button. This is will bring you to a form that lets you change parameters that affect the game's appearance. These same parameters can be edited in Edit mode, and they are described there under the heading of Appearance. Although you could use Edit mode to modify clones of settings files, there are three reasons for using the Customize mode instead:

  1. A customized preset will inherit any future bug fixes and improvements made to the original settings file, but a cloned preset will not. This is the most important reason of all. If you didn't program the original preset, you don't want to create one you won't be able to maintain. If you did program the original preset, it will be easier to maintain if you create only one and provide additional graphic options by customizing it.
  2. Customize mode protects you from making mistakes by not allowing you to change anything you shouldn't.
  3. Fewer options makes it less confusing for the average user.

Editing a Game

To edit a game, you need to change the default values Game Courier uses to represent a game. You should already know that you can change these with a query string or with a form. But you don't have to hand write your own query strings and forms to get Game Courier to play other games. Game Courier has an Edit mode that allows you to change default values and to routinely see the results of your changes. For any particular game, you can reach Edit mode by clicking on the button in its main menu. If you haven't done so already, go to one of the settings files linked above, and click on this button. This mode provides you with a form that is divided into five main sections:

Identification
The section where you identify the game, the settings file, and yourself.
Structure
The place for defining the coordinate system and the initial placement of pieces.
Appearance
Settings that affect the appearance of the game. These should be mostly user-configurable and have no bearing on gameplay.
Written Rules
A brief statement of the rules as a reference for players.
Code
Code in the GAME Code language for automating aspects of moves (such as castling or en passant) or for enforcing rules.

Identification

In this section, you identify the game, the settings file, and yourself. Here are detailed descriptions of each field.

Game

This field specifies the name of the game the preset is for. This name will be displayed at various places in Game Courier. It will also be translated into a game ID that will be used for locating logs, settings files, and minirules files. The game ID is made by converting all capitals to lowercase, by converting all high ASCII (8-bit) characters into the closest equivalent low ASCII (7-bit) characters, and all spaces into underscores. The name you use here should use proper capitalization, and it should separate words with spaces. This is not the place for giving your preset a distinctive name. Nothing but the game's name should go here.

Rules URL

This field specifies a webpage where a user may go to read the rules of the game. This will usually be to one of the webpages of our main website, the Chess Variant Pages. Any of these pages may be entered without including the domain. Start the name with the slash that follows the domain name. For example, the default value is "/d.chess/chess.html", which refers to http://www.chessvariants.com/d.chess/chess.html. Note that this beginning slash is important. Without it, it would be interpreted as a relative URL pointing to http://play.chessvariants.com/pbm/d.chess/chess.html, but there is no webpage there. Yet if you want to refer to a page in the play.chessvariants.com subdomain, then this is the thing to do. Just enter the URL relative to the http://play.chessvariants.com/pbm/ directory. For example,"../erf/MiniChss.html" would point to the page at http://play.chessvariants.com/erf/MiniChss.html. If the webpage is offsite, then you must enter the full URL, including the http:// part at the beginning.

Settings

This field is for the basename of a settings file. The extension for the filename will be ".php", but this will be added automatically. This file will be found in a subdirectory whose name is based on the name of the game. Thus, it isn't important to include the game's name in the settings file name. Together, this basename and the game's name specify a specific settings file. When this file already exists, Game Courier will use the defaults listed in it for its default values. When you click on the "Save" button, you can create or overwrite this file. If you enter an unused value in this field without saving a settings value, it will have no effect.

This field is not required, because you can distribute a preset as an URL or a form, but it is recommended. If you do not enter a name for a settings file, games that use your preset will not inherit any fixes you make to it later. If you do any programming of games, it will be a very good idea to save your work to a settings file. This will allow games already using it to inherit fixes, and it will allow for the distribution of customizations that inherit the structure and code of the main version.

Redirect

When you have written a new settings file for a game that makes an old one obsolete, but games have been played with the old one that will not work with the new settings file, whether because you changed the setup or changed how notation works, the right way to handle this situation is to deprecate the old settings file. You can do this by redirecting any new invitations to the new settings file while leaving the old one around for viewing the games played with it. So, to deprecate an obsolete settings file, use this field to name the settings file to redirect new invitations to. Note that the name of the game must remain the same, since a particular settings file gets identified by the combination of its name and the game's name.

Userid

This field is for your userid. This needs to be filled in whenever you save a settings file. Each settings file stores the userid of its author so that only its original author may make any changes to it. You may not overwrite an existing settings file unless you are its original author, which you can confirm by entering your userid and password.

Password

This field is for your password. This field is required whenever you save a settings file. You can save a settings file only when you enter the correct password for your userid.

Structure

The single-most important part of defining a game is its structure. This includes its coordinate system, the initial placement of pieces, and how many players there are. Game Courier uses the coordinate system and the positions of pieces to mathematically model the game, so that it has knowledge of the playing area and the pieces. It needs to know how many players there are to know who to pass the next turn to. Currently, Game Courier supports only two-player games, but I hope to change that in time.

Game Courier keeps track of the board position with an array called $space. This is an associative array that keeps track of what the spaces are called and what is on each space. The key of each element is the coordinate of a particular space, and the value of each element is a label representing what is on the space. This label can be @ to represent an empty space, - to represent a deleted space, or a letter or longer string representing a particular piece.

Instead of asking you to enter the $space array directly, Game Courier calculates it from the values of some other fields. Here are the fields that define the structure of a game:

FEN Code

Game Courier had its genesis when I realized that I could use Forsythe-Edwards Notation to represent the positions of variants with different pieces and boards than Chess. Forsythe-Edwards notation is a method of representing the position on a Chess board with a compact string. The initial idea was to pass along URLs with modified FEN strings as moves were made in a game, and this would enable players to see the position on the computer screen. Nowadays, Game Courier stores moves in a log and freshly calculates each position from the moves made. But it still uses the FEN string to represent the initial position.

Game Courier represents the board with a variation of Forsythe-Edwards Notation that has been modified for use with variants. This notation was invented in 1883 by David Forsythe, chess editor of the Glasgow Weekly Herald, for the purpose of concisely recording positions in chess. It assumed the standard 8x8 board, and it consisted of letters, numbers, and slashes. As a whole, the notation described each position in a left-to-right, top-to-bottom order from White's perspective. This is the same direction that we read English in. Each letter represented a piece, each number a series of empty spaces, and each slash indicated the end of a rank. It used lowercase letters for Black and uppercase for White. Using this code, the opening position in Chess would look like this: "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR". Game Courier's version takes some inspiration from Hans Boedlander's Fairy Forsythe-Edwards Notation, but it is not the same.

Game Courier's extended version of Forsythe-Edwards Notation works with all types of boards, not just 8x8 square Chess boards. The coordinates of most boards are represented by ranks and files. These may not always be at right angles to each other, but that is irrelevant to the use of this notation to represent positions. No matter what labels are used for ranks and files, all ranks and files are represented internally by integer array indexes, beginning with zero. So, on a Chess board a1 is internally (0,0), and h8 is internally (7,7). Given this, the Forsythe code begins by describing the highest ranked position in file 0. This is the top left space on a rectangular board. This would be (0,7) or a8 on a Chess board. A little trial and error will tell you where it is on any unusually shaped board. It then continues to describe the board one rank at a time until it finishes with rank 0. It uses the Max Columns parameter to know how long a rank should be. This code may represent any number of spaces, and the number of ranks is a function of the number of spaces divided by the length of a rank. With the use of the minus sign, which represents non-space, it is possible to create non-rectangular boards by cutting out any unused spaces. A minus sign is used just like a piece label but has a different function. For the custom shape, which does not use ranks and files, the Forsythe code represents pieces in the order that the positions were listed. With a custom board, cutting out spaces isn't necessary, because you can omit a space simply by not creating it.

Game Courier's expanded FEN code also allows for pieces besides those in Chess. The 52 ASCII characters that represent the letters of the alphabet are reserved for identifying pieces. Lowercase letters are normally used for Black pieces, while uppercase letters are normally used for White pieces. Longer labels may be used by enclosing them in braces, like so: {NB}. When the board is rendered as an ASCII diagram, the labels themselves are used in the diagram. But for graphic boards, the labels are used to identify piece images stored on the website. Which images are used depends on the set that has been selected. Each set has a file that tells which image to use for each label. A variety of sets are offered, because there are different designs of the same pieces available, because there are more than 26 pieces used in Chess variants, because the same letter is sometimes appropriate for different pieces, and because many were made back when only individual letters could be used to represent pieces.

The remaining modifications to FEN code simply make it easier to read and write. The asterisk (*) fills the remainder of a rank with empty spaces. This is most useful for designating empty ranks. The slash (/) has become optional, and when it comes before the natural end of a rank, it fills the remainder of the rank with non-space. Note that the asterisk and the slash differ on more than what they fill the rest of the rank with. When an asterisk appears at the natural end of a rank, it starts a new rank, while the slash does not. Thus, "****" and "*/*/*/*/" are equivalent to each other, but "////" and "/*/*/*/*" are not equivalent to each other.

Here is a summary of the characters used in the FEN Code:

Any letter, typically [a-z] and [A-Z]
Each letter represents an individual Chess piece. Lowercase letters normally represent Black pieces, and uppercase letters normally represent White pieces.
Any base 10 number
A number represents a series of as many empty spaces.
The minus sign: -
A minus sign, or hyphen, represents a place in the board definition where there is no actual space. This could be a hole in the board or extra space around a non-rectangular board.
The slash: /
A slash represents the end of a rank. When it comes at the natural end of a rank, it serves mainly as a visual cue for someone reading the code. When it comes earlier, the rest of the rank gets padded with hyphens (representing non-existing spaces).
The asterisk: *
An asterisk fills the remainder of a rank with empty spaces.
The opening brace: {
Indicates the beginning of a label.
The closing brace: }
Indicates the end of a label.

With this in mind, here are some alternate ways of representing the opening position in Chess:

rnbqkbnrpppppppp32PPPPPPPPRNBQKBNR
This is the most compact way to represent it. The number 32 represents the four ranks between the Black and White Pawns.
rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR
This way is less compact but more legible. It visually divides the code into all eight ranks.
rnbqkbnr/pppppppp/****/PPPPPPPP/RNBQKBNR
In this one, each asterisk represent an entire rank of empty spaces.
rnbqkbnr/pppppppp/*/*/*/*/PPPPPPPP/RNBQKBNR
Some might prefer this one to the one above it, but I don't.

Columns

This specifies how many files wide the board will be. This value is used when parsing the FEN Code used for representing the board.

Files

This specifies what labels to use for the files. In this context, a file is a vertical column of spaces on a chess board. All labels must be separated by single spaces. A label may be a string of any length. The empty string is an acceptable label for a file that won't have any spaces in it. The first label will be used for the leftmost file from the first player's perspective, what is normally the a file in Chess. Labels will be assigned to files in left-to-right order. When this field is left unset, which is what you'll want to do for most games, the default behavior will be to start with a lowercase a and go through the alphabet to a lowercase z. All labels are case sensitive, and if you want any capital or numeric labels for files, or if your game requires more than 26 files, you will have to enter them in this field.

Besides regular labels, you may enter a null label by entering two spaces side by side. Since every space is parsed as a separator, two adjacent spaces will be understood to have a null string between them. A null label is used for a rank or file that is not actually used for actual spaces on the board. It is useful for separating areas of the board from each other. One special type of label is the invisible label. When you precede a label name with an exclamation point, !, some methods of rendering the board will refrain from displaying its label. An invisible label is used for spaces that will be used in the game without the players ever having to specify coordinates of those spaces. This can happen when moving pieces to and from certain spaces is handled only by automation or the * operator. For example, in Shogi, the file labels for the off-board areas have been made invisible. When a player does try to explicitly specify an invisible coordinate, the move will be treated as illegal.

The value of this field is used for every board shape except the Custom shape.

Ranks

This specifies what labels to use for ranks. All labels must be separated by single spaces. A label may be a string of any length. The empty string is an acceptable label for a rank that won't have any spaces in it. Null labels and invisible labels can both be used. These have already been described in the previous section on the Files parameter. The first label listed in this field will be used for the bottommost rank from the first player's perspective, what is normally the first rank in Chess. Labels will be assigned to ranks in bottom-to-top order. When this field is left unset, which is what you'll want to do for most games, the default behavior will be to use arabic decimal numerals, starting with 1 and counting up for each successive rank. All labels are case sensitive, and if you want any alphabetic labels for ranks, you will have to enter them in this field.

The value of this field is used for every board shape except the Custom shape.

Checker Pattern

Several rendering methods for particular shapes can automatically generate boards according to a specified pattern for checkering the board. It is this pattern that is stored in this field. The variable underlying this field is called $board, because it seemed like a good idea at the time, but it is more accurately described as a checker pattern.

I originally put this one under Appearance, but I decided to move it to Structure for two reasons. First, the value of this field does not need to be changed in a customization. Second, the color operator in the GAME Code language will return the color value of a space, and although this is not important information in most games, a game could be designed that uses the colors of spaces as important structural information about the game.

Here is how the Checker Pattern works. Each digit in this pattern represents one of the colors or patterns listed in the Colors or Patterns field. Patterns is used for ASCII diagrams, Colors for everything else. 0 is for the first color or pattern, 1 for the second, and so on up to 9. The pattern begins at the left end of the top rank, going across one rank at a time. It follows the same path as the FEN code, described earlier. The period marks the end of a rank. When it reaches a period before it reaches the end of the rank it is on, it repeats the same pattern for the rest of the rank. If it reaches the end of the whole pattern before it reaches the end of the whole board, it repeats the whole pattern as needed. Thus, something as simple as "10.01." works for Chess and most other variants. An occasional variant will use a different or more complex pattern. Hexagonal Chess uses a three-color pattern that covers three ranks before repeating, and Chessgi, which includes a holding area for captured pieces on each side of the board, uses a pattern that describes the first two ranks in full. The normal behavior is to draw no borders around spaces, letting only the different colors of spaces distinguish them from each other. But when this parameter is set to "1.", borders will be drawn around spaces for the square-table combination.

Sides

This specifies the names of the sides. The default for this is "White Black". Since all names must be separated by single spaces, spaces may not be used in the names. At present, only two-player games are supported. So only the first two names will be used. The first name is for the side that moves first, and the second name is for the side that moves second. You will normally want to leave this field unchanged unless your game uses different names for the two sides, such as Red and Blue, or has Black move first, as Shogi does.

Appearance

How a game is displayed to a player is not a critical part of what Game Courier needs to know to interpret moves, calculate new positions, or enforce rules. The appearance of a game is for the benefit of the players, and it should be user-configurable to allow players to play with sets and boards they are personally comfortable with. When you create a preset, you should define a default appearance for the game. You may then use Customize mode to provide other customizations of the preset that keep the same settings file but use different graphics. Players may alter most of the same fields to their personal preferences in ongoing games. This will affect only what a particular player sees and not what the other player sees.

Shape

This field controls the shape of the cells or the board. While shape normally has an effect on what kind of movement is allowed across the board, it has no bearing on how the program internally models the game. It could display a Chess board as a circle or as a rhombus of hexagons, and it wouldn't make a bit of difference to how Game Courier understands the game. The shape parameter is provided for the benefit of human players, who normally expect certain games to use certain shapes.

But because shape does have a bearing on the rules, customization of shape is not allowed unless the shape is square or custom grid. These two shapes are interchangeable for the same games. The main difference between them is that the square shape tells Game Courier to draw a board from scratch, and the custom grid shape tells Game Courier to draw the board using a pre-existing graphic image.

Game Courier handles boards with the following shapes:

The first five shapes cover most kinds of boards, and the last shape covers all the rest. The first five all use standard file/rank coordinates, which are represented by a file label immediately followed by a rank label, such as a1 or e4. These are the standard algebraic type of coordinates used in Chess. How this is done for boards whose cells are not rectangular is described further below. Unlike the other shapes, the Custom Board shape lets you individually specify coordinates without any underlying two-dimensional file/rank axis. This makes it useful for 3D games and for very strange boards.

Square Cells

Most variants will use the square cell shape. When this shape is specified, each space will be the same shape and size, a square, or at least a rectangle, whose dimensions are determined by the $height and $width variables. These are normally set to 50, but they may be changed in files for individual piece sets. This allows the size of the cells to be based on the size of the pieces. This shape uses standard file/rank coordinates. Files are vertical lines of spaces, and ranks are horizontal lines of spaces. The boards made with this shape may be of varying shapes and dimensions. This shape only constricts the shape and size of individual spaces.

The spaces drawn for square-celled boards will be colored according to a Checkering pattern, described further below. Unless it is drawn in ASCII, its spaces will be drawn in solid colors listed in the Colors field.

Horizontal Hexagons


      /!\ /:\ / \ /!\ /:\ / \ /!\ /:\ 
2    |!!!|:::|   |!!!|:::|   |!!!|:::|
    /:\!/ \:/!\ /:\!/ \:/!\ /:\!/ \:/ 
1  |:::|   |!!!|:::|   |!!!|:::|   |  
    \:/ \ / \!/ \:/ \ / \!/ \:/ \ /   
     a   b   c   d   e   f   g   h   

Horizontal hexagons are standard equilateral hexagons that naturally align along the horizontal axis. These cells have a point at the top and bottom, with vertical flat sides on the left and right. Game Courier identifies their coordinates by means of slanting files that go from the lower left to the upper right and horizontal ranks. Coordinates are given in standard file/rank format. Note that each new rank begins half a space to the right of the previous rank. Thus, a full board will be shaped like a parallelogram. For a board that is shaped like a hexagon, which is common for hexagonal chess games, various spaces must be cut out.

See Hex Shogi 91 for an example.

Vertical Hexagons

     a   b   c    
            ___  4
        ___/   \  
    ___/:::\___/ 3
   /!!!\___/!!!\  
 4 \___/   \___/ 2
   /:::\___/:::\  
 3 \___/!!!\___/ 1
   /   \___/   \  
 2 \___/:::\___/  
   /!!!\___/      
 1 \___/          
     a   b   c    

Vertical hexagons are standard equilateral hexagons that naturally stack vertically. These cells have flat sides on the top and bottom and points on the left and right sides. Game Courier recognizes their coordinates by means of vertical files and slanting ranks that go from the lower left to the upper right. Coordinates are given in standard file/rank format. Note that each new file begins half a space above the bottom of the previous file. Thus, a full board will be shaped like a parallelogram, and various spaces must be cut out to shape the board like a hexagon, which is a common board shape for hexagonal chess variants.

See Glinski's Hexagonal Chess for an example.


Circular Boards

Circular boards are distinguished by the shape of the board, not the shape of the cells. Instead of using cartesian coordinates, circular boards use polar coordinates. Cartesian coordinates place points on an x/y axis. Hexagonal boards merely shifted the angle between the axes. Polar coordinates distinguish a point by its angle and distance from the center. On a circular board, Game Courier distinguishes ranks by their distance from the center, and it distinguishes files by their angle. In other words, each ring of spaces counts as a rank, and each pie slice of spaces counts as a file. Because there is no good place to place rank markers on a circular board, Game Courier normally just writes file markers. Game Courier's usual convention is to number the innermost ring as rank 1, counting out from the inside. So, the higher the rank number, the further away it is from the center. Circular boards are automatically generated by the PNG, GIF and JPG methods, and the CSS method supports circular boards when an appropriate graphic image is used.

See Circular Chess for an example.


Custom Grids

A custom grid can be used for square boards, hexagonal boards, triangular boards, and more. It can do any of these by letting you adjust the x and y intervals between ranks and files. It does these with two fields. These are Nextfile and Nextrank. Each takes at least two numeric values. By default, Nextfile is "50 0" and Nextrank is "0 50". These defaults create a board checkered with squares whose sides are 50 pixels in length. The first number is the x interval, and the second is the y interval. For square boards, a change in file changes only the x value, and a change in rank changes only the y value. But other kinds of boards change both values for either rank or file changes. For example, values of "50 25" for Nextfile and "0 50" for Nextrank can create a vertical hexagonal board.

Nextfile and Nextrank can also take more than two values, though each must always take an even number of values. When more than two values are given, the first pair is used first, then it uses each subsequent pair in turn until it goes through them all, then it repeats. Because of this, a triangular board can be done with values of "50 25 50 -25" for Nextfile and "0 50" for Nextrank. Even more complicated boards can be handled with longer strings of values.

Note that the values of Nextfile and Nextrank presume a value of (0,0) for the first space in the first rank, which is by default a1. Values for Nextfile and Nextrank should normally be positive, though negative values are also acceptable. The dimensions of the board are calculated to find the size of the box used to contain the board, and positions in the container are readjusted for negative positions.

See Chinese Chess for an example.

Custom Boards

A custom board lets you use any board you can draw a computer image of. It is the most versatile way to design any board you like, but it is also the most tedious way to make a board. So it should be used only for boards you can't do any other way. It works by taking a list that associates board coordinates with pixel coordinates. This is filled into a TEXTAREA box, and each association of coordinates should have its own line. Here's a short example:

The first word in each line should be a board coordinate. It doesn't have to be in the usual coordinate form. It may be any kind of label. The second word is the x position, and the third word is the y position. These should all be positive, and (0,0) should be understood to lie at the top left corner. This is the same point that is used as the origin for graphic images. When you enter pixel coordinates, it will often help to look at the image in a graphics program that can tell you the coordinates of wherever you point the mouse. The coordinates you enter should belong to the top left corner of the space, or if it's not rectangular, the top left corner of the rectangle the piece will be displayed in. Don't worry about centering your pieces. The PBM will read the dimensions of each piece and center pieces automatically.

When using the Custom shape, the PBM does not make use of the usual rank and file coordinate system. It ignores any values given to the Ranks, Files, and Columns fields. The Forsythe code uses the order in which you define the positions, and it determines the dimensions of the container from the dimensions of the background image. So, unlike some shapes, the custom shape does not allow the use of tiled images.

See Crazy 38's for an example.

Rendering Method

Boards may be drawn in a variety of ways.

Before describing these in detail, let me mention that the combination of shape and rendering method determines exactly how a board is drawn. This table indicates the available combinations and what they do.

ASCIITableCSSPNG, GIF or JPG
SquareDraws ASCII diagramGenerates board from scratch; draws as tableGenerates board from scratch; draws as image
Horizontal HexagonalUses background image for board
Vertical Hexagonal
Circular
Custom GridUses background image for board, or generates board from tile image
CustomUses background image for board

PNG, JPG, or GIF Image

Each of these methods renders a board as a graphic image file, making use of an AREA MAP and the USEMAP attribute of the IMG tag to click on and move individual pieces. These are the most versatile of any methods, and they share some of the same pros and cons:

ProsCons
  • Uses anti-aliasing to retain image quality when resized.
  • Works for any type of board, including circular, hexagonal, and custom.
  • Allows use of background images.
  • Can auto-generate square, hexagonal, and circular boards without background images.
  • Can use server-side fonts for coordinates.
  • Pieces can be moved by clicking the mouse or by touching the touchscreen.
  • Must generate a fresh image each time, which means there are no bandwidth savings from using cached graphics.

They function almost identically, using much of the same code, differing only in the file format used for the generated image.

PNG Images

If you're using a modern browser with a fast broadband connection, this will normally be your best choice. The PNG format was created to replace GIF at a time when the patent on GIF hindered the development of free software for creating GIF images. It is generally superior to GIF, because it can support true color images and has better compression for small-pallette images.

ProsCons
  • Best image quality, lossless and true color.
  • Smaller file size for small pallette images than GIF.
  • Larger file size for true color images than JPG.
  • Larger file size for resized images than with GIF or JPG.
  • The PNG format is not supported in some older browsers.
JPG Images

If you're short on bandwidth but want to use resized or true color images, the JPG format may your best choice.

ProsCons
  • True color images.
  • Smaller file size than PNG for true color images.
  • Smaller file size than PNG or GIF for resized images.
  • Works with any browser that supports graphics.
  • Lossy image compression, resulting in some degradation of image quality.
  • Larger file size than GIF or PNG for small pallette images.

Unlike the GIF and PNG methods, this method supports the use of the Quality field, which should be set to a value between 1 and 100. This is the quality at which a JPG image gets saved. A lower quality results in a smaller filesize but also in more image distortion. The default of 75 is usually a good balance between filesize and image distortion.

GIF Images

The GIF format supports small-palette images of no more than 256 colors. It is good for images that don't make use of true color graphics and don't need to be resized. Resized images will be reduced to 256 colors and dithered to minimize distortion, but the result will usually be larger than a resized JPG file. The GIF format is supported by every graphical web browser. The main reason to use GIF is if your browser does not support PNG. Unless you are using an antique browser, it is unlikely that you lack PNG support.

ProsCons
  • Lossless image quality.
  • Works with any browser that supports graphics.
  • Limited to 256 colors, which can result in some image loss when using true color graphics or when resizing the board.
  • Larger file size for resized images than with JPG.

CSS Code

This method makes use of Cascading Style Sheets. Known by the abbreviation CSS, this is available on any modern web browser, including, but by no means limited to, Firefox, Chrome, Safari, Opera, Edge, and Internet Explorer. This method uses a background image for the board, and it positions pieces by means of absolute positioning. The background image may constitute the entire board or be a tiled pattern that gets repeated for boards of various dimensions.

ProsCons
  • No loss of image quality at normal size.
  • Minimal loss of image quality when increased in size.
  • Works for any type of board, including circular, hexagonal, and custom.
  • Allows use of background images.
  • Can auto-generate square-spaced boards with the use of tiled background images.
  • Saves bandwidth by reusing cached graphics.
  • Can use client-side fonts for coordinates.
  • Pieces can be moved by clicking the mouse or by touching the touchscreen.
  • Will not auto-generate boards without a background image.
  • Will not use server-side fonts.
  • Substantial loss of image quality when decreased in size.
  • Will not work on old browsers that do not support CSS.

HTML Table

This method renders boards as HTML tables. It works only with the square shape, representing each space with a table cell.

ProsCons
  • No loss of image quality at normal size.
  • Minimal loss of image quality when increased in size.
  • Can auto-generate boards without background images.
  • Saves bandwidth by minimizing use of graphics.
  • Saves bandwidth by reusing cached graphics.
  • Works on any browser with graphics support.
  • Can use client-side fonts for coordinates.
  • Pieces can be moved by clicking the mouse or by touching the touchscreen.
  • Cannot use background images, making it unsuitable for some games.
  • No support for circular, hexagonal or custom boards.
  • Will not use server-side fonts.
  • Substantial loss of image quality when decreased in size.

ASCII Art

This method draws ASCII diagrams. It can be used for square boards and both types of hexagonal board, but it cannot be used with custom grids or custom coordinates. The only reason for having this method is that it is the only one to work with any browser. It is usually unnecessary to choose this option in a preset, since Game Courier will automatically draw diagrams as ASCII art whenever it detects that someone is using the Lynx browser, which is the main text-based web browser in use. Although you probably won't ever need to make a preset using this method, it can come in handy when you want to generate an ASCII diagram for displaying on a web page. You can think of this method as the equivalent of figlet for Chess variant diagrams.

ProsCons
  • The only method to work with every browser.
  • Lowest bandwidth.
  • Can auto-generate square and hexagonal boards.
  • No graphics.
  • Worst visual appearance.
  • Cannot move pieces by clicking or touching.

Set Group

This changes the sets that appear in the Set dropdown menu. Various sets have been grouped together by compatibility with each other. These are sets that normally associate the same letters with the same pieces, differing only in piece design. Some sets are unique and so don't belong to any group. To select one of these sets, you should first use this to display all sets in the Sets menu.

Set

This allows you to select a different set of pieces. Your choice will usually be limited to other sets within the same group. These are sets that are compatible with each other. When you're just customizing a preset, you will probably want a piece set that is compatible with the original set. In that case, you should limit yourself to the choices within the original set's group. But you might sometimes have a reason to choose a different set. In that case, you can use the Set Group menu to change the sets listed by the Sets menu.

See Also: Creating a Piece Set

Background

Background images are used with the CSS, PNG, GIF and JPG methods. All available background images are stored in the same directory, and the menu for this field lists all of them except for those used only for displaying the board from the second player's perspective. Most background images are symmetrical and will do for both players, but some are asymmetrical, such that one is used for the first player's perspective, and another one is used for the second player's perspective. To avoid confusion, the only background images made available for you to select from are those that will work for the first player.

Some background images are designed for tiling, and some display the entire board. Tiled background images may be used to generate boards of varying dimensions.

Your choice of background image affects the width and height of spaces. These are normally determined by which piece set you choose, but when you choose a background image, its values for width and height override other values. If you upload any new images to the backgrounds/ directory, you should contact me (Fergus Duniho) if its cell dimensions are not the default of 50 pixels by 50 pixels or if two asymmetrical images need to be paired together.

Colors

This lists up to ten colors that may be used for automatically generating boards with the Table, GIF, PNG, or JPG methods. Which colors are used where is determined by the Checker Pattern, described above. These colors may be entered in hexadecimal format or by name.

Patterns

This lists up to ten patterns that get used for drawing ASCII diagrams. Each pattern must be a single ASCII character, and there should be no separation between them. Which patterns are used where is determined by the Checker Pattern, described above.

Font

This menu selects the font used for coordinates. The font selections match fonts stored on the server, which the GIF, PNG, and JPG methods use when generating board images. The script can read these fonts, but they're in a location you can't download them from. Some of the fonts are freely available from other websites, and some come from CD-ROMs I own. Other methods make use of fonts on your computer. The font you select determines the fontlist to use. Each fontlist begins with the font stored on our server, followed by some substitutes, ending with a generic font type of serif, sans-serif, or monospace.

In selecting the fonts, I tried to represent various standard types of fonts, I selected legible and good-looking fonts, and I sought out various regional, historical, and display fonts that would suit certain games or certain themes common to many variants. The available fonts are shown below by category. The images seen here are not stored on the server. They are generated on the fly by a script that reads the fonts.

Serif

Old Style
Garalde

Cardo resembles Bembo

Cardo

Tex Gyre Pagella, a free clone of Palatino

Pagella
Transitional

Libre Baskerville, a free Baskerville clone

Baskerville

Tex Gyre Bonum, a free Bookman Old Style clone

Bonum

Resembles Times

Centime

Standard Microsoft font

Georgia

A Plantin look-alike

CrimsonText
Modern

Libre Bodoni, a free Bodoni clone

Bodoni

GFS Didot, a free Didot clone

Didot
Slab Serif
Typewriter
Courier
Clarendon
Century Schoolbook
Flare Serif
Flair

Sans-Serif

Grotesque/Gothic
Helvetica Univers
Geometric
Futura
Humanist
Optima
Computer/Legibility

Public domain clone of Apple Macintosh font:

Chicago

Optical Character Recognition A

OCRA

Optical Character Recognition B

OCRB

Based on the Commodore Amiga font Topaz:

Topaz New

Standard Microsoft font

Trebuchet

Standard Microsoft font

Verdana

Display

Historical/Fantasy
Cloister Druid Enchantment Templar
Show Business
Review Uncollage
Miscellaneous
AdLib Benguiat TechSchool Trinigan

Foreign

Chow Fun German Japan

Point Size

This lets you choose the point size of the font used for coordinates and ASCII art. The default value is 12.

Scale

This is a percentage value of the scale to render a board at. The default value is 100, which doesn't change the size at all. Lower values decrease the size, and higher values increase the size. The method used for scaling depends on the rendering method. The GIF, PNG, or JPG methods resize the image they create. This is best for scaling down to smaller boards, because it uses anti-aliasing to preserve the image quality, and it reduces bandwidth by using smaller images. The Table method changes the WIDTH and HEIGHT values of table cells and piece images. The CSS method modifies CSS to resize the board, and it changes the WIDTH and HEIGHT values for piece images. These two are both good for scaling a board up to a larger size, because they save bandwidth by letting you cache and reuse graphics without using larger images for larger boards, and not as much image quality is lost when increasing the size as is lost when decreasing it. Finally, the ASCII method scales the board by changing the font size used for the ASCII art.

JPG Quality

This is a percentage value between 0 and 100 for the quality of an auto-generated JPG image. Reducing the quality reduces the filesize, which reduces download time. The default is 75, which is commonly the default that graphic programs use when saving JPG files. It is best to play around with this value to see what gives a good filesize without starting to look bad.

Max Colors

The maximum number of colors allowed in a GIF or PNG image. Since the GIF format is limited to 256 colors, any value above 256 affects only PNG images. For any value above 256, a PNG image is treated as true color, and how much the value is above 256 makes no difference. This value has no effect on JPG images, which are always true color.

Border Color

This specifies the color of the border placed around the board when autogenerating it. It may be entered as a hexadecimal color code or by name. This color is also used for highlighting the spaces a piece may legally move to when a player touches or clicks on a piece. For details on how to make a game display legal moves, see the tutorial How to Make Your Game Display Legal Moves in Game Courier.

Text Color

This specifies the color of the text used for coordinates. It may be entered as a hexadecimal color code or by name.

Border Size

This specifies the minimum width and height of the border placed around the board when autogenerating it. It is measured in pixels.

Exclude Pieces not in Setup

Setting this checkbox will cause the display of pieces at the bottom of the page to leave out any pieces from the piece set that are not used in the Forsythe code used for representing the game's opening position. This helps decrease download time by not downloading unnecessary images, and it makes the display less confusing. But it is not appropriate for all games. When, for example, pieces may promote to pieces not found in the opening position, this should be left unchecked.

Written Rules

This is where you can enter a brief prose description of the rules as a reference for the players. Besides describing the rules, you may mention details about the preset, such as how it is programmed (or not programmed) to behave, and what players may need to know about entering notation. But save details about the game's history or strategy for the main page on it. You may use HTML, but not JavaScript or PHP.

To help you display pieces using the current piece set, I have provided a shortcode called [pc]. It should be placed within square brackets, and it normally takes a piece label as a parameter. For example, [pc K] would display the image of the White King using the currently selected piece set. If a player changed the piece set, the image would change with it. This helps you match the images in your description of the game with the images used in Game Courier's display of the game. This shortcode can also take a name parameter, and it may include a description between opening and closing shortcode tags. For example, [pc K King]The King may move one space in any direction but cannot move into check.[/pc] will display the name of the piece underneath its image and place the description to the side of the image.

In case you would like to provide rules in different languages, I have provided a [lang] shortcode. This takes one parameter, the two-letter code for a language (see List of ISO 639-1 codes), and text should be placed between an opening tag with the parameter and a closing tag. Here's an example:

[lang en]This text is in English.[/en]
[lang de]Dieser Text ist in deutscher Sprache.[/lang]
[lang fr]Ce texte est en Français.[/lang]
[lang el]Είναι τα Ελληνικά μου.[/lang]

This shortcode identifies what language the enclosed text is written in, and when multiple bodies of text are written in different languages, it consults the browser's HTTP_ACCEPT_LANGUAGE environment variable to determine which language to display. If one of the languages appears in this variable, it will display text in the language most favored by this variable. When there is no match, it will display text from the first language provided by the author. In this case, that would be English.

So, it is a good idea to place text in your native language, which you would be most proficient in, first.

Programming

When you make a game available in Game Courier, you may want it to automate certain moves, enforce legal moves, display legal moves, or recognize when someone has won. All of this can be done by writing code in the GAME Code language, described further on. This is a server-side, interpreted language I designed for letting anyone program games on this site without being able to use it to hack the site. Code may be entered in seven different fields, described below. Whenever a move is made, Game Courier constructs and runs a program made from the code in these fields.

Pre-Game Code

This code gets evaluated once at the beginning of the game before anyone moves. It is the appropriate place for code that randomly places pieces, as in Fischer Random Chess, for initializing variables and , for defining functions and subroutines, and for including include files.

Pre-Move 1 Code

This code gets evaluated right before the move entered by the first player each time the first player moves. In the presets I've written, this field has often gone unused, but it sometimes has its uses.

Pre-Move 2 Code

This code gets evaluated right before the move entered by the second player each time the second player moves. In the presets I've written, this field has often gone unused, but it sometimes has its uses.

Post-Move 1 Code

This code gets evaluated immediately after each move made by the first player. It is the appropriate place for code that checks the legality of a move.

Post-Move 2 Code

This code gets evaluated immediately after each move made by the second player. It is the appropriate place for code that checks the legality of a move.

Post-Game1

This code gets evaluated after all moves and all post-move code has been evaluated. It will be evaluated only when the last move made so far was made by the first player. It is the appropriate place for code that checks for check, checkmate, and stalemate or other win/draw conditions. This is because the code for this is usually too time-consuming to run after every move. It is also the right place for code that populates an array of legal moves for displaying legal moves when the second player clicks on a piece.

Post-Game2

This code gets evaluated after all moves and all post-move code has been evaluated. It will be evaluated only when the last move made so far was made by the second player or when no players have moved yet. It is the appropriate place for code that checks for check, checkmate, and stalemate or other win/draw conditions. This is because the code for this is usually too time-consuming to run after every move. It is also the right place for code that populates an array of legal moves for displaying legal moves when the first player clicks on a piece.

Bypass Error Check on Piece Label

By default, Game Courier makes sure that the piece label you specified for a piece matches the piece you are moving. For example, it will allow "N b1-c3" as a first move in Chess, but it will not allow "B b1-c3", because the piece at b1 is a Knight, not a Bishop. While this behavior is appropriate for most games, some games need it turned off in order to distinguish between different legal moves. For example, in Fusion Chess, a simple piece may separate from and move away from a compound piece. So if a Queen is on d1 with an open file, "Q d1-d4" and "R d1-d4" would both be legal moves. This checkbox should be set only when you will use code that distinguishes between legal moves such as these and will take different actions depending on which move has been entered.

Composing a Fairy Chess Problem

You can compose problems for any of the Chess variants you can play on Game Courier, and the problems you compose will be listed in the Problems index. To start, find a game and click the Compose button. You can do this from the main preset for a game or from a position in a game you are viewing a log of. This will bring you to the problem composer. Here, you can change the board position, set the stipulation for the problem, describe it, select whose turn it is, and enter a solution. You can change the board position by entering new FEN code or by moving pieces manually. You can move pieces with the mouse or enter commands for moving pieces. Once you have the position you want, have entered the stipulation and who should move, you should enter the solution. Click on the Move button when no fields have been changed. This will bring you to where you can enter the solution by moving pieces. Once you have finished the solution, click the Compose button to go back to the problem composer, and from there enter your userid and password if need be and click the Publish button. This will store your problem on the website, and it will be accessible from this page.

Creating a Piece Set

A piece set is made from a set of images in a common folder and a PHP file that sets up an array for associating letters with piece images. Each image should be a GIF or PNG file with a transparent background, and the color of the background should be #00FF00. The transparent background is required for the Table and CSS rendering methods, which both display the actual piece images in the web browser. The green background is required for the PNG and JPG rendering methods, which both make this color transparent when copying piece images into the single image being generated. The use of this particular color for backgrounds is a convention, chosen to ease conversion of graphics created for Zillions of Games, which happens to use the same convention.

When creating a new set, you do not have to create new pieces. You might just create a PHP file that picks out a new selection of the pieces already available. But if you do make your own pieces, have an editor upload them to the site. As a general policy, I won't have set files pointing to off-site graphics. You should also have an editor upload your set file to the sets subdirectory. And whoever does the uploading, you should contact me, Fergus Duniho, to have the set listed in the sets.php file so that Game Courier has access to it.

Here is an example of what a set file looks like:

<?
$dir = "http://www.chessvariants.com/graphics.dir/japshogi/";

$pieces = array(
	"B" => "flip/Bishop.gif", "b" => "Bishop.gif",
	"D" => "flip/RookP.gif", "d" => "RookP.gif",
	"G" => "flip/Gold.gif", "g" => "Gold.gif",
	"H" => "flip/BishopP.gif", "h" => "BishopP.gif",
	"K" => "flip/WKing.gif", "k" => "BKing.gif",
	"L" => "flip/Lance.gif", "l" => "Lance.gif",
	"M" => "flip/LanceP.gif", "m" => "LanceP.gif",
	"N" => "flip/Knight.gif", "n" => "Knight.gif",
	"P" => "flip/Pawn.gif", "p" => "Pawn.gif",
	"R" => "flip/Rook.gif", "r" => "Rook.gif",
	"S" => "flip/Silver.gif", "s" => "Silver.gif",
	"T" => "flip/PawnP.gif", "t" => "PawnP.gif",
	"V" => "flip/SilverP.gif", "v" => "SilverP.gif",
	"Y" => "flip/KnightP.gif", "y" => "KnightP.gif",
	"Z" => "flip/Kamikaze.gif", "z" => "Kamikaze.gif"
);

$flipped = array (
	"K" => "WKing.gif", "k" => "flip/BKing.gif"
);

if (($shape == "square") || ($shape == "grid")) {
	$width=42;
	$height=45;
}
else {
	$width = 52;
	$height = 52;
}
$flip = true;
?>

In this example, $dir indicates the directory where all the images can be found. Lowercase letters are assigned to Black pieces, and uppercase letters are assigned to White pieces. Individual letters or longer names may be used for this. The $width and $height variables indicate the dimensions for the spaces. These normally default to 50 and usually don't need to be set here, but the Shogi pieces were smaller than the default pieces. To accomodate hexagonal boards, different values have been given for nonsquare shapes. When the $flip variable is set to true, as it is here, it indicates that piece sets should be switched when the board is flipped. It is set to true here, because these pieces are distinguished by orientation rather than by color. The default is for it to be false, and for most piece sets, it does not need to be set in the piece set definition files. When it is true, a $flipped array will be used, and it will be automatically generated from the $pieces array by switching the values for lowercase and uppercase keys. When exceptions to this procedure are required, they should be made in the set file by partially defining the $flipped array ahead of time. This was done here, because in this set, the two Kings are distinguished by appearance as well as by orientation. If you happened to use longer names and did not use all lowercase for one side and all uppercase for the other, you may have to define a full $flipped array in the set file.

Making Boards

Although Game Courier can automatically generate boards for many games, it can't generate boards for all games. Also, you may prefer something more beautiful than the simple small-palette boards generated by Game Courier. The CSS, GIF, PNG, and JPG methods can make use of background images for boards. If there isn't already a suitable background image available, you will need to make your own. That's what this section is about.

The first thing you will need is an image editor. While I do still use and recommend Ultimate Paint, it is no longer being developed, and it frequently crashes. Other editors you may check out include Paint.net and GIMP. Whatever editor you use, it should let you create GIF, PNG, and JPG files, which are the three acceptable file types for images on web pages.

This guide won't tell you how to use a graphics program. But I will describe some general techniques for designing boards. One is to first display your pieces against some tiling background image. This is to find out exactly where Game Courier will be placing the pieces on the board. If you take a screenshot of the display, you can load it into your graphics program and use it as a guide for positioning the spaces. While this is not so important for square boards, it can really come in handy for circular or hexagonal boards, not to mention boards of even more unusual designs.

You can use textures in place of solid colors by pasting solid color patterns over images of textures, then cutting them out and pasting them on your board in the right place. This is how I have created various boards with wood and marble backgrounds.

If you want to control how coordinates are displayed on your board, make two boards. Put the coordinates from White's perspective on one board, and put them from Black's perspective on the other board. Then have your preset use both boards, a different one for each player. Doing so will cause Game Courier to not display any coordinate labels, leaving only your predrawn coordinate labels.

GAME Code

When Game Courier calculates how moves change the board position, it does so by constructing and running a computer program written in a language designed specifically for Game Courier. This language began as a set of commands for automating tedious or special tasks, such as rotating the board for Motorotor, handling captured and dropped pieces for Shogi, or rolling dice for Vegas Fun Chess. Over time, it evolved into a full-fledged programming language that can be used for enforcing the rules of games. It is named in the Procrustean manner of starting with an acronym and finding words to fit. So GAME Code is an acronymic name for Game Courier's Automation, Management, and Enforcement Code. The main influences on GAME Code are PHP, BASIC, and the Zillions of Games language. It is written in PHP, it is an interpreted language with a structure very similar to BASIC, and it is designed for some of the same purposes as the Zillions of Games language.

To calculate how the moves of the game change the original position, Game Courier constructs and interprets a program written in the GAME Code language. Note that you will never write a full GAME code program yourself. You will just write parts that it will put together into a complete program for the sake of evaluating moves and determining the board position. At the bare minimum, this program consists of a series of moves, and such a program will just change the position of pieces on the board. But it can be programmed to do more. With the GAME Code language, you can write code that runs at the beginning of the game, at the end, and before or after each move. Code run at the beginning goes in the Pre-Game field. This is typically used for setting flags and variables and for defining functions and subroutines that will be used later. It is also where you include files, which may contain code intended for use with multiple games. The code for included files will be appended to the end of the program after the end command. Code for evaluating the legality of a move typically goes either before or after each move is made. There are Pre-Move and Post-move fields for this. My own practice is to use the Post-Move fields to evaluate a move after it has been made. This allows the use of special variables that give information about the move to be evaluated. For most games I've programmed, I've left the Pre-Move fields blank. But they sometimes have their uses. Code for determining whether anyone has won yet typically goes at the end. There are two Post-Game fields for this, one for each player, so that it may run different code depending on who the last player to move was.

Code appearing before or after the game appears at the main level of the program. Moves also appear at the main level. Code run before or after each move is encapsulated in a subroutine. Before each move, it adds a line that sets the variable mln to the index of the mline array with the original move in it. This is useful when you want to access the actual text of the move with the thismove built-in function. This is useful for multi-move variants whose parts need to be separated and individually evaluated, but for most games, moves can be evaluated by checking the value of variables set after the move is made. Here is a basic outline of what a Game CODE program looks like:

pre-game code
sub preauto1:
	code
endsub;
sub preauto2:
	code
endsub
sub postauto1:
	code
endsub
sub postauto2:
	code
endsub
gosub preauto1;
White's first move
moveindex 3;
gosub postauto1;
gosub preauto2;
moveindex 5;
Black's first move
gosub postauto2;
This portion from gosub preauto1 to gosub postauto2 may repeat with some variation for more moves.
post-game code
end
included code

For a more detailed example, look here.

The GAME Code language has evolved in two directions. One is as a functional programming language similar to Lisp, and the other is as an imperative language similar to C and BASIC. The functional part of the language is used for evaluating expressions, and the imperative part is used for enforcing rules and updating the board and pieces. The main features of the language are divided into the following sections:

In case it helps you learn the language better, you may also examine some of the PHP source code behind the GAME Code language:

Comments

Comments can be added with //, which is commonly used in C++ and PHP for comments. Anything following // in a line will be considered a comment. Use comments to describe what your code is doing, so that you and others may read and understand it better. It also helps to write comments as you program, because comments can remind you what you are trying to do.

Game Commands

These commands manipulate the gaming environment, particularly piece positions and board shape. They are presented first, because they are useful even when nothing else of GAME Code is used.

add P [all|any] C1 ... C2
Adds piece P to designated spaces, whether already occupied or not.
add P C
Adds piece P to the space at coordinate C
add P all C1 ... Cn
Adds piece P to every designated space.
add P any C1 ... Cn
Adds piece P to randomly selected space from among designated spaces.
alias A1 P1|C1 ...
Sets one or more aliases for piece and coordinate labels. Each odd argument should be an alias, and each following argument should be the actual internal representation of a piece or coordinate. You should not define multiple aliases for the same piece or coordinate, and you should not use the same alias for multiple pieces or coordinates. Setting an alias allows it to be used in a move in place of the actual internal representation, and it causes the alias to show up in tooltip text over spaces on the board, to be used when listing available pieces, and to be used in tooltip text for displaying pieces in minirules files that use the showpiece function. An alias is replaced by its internal representation during line parsing. Note that an alias may be used only with moves that use the - operator or the * operator, i.e. typical player input, and an alias should not include either of these operators or the semicolon, though it may include other punctuation. When a line gets interpreted as a command, aliases are ignored. So any code for enforcing rules should still make use of the internal representations of pieces and spaces. The alias command is intended only for improving the user interface, not for changing how presets get programmed. If you use this command to allow special names for certain spaces, it is best to use a custom image for your board that has the coordinates you want players to see. Although the alias command will affect tooltip text for individual spaces, it will not affect how rank and file labels get displayed.
capture C1 ... Cn
Captures pieces at listed coordinates. Saves last piece captured.
change C P1 ... Pn
Searches through the list of pieces for the piece at coordinate C. If it finds it, it converts it to the next piece in the list. If a piece in the list should not change, just follow it with itself. If coordinate C is given as "dest", the last position moved to is used. Useful for demoting captured pieces in Mortal Chessgi or Mortal Shogi.
clear [board]
Removes all pieces from board. Useful when composing a fairy chess problem.
convert C P1 P2 ... Pn-1 Pn
Searches for the first pair of pieces whose first member matches the piece at coordinate C. If it finds it, it converts it to the next piece in the list, which will be the next piece in the same pair. If coordinate C is given as "dest", the last position moved to is used. Useful for demoting captured pieces in Shogi.
copy C1 C2
Copies the piece at C1 to C2. Leaves C1 unchanged.
delete C1 ... Cn
Deletes the listed spaces from the board. This does not simply empty a space. It removes a space from the board, changing the board shape. Useful with Wormhole Chess.
drawn
Indicates that the game is drawn and ends the game.
drop P [all|any|first|last|left|right] C1 ... Cn
Drops piece P onto an empty space or onto all empty spaces from among the coordinates listed after the subcommand. It differs from add by not dropping a piece onto occupied spaces. Here are the subcommands:
all
Drops the piece onto every empty space among the listed spaces.
any
Drops the piece onto a single randomly selected empty space among the listed spaces.
first
Drops the piece on the first empty space listed in the series. Since "drop first" is normally used for automating the capture of pieces in Shogi-like games, its first use determines the spaces that will be searched by the * operator for dropping pieces.
last
Drops the piece on the last empty space listed in the series. Since "drop last" is normally used for automating the capture of pieces in Shogi-like games, its first use determines the spaces that will be searched by the * operator for dropping pieces.
left
Drops the piece on a randomly selected empty space from among those between the first space listed and the first occupied space.
empty all
empty C1 ... Cn
With the all keyword, it empties every space of the board. This is useful before setting up a fairy chess problem. With a list of coordinates, it empties each listed space. Like capture but doesn't record last captured piece.
flip C1 ... Cn
flip array
Flips which side a piece belongs to at each listed coordinate. The first coordinate may be "dest" for the last space moved to. If the first argument is an array, it will assume it has an array of coordinates and flip each piece on those coordinates.
lost
Indicates that the current side has lost and ends the game.
map direction-name y x ...
Adds a named logical direction to the logical map of the board. For each space on the board, it identifies the space in the direction named as the space that is y files and x ranks away. This is similar to how Zillions of Games defines directions, but the origin for Game Courier is in the lower left, not the upper left, as it is for Zillions of Games. So positive x values go up and negative x values go down. Positive y values go right, and negative y values go left. The logical map is used with the built-in functions logleap and logride, which determine whether a piece can make a leap or a ride using logical directions.
move C1 C2
Moves piece on C1 to C2. Does not set $oldpiece, $origin, or $dest. This is frequently used for moving pieces around while evaluating potential moves. This command used to move flags too, but it no longer does. I realized I had been using this command without that feature in mind, I can't think of a particular game where flags need to move with pieces, and if you are coding one, it would be best to make the movement of flags explicit.
recolor C Color_Index
recolor (C1, C2, ... Cn) Color_Index
This changes the color index of a space to the new Color_Index value. A solitary space may be given, or a set of spaces may be given as an array. When that is done, all spaces in the array will be set to the same color. The Color_Index should be an integer between zero and the number of colors minus one. The colors have previously been defined in the Colors field. If you're displaying the board in ASCII, it will use a character from the Patterns field in place of a color. The Color_Index can be given as a single integer or as an expression.
remove C1 ... Cn [Deprecated: Same as Delete]
Removes every space listed by its coordinates.
replace [not] P1 P2 [all|any|first|last|left|right] C1 ... Cn
Works much like drop, described above, except that it is more generalized. While drop works with empty spaces, replace works on spaces with piece P1 on them. When the not keyword is used, replace works on spaces that do not have piece P1 on them. One of the main uses of replace is to replace all of one piece type with another.
reserve [left|right|first|second] [number] P1 [number] [P2] ...
Places pieces in reserve. The reserve area of the board is defined by the system variable $starpath. You need to set this variable before this command will be useful. The minimum parameter required is the label for a piece. It will start searching the spaces listed in $starpath[0] for an empty space, and it will add the piece to the first empty space found. The keywords left and second will make it search along the path defined in $starpath[1] instead. These may be different areas of the board, or they may be the same area with coordinates listed in reverse order from each other. $starpath[0] is normally used for the first player's reserve area, and $starpath[1] is normally used for the second player's. These areas are used with the * operator to drop pieces from. When a number appears before a piece label, it means to put that many of the following piece into reserve. Other numbers and pieces are optional. This command can take a list of pieces and their quantities to put in reserve at once. This makes it useful for composing Shogi Tsumi or fairy chess problems for games that allow piece drops. Because of the directional nature of the command, it should be used separately for each player's pieces.
resign
Resigns you from a game, causing your opponent to be declared the winner. Should never be used in automation. For use only by a player wishing to resign.
restore [label]
Restores the board configuration, color indexes, flags, and information on the last move to what it was when the store command was last used with the same label. When a label is not specified, the default label is "last", the same as it is for the store command. This command is useful for restoring the actual board position after making hypothetical moves while testing for checkmate or stalemate.
reverse C1 ... Cn
Reverses the order of the contents of the listed coordinates.
rotate C1 ... Cn
Rotates the listed coordinates, so that the contents of each coordinate is moved to the next coordinate in the list, and the contents of the last coordinate is moved to the first coordinate in the list. Useful for Motorotor.
shift C1 ... Cn
Shifts the listed coordinates, so that the contents of each coordinate is moved to the next coordinate in the list. The first coordinate is emptied, and the contents of the last coordinate are lost.
shuffle C1 C2 ... C2
Randomly shuffles the contents of the listed coordinates.
store [label]
Stores the current board configuration, color indexes, flags, and information about the last move. Used with a label, it stores all this information to a unique storage space identified by the label. This allows you to keep a record of multiple past positions. Used without a label, it uses "last" as the default label. It is commonly used without a label to store the current game configuration while trying out possible moves, which can then be restored with the restore command.
swap C1 C2 ... Cn-1 Cn
Swaps the contents of the coordinates in each pair of positions. With two arguments, swap, reverse, and rotate all function the same.
won
Indicates that the present side has won and ends the game.

I have also implemented a method for handling dice rolls. Enclose a list of piece letters in brackets, and move it to a space like you were moving a single piece there. For example, [KQRBNP]-Dice1. This will randomly select one of the listed pieces and place it at the coordinate die1. This is suitable mainly for Chess dice. To use it for numbered dice, you would need to include appropriate graphic images in your piece set.

For examples of automation and randomization in actual presets, check these presets out in Edit mode:

Brand X Random Chess
Randomizes the setup with shuffle in the Pre-Game automatic move.
Fischer Random Chess
Uses drop, copy, and flip in the Pre-Game automatic move to randomize the setup according to Fischer's rules for randomizing the setup.
Motorotor
Uses Post-Move 1 to rotate the board after every move.
Vegas Fun Chess
Makes dice rolls with the two Pre-Move automatic moves.

Revision Commands

The commands in this section revise the current move. This is useful for allowing a player to enter more complicated moves with just the mouse. While these commands do not ask for user input, the next section contains commands that both ask for user input and revise the move based on the value of the input.

appendmove expression
This command appends the value of the expression to the current move. This command is useful when you want to make a move clearer without requiring the player to write out the full move. I have used this command in Shogi to identify forced promotions. When a promotion is mandatory, there is no need to ask a question about it, and it is possible to make the promotion quietly without editing the move, but this makes it easier to spot promotions when looking back over the moves played in a game.
rewritemove expression
This command rewrites the current move with a new move. This is useful for standardizing the notation used for a game. In Janggi, for example, I allow players to reposition Horses and Elephants using the mouse, and then I use this command to rewrite the Horse or Elephant move into a swap command or a pass command. I also add code that puts pieces in the position the new command will. Using this command, it is possible to program a game to use specialized notation while also accepting the standardized notation used by moves made with the mouse.

Input Commands

Because Game Courier will run an entire program that includes all past moves each time someone makes a new move, it would not be feasible to include input commands that set a variable. But input commands can be useful so long as each one asks a player something only once and then remembers the results. Most of the following commands remember the results by modifying the move. One of them remembers its result by storing it in a constant. Many of these are used to better enable a player to make all moves by clicking (or touching) pieces.

ask question answer-1 move-1 ... answer-n move-n
The question is text presented to the player. This is followed by two or more pairs of answers and moves. This command is to be used when a player makes an ambiguous move. Instead of proceeding straight to verification of the move, it asks a question and presents the player with choices in the form of radio button options. The answer a player chooses will determine how the move will be appended. Once the move is appended, it will proceed to the usual form for verifying the move, assuming that the code does not create an infinite loop with this command. If this command is used unconditionally, it will create an infinite loop. To prevent an infinite loop, it must be used with a condition that changes after this command disambiguates the move it was used with. This can usually be done by examining the move itself. When the move is incomplete or ambiguous, it is appropriate to use this command, but when a move is complete and unambiguous, this command should not be used. To give one example, I have used this command in Shogi. When a player makes a move where promotion is optional but not mandatory and promotion hasn't been specified, it uses this command to ask whether a player wishes to promote the piece. When the player chooses "No", I have had it append a "skip" command to the move just to make the move unambiguous and prevent it from repeatedly using the ask command in an infinite loop. This also prevents the command from being used for past moves.
askpromote array
askpromote P1 ... Pn
Like ask above, this asks a question and appends the move based on the answer selected. It specifically asks the question, "Which piece will you promote to?" It should be followed by the labels identifying the choices for promotion or an array with the same information. It presents the choices with images of the pieces. It should be used when a piece gains the option to promote to one of two or more different pieces, and the promotion has not already been written into the move. I have used this command in the Pawn subroutines in the Chess include file for allowing the player to decide which piece he will promote a Pawn to when it reaches the last rank. Since the Pawn cannot, by the rules of Chess, remain a Pawn, adding the selected promotion always makes the move unambiguous, preventing askpromote from being used more than once for the same move during a game. Nevertheless, this command can create an infinite loop if used unconditionally. It should always be used conditionally under certain circumstances.
continuemove
This command allows multi-part moves to be made with the mouse. Instead of moving on to the form for verifying a move, this command returns to the form for making a move, showing the code for the move just made in a field called "Past Moves", allowing the player to make another move, which will get appended to the value in Past Moves. I have plans for using this command with multi-move variants. To avoid infinite loops, this command should be used only for incomplete moves, and it should never be used unconditionally.
input constant question [arg1 arg2 ...]
This command asks the player a question and stores the answer in a named constant. When it finds that the constant is already set, it skips the question and does nothing. Arguments after the question are optional. When there are none, the user may write an answer in a text field. When only one argument follows the question, it is used as the value for a checkbox field, and it is printed as text. When more than one argument is given, multiple choices are given as radio button fields. When the argument is a string, it will be used for the value of the radio button field, and it will be displayed as text. If that string is a piece label or a coordinate label, it will also display the piece or coordinate. When the argument is an array, the array's first element will be used for the value of the radio button field, the rest will be displayed as text, and no image will be displayed. See the code for Mystery Chess for an example.
redomove
This command repeals the last move and prompts the player to move again. In correspondence games, it goes back to the form for moving instead of forward to the form for verifying a move. Although it removes the last move from the movelist, as though it were never made, it does not return the board to the position it was in before the last move was made. This is left up to other code in the program. Depending on what kind of moves are expected, this can be done with "add old dest; add moved origin;" or with "restore". If restore is used, store should be placed in the pre-move code, so that the board position is stored before any moves are made. This command functions like continuemove except that it discards the last move made instead of letting a player add to it. The main purpose of this command is to allow players to redo illegal moves. To avoid infinite loops, this command should never be used unconditionally.

Output Commands

The first four commands output text immediately and are intended for debugging or for writing error messages for the player to see. If the GAME Code program completes successfully, output from these commands will be hidden, though you may still view it by viewing the page source. But if the GAME Code program exits prematurely, Game Courier will not reach the CSS code for hiding the output, and it will remain visible. This makes it useful for displaying error messages when a player makes an illegal move. The last two set strings of text that will be displayed after the GAME Code program has completely finished. These are useful for communicating information to players.

die text
Displays text on screen and exits Game Courier program. This is intended for writing messages about illegal moves. To set it off from other output, it will be formatted as a top-level heading. This works out, since you can use this only once in the execution of a program, and when it is used, there will be no further text on the page.
echo text
Displays text on screen. Useful for placing a message at the top of the preset and for displaying debugging messages.
print expression
Displays the value of the expression on screen.
printr variable
Displays the value of the named variable on screen. Useful for displaying values of arrays.
remind text
Displays reminder text, which will be displayed lower and smaller than the text displayed with the say command. Since the output is displayed after the GAME Code program ends, repeated uses will not display multiple messages, only the message given in the last use of remind will be displayed, and it will not display anything when the GAME Code program exits prematurely. It is intended for general reminders, not for game status updates or error messages.
say text
Displays a message in boldface above the board. Since the output is displayed after the GAME Code program ends, repeated uses will not display multiple messages, only the message given in the last use of say will be displayed, and it will not display anything when the GAME Code program exits prematurely. It is useful for displaying messages about the status of the game, such as "Check!", "Checkmate! White wins!", "Stalemate! Drawn game!", etc., but it is not useful for displaying error messages.

Variables

Using Variables

GAME Code allows you to set and use variables. A variable may be accessed in one of two ways. In an expression, the var operator will return the value of a named variable. For this to work, the variable name should not match any operator name. The other way is to prefix the variable name with a # sign. For example:

set v 5;
echo #v;

Used this way, variables work sort of like preprocessing code. In fact, this was the original reason for using the # prefix. Like preprocessing code, the variable in the line of code gets replaced by its value. For example, "echo #v" becomes "echo 5". While this does not make a difference in most places, it does matter in function definitions. If you specify a variable with the # prefix in a function definition, it will use its value at the time of the function's definition, but if you use the var operator, it will use the value which the variable has when you call the function.

Although the # prefix works similarly to preprocessing code, it doesn't work entirely like it. A typical line of code consists of a command followed by arguments, each separated by a space. When the value of a variable includes spaces, it does not change the number of arguments passed to the command. For example, this code will produce an error:

set v "a1 b1 c1 d1 e1 f1 g1 h1";
shift #v;

Instead of finding eight arguments, the shift command in this example will find one unusable argument. The eval command, described later, will help you work around this.

Variable Names

The main rule for variable names is that they should not begin with a digit. Beyond that, any string is allowed that can be used as an array key in PHP (GAME Code's parent language). Generally, variable names should be alphanumeric strings that start with a letter. It is best to avoid the names of commands and operators as variable names.

Variable Types

Variable types include strings, arrays, numbers, and booleans. There is no strict typing of variables. You don't have to define a variable's type before using it. The content of a variable will determine its type. Here are some examples of setting variables to different types:

set stringvar "This variable is a string, which is a continuous series of characters.";
set arrayvar (This variable is an array. Each word, including adjacent punctuation, is an element of this array.)
set numvar 6;
set boolvar true;

As shown above, strings are surrounded by quotation marks, and arrays are surrounded by parentheses. Arrays can include arrays by nesting parentheses. For example:

set twodarray ((One array) (another array));

Variable Scope

For the sake of being able to reuse variable names in different subroutines, the same variable name can be used for different variables within different scopes. Even if you were careful to give all variables unique names, recursive subroutines would still require the use of scoping. Scope can differ in width, and it can differ over whether it is dynamic or lexical. GAME Code provides all combinations of these differences.

When you call a subroutine from the main program, it has a narrower scope than the main program. Likewise, if you call one subroutine from another, it has narrower scope than the one you called it from. You could repeat this indefinitely, calling one subroutine from another from another, etc. Each subroutine would have a narrower scope than the one you called it from.

Some variables are limited to the scope they were created in, and some are not. This has to do with whether a variable has dynamic scope or lexical scope. A variable with dynamic scope is visible in all narrower scopes, while a variable with lexical scope is visible only in the subroutine it was created in.

ScopeDescriptionTechnical Details
Global Being dynamic variables with the widest scope, global variables can be created and accessed from anywhere in a program. By default, any new variable is global. Indexed to the widest scope and to the main program as $uservar[0]["main"].
Local Being dynamic variables with narrow scope, local variables are visible to any subroutines they call, but they are invisible to the main program and to any subroutines with wider scope. Where local variables exist, they supersede all dynamic variables with the same name but wider scope. So local variables supersede global variables, and local variables of narrower scope supersede local variables of wider scope. By default, any variable passed as the parameter of a subroutine is local. Other local variables must be created with the local command. Indexed to the current scope and the main program as $uservar[$scope]["main"].
Static Being lexical variables with the widest scope, static variables are visible only to the subroutine they are created in, but they retain their value through multiple calls to the same subroutine and between subroutine calls. Where static variables exist, they take precedence over any local or global variables with the same name. Static variables must be created with the static command. Indexed to the widest scope and to the current subroutine name as $uservar[0][$sub[$scope]].
My Being lexical variables with narrow scope, my variables are always unique to a specific subroutine call. Where they exist, they always take precedence over other variables by the same name. My variables must be created with the my command. Indexed to the current scope and the subroutine name as $uservar[$scope][$sub[$scope]].

When different variables have the same name, GAME Code recognizes my variables first, static variables second, local variables third, with precedence given to more local variables, and global variables last. By default, any variable passed as a parameter of a subroutine is local to the subroutine, and any new variable is global. To use static, my, or other local variables within a subroutine, they must first be defined by the appropriate command:

local variables
Makes dynamic local variables using the names listed. When the local variable is new, it gets set to zero. Local variables are indexed to the scope but not to the subroutine name. A local variable is visible to any higher scope that doesn't redefine the name, even within subroutines. All local variables created in a scope are destroyed when the scope closes. This command has the same effect as the Perl command by the same name.
static variable expression
The first time a subroutine runs, the static command makes a static variable with the value given in the expression. A static variable is indexed to the current subroutine name but not to the current scope. So using this command at different scopes within a subroutine will not create a new variable or change its value. A static variable lasts for the duration of the program, and it will still retain whatever value it was last given when its subroutine is called again. This command has the same effect as the C or PHP command by the same name.
my variables
Makes lexical local variables using the names listed. When the variable is new, it gets set to zero. These variables are indexed to both the current scope and the current subroutine name, making them the most isolated of all variables. They are invisible to both other subroutines and recursive calls to the same subroutine. When the scope they were created in closes, they are destroyed. This command has the same effect as the Perl command by the same name.

Commands for Variables

Here are the commands for reading, setting, and creating variables.

calcset operator value variables
Sets each variable in a list to a value that is calculated from a simple binary operation on its original value and another value.
calcset or value variables
calcset | value variables
Sets each variable in the list to the binary OR of itself with value. Useful for turning on individual bits.
calcset and value variables
calcset & value variables
Sets each variable in the list to the binary AND of itself with value. Useful for turning off individual bits.
calcset xor value variables
calcset ^ value variables
Sets each variable in the list to the binary XOR of itself with value.
calcset << value variables
Binary left-shifts each variable the number of times given by value.
calcset >> value variables
Binary right-shifts each variable the number of times given by value.
calcset = value variables
Sets each variable to value
calcset * value variables
Sets each variable to itself times value
calcset / value variables
Sets each variable to itself divided by value
calcset - value variables
Sets each variable to itself minus value
calcset + value variables
Sets each variable to itself plus value
calcset && value variables
Sets each variable to the Boolean AND of itself with value
calcset || value variables
Sets each variable to the Boolean OR of itself with value
calcset == value variables
Sets each variable to true if it matches value or false if it does not.
calcset mod value variables
calcset % value variables
Sets each variable to itself mod value, which is the remainder of dividing it by value.
dec V
Decrements the user variable named by V. Useful only for numeric values.
inc V
Increments the user variable named by V. Useful only for numeric values.
pop array variable
Pops off the last value of the array and copies it to the variable.
push array expression
Pushes to the end of the array the value of the expression that follows. The expression is evaluated by the Polish notation calculator.
set [many] variable arguments
Sets a program variable.
many
Set many variables. Each even argument is a variable name, and each following argument is its value. This shortcut for setting many variables cannot be used for anything but simple values. It will not evaluate complex expressions.
anything else
Any other expression gets evaluated by a Polish notation calculator, and the result is placed in the variable. It includes math, logic, board information operations, and user defined functions or subroutines.
setelem array element expression
Sets array[element] equal to the value of the expression.
unset
Unsets the named variable. When more than one variable has the same name, it unsets the one with the highest precedence, allowing the name to be used for the same-named variable with the next highest precedence.

Flags

Flags are global boolean variables that exist in a different namespace than the other variables. This allows the same names to be used for flags and variables. Unlike variables, flags can be named with numbers or alphanumerics beginning with numbers. Flags are normally associated with board spaces. Some commands assume that every board space has an associated flag. The significance of a board space's flag will depend upon how it gets used in a program. Sometimes it will have no significance at all. A flag's value can be accessed by prefixing its name with a ? or by using the flag operator before its name in an expression. In a function definition, the former will use the value of the flag at the time the function is defined, and the latter will use the value of the flag at the time the function is called. If a flag is subject to change during a game, it is better to use the latter in a function definition. By default, any flag is false unless it has been set. These commands deal specifically with flags:

copyflag C1 ... Cn
Copies the value of C1's flag to all the other listed flags. Leaves C1's flag unchanged.
setflag C1 ... Cn
Turns on the flag for the listed labels, which are typically coordinates, but they may be anything.
unsetflag C1 ... Cn
Turns off the flag for the listed labels, which are typically coordinates, but they may be anything.

Constants

Constants have even greater scope than variables. Let's call it trans-global scope or universal scope. While a variable's life begins and ends during a single run of the program, a constant will endure between separate runs. As you should be aware, Game Courier contructs and runs a fresh GAME Code program each time a player makes a move in a game. Once a constant gets set in a program, it will be available at the very start of the program on subsequent runs. For correspondence games, the values of constants get stored in the log, and for solitaire games, they get passed as form data.

Constants are useful when some values in a game are determined randomly, and it is important to reuse the same values at the same points in the program each time it is run. For example, when Fischer Random Chess randomly arranges the pieces at the beginning of the game, the new order of pieces needs to be remembered each time a program is run for the game in question. The usual way of remembering this information was to store the seed used for random number generation in the log. But this messed up some games when the algorithm for selecting random numbers was rewritten. This brought on the need to store this information directly in the log. Constants work better for this purpose than variables do, because the same information has to be available for the same moves time and again.

Constants can be accessed in one of two ways. The const operator will return the value of the constant whose name follows it. This works in Polish notation expressions but not elsewhere. A constant can also be accessed by preceding its name with a #, the same as is done for variable names. Using this convention, constants have higher precedence than variables. If the name belongs to a constant, the value of the constant will be used. The value of a variable will be used only if the name does not belong to a constant. The following commands are used with constants:

setconst constant expression
Sets the named constant to the expression that follows unless the constant already exists. The expression may be any Polish notation expression that GAME Code supports. If a constant already exists with the name used, it is left unchanged, and the expression doesn't get evaluated. No error message is given, because this can be a desirable feature. It sets the constant the first time it is used and does nothing every subsequent time the same program is run. But note that it is sometimes best to use setconst in one part of an if-else statement. When you need to run many lines of code to get the value for the constant, it is best to run them only once.
unsetconst constant
Deletes the named constant. This command should not be used unless you really know what you are doing. Unsetting a constant will let you recreate it with a new value, which can be a dangerous thing if any past moves were legal only because of the value of the constant. Unlike changing a variable, which affects only future uses of the variable, changing a constant will also affect past uses of the constant when the program associated with a log gets run again. I originally included this command on the off-chance that someone might use it to make Game Courier do some neat tricks. Now that I have created commands for rewriting moves based on user input, this command may be used to allow constants to indicate whether a potentially incomplete move should call for user input to disambiguate it or should be accepted as is.
resetconst constant expression
Sets the value of the named constant to the value of the expression. Unlike setconst, it allows the value of const to be changed. This should be used only for constants that are intended to change, such as a constant that keeps track of changing information from one move to the next. When a constant changes value during the game, it should only be used with the latest move, not with any past moves.

System Variables

GAME Code gives you access to some of the PHP variables used by Game Courier. These all exist outside the namespace for user variables. I named the following command before I implemented scoping. It does not affect the global variables mentioned above.

setglobal variable expression
setsystem variable expression
Allows you to set the values of selected PHP variables. The setglobal name is confusing, because this command does not affect user variables of global scope. Hence, this name is deprecated in favor of setsystem. This command affects variables in the external PHP program, not GAME Code's own global variables. It uses the Polish notation calculator to evaluate the expression following the variable name. The following variables are supported:
capturedpieces
This is an associative array of captured pieces to display. The keys should be piece labels, and the values should be numbers of how many captured. By default, this value is calculated automatically by comparing the opening position with the latest position, counting as captured anything from the original position that is not in the latest position. For some games, this would not be accurate, and setting this variable lets you override the default value, replacing it with one calculated with greater knowledge of the game's particular rules. For other games, such as Shogi, which keeps all captured pieces in play, showing a separate display of captured pieces is inappropriate. Setting this variable to false prevents the separate display of captured pieces.
dest
This is the coordinate that a piece was last moved to. It can be accessed in commands with the dest keyword.
lastcaptured
This is the type of the last captured piece. It can be accessed in commands with the old keyword.
lastmoved
This is the type of the last piece moved. It can be accessed in commands with the moved keyword.
maxmove
Setting the value of maxmove to anything above zero limits the number of separate moves a player can enter as part of his fullmove. A value of 2 is suitable for Chess and most of its variants, because a second move is sometimes required for a promotion. A value of 1 is suitable for Chinese Chess and many other games without any promotions. A value of zero, which is the default, will allow an unlimited number of separate moves.
noerrorcheck
A boolean flag that turns off the usual error checking when set. When this isn't set, Game Courier will normally make sure you're moving the piece you say you're moving when you use the full style of notation, such as "N b1-c3" instead of just "b1-c3". You may turn it off when error checking would get in the way of how you wish to automate the game. For example, in Fusion Chess, with a Queen at e5 and the path to e8 clear, "Q e5-e8" and "R e5-e8" would both be legal moves, and setting noerrorcheck to false would give the automation the opportunity to distinguish between them.
origin
This is the coordinate that a piece was last moved from. It can be accessed in commands with the origin keyword.
originalpieces
This sets the array that contains counts of the original pieces in the game. This is normally used to calculate the value of captured pieces. It is useful to set this when a game is programmed to change the pieces in the game before it actually begins. Set this equal to the function piececount to set it to a count of the pieces in the current position.
piecekeys
This is an array of all the keys used for piece images in the game. It affects what pieces show up at the bottom of the page. It is useful to set this when your game uses pieces not in the initial setup. Otherwise, it can be automatically generated as all the piece keys used in the initial position. This is done by setting the appropriate option in the preset edit form.
piecevals
This is an associative array that gives a numeric value for each piece. Its keys should be piece labels, and its values should be numbers. When the - operator is used for exchanging one piece for another, it is used for evaluating whether it is a legal exchange. More valuable pieces should be given higher numbers, so that a player may not get back a piece without exchanging a piece of equal or greater value.
prison
This is a two-dimensional array of two arrays. Each array specifies a prison area used in Hostage Chess. When the - operator is used for exchanging one piece for another, Game Courier will look for the pieces in the prisons. If $prison is not set, this operation won't be allowed.
starpath
This is a two-dimensional array of two arrays. Each array specifies the search path that the * operator uses to find the piece it is supposed to drop. The initial element of each array may be the keyword "first" or "last". This indicates whether the search will start at the beginning or end of the list that follows. If this is omitted, it will search for the first one. All other elements of each array should be coordinate labels. These are the coordinates that will be searched. $starpath[false] or $starpath[0] is used for the first player, while $starpath[true] or $starpath[1] is used for the second player. When captured pieces are automatically moved to the same area they will be dropped from, then setting starpath is unnecessary. But it is useful for a game such as Hostage Chess, where captured pieces go to a prison and may be dropped only after being transferred to an airfield.

Preprocessing Substitutions

Since GAME Code is an interpreted language, not a compiled one, it processes each line each time it executes it, and before processing it, it preprocesses it, which sometimes involves substituting some text for other text. When any of the following appear in a line, it gets replaced before processing the line.

alias
When an alias is made of a coordinate or piece, you can use the alias in your input, and the alias will be automatically replaced with its real value.
old
This keyword gets replaced with the previous contents of the last space moved to. This will normally be the piece label of the last captured piece. When a move was to an empty space, it will be @.
moved
This keyword gets replaced with the label for the last piece to move. If a piece gets promoted after moving, this will be what the piece was when it moved, not what it became after moving.
origin
This keyword gets replaced with the coordinate for the space the last piece to move came from.
dest
This keyword gets replaced with the coordinate for the last space moved to.
#variable_name
A variable name prepended with # sign gets replaced with the value of the named variable. This allows the use of variables with commands. This should not be used in a function definition, because it will substitute the value of the variable at the time of the function's definition. To use the current value of the variable each time a function is called, you should use var variable_name instead.

Expressions

GAME Code evaluates expressions with Polish notation. This is a form of prefix notation that lists operators in an unambiguous order. Every operator gets listed before its operands, but the whole expression is evaluated in a back-to-front order, so that operands get evaluated before operators. Although Polish notation does not require parentheses to establish order of operations, GAME Code's line parsing allows the use of parentheses. Parentheses never get as far as the Polish notation calculator, but they do affect the input that does reach it. When text appears between parentheses, it gets parsed as an array. Since the process is recursive, nested parentheses will parse into multi-dimensional arrays. Arrays are useful for partitioning off operations that may take a variable number of operands. So parentheses can be used to control how many operands get passed to an operator. Some operators take the remainder of the stack for their operands unless the first operand is an array, in which case the contents of the array gets used for the operands. Another option is to include an operator at the beginning of an array and to pass the whole array as an operands to the eval operator.

Polish Notation is simply a backwards form of Reverse Polish Notation (RPN), which was commonly used in HP Calculators. RPN was easier for early calculators to handle, because it could perform operations as they were entered and did not require parentheses to indicate the order in which to perform operations. The reverse order of RPN is essential for ease of use on a hand-held calculator, but it makes no difference when the whole expression is already entered into memory. In that case, it is just as easy to start from the beginning of an expression as it is to start from the end. So Game Courier starts evaluating the expression from the end, which allows you to put operators before operands. Here are the basic principles behind RPN. Whenever an operand is entered, it is pushed onto a stack. When an operator is entered, it pops off a certain number of operands from the stack, performs an operation on them, and pushes the result onto the top of the stack. When all is done, the stack should have only one value in it, and that is the result of the whole complex operation.

Here are some examples to help you better understand. Take the expression "minus 8 3". First, 3 is pushed onto the stack, then 8 is pushed onto the stack, then both are popped off, 8 minus 3 is calculated, and the result, 5, is pushed back onto the stack. For a more complex example, consider "not and equal 7 3 not less 3 4". First, 4 and 3 are pushed onto the stack. Then they're popped off, and the value of 3 < 4, which is true, is pushed onto the stack. This value is popped back off, reversed by the not, and a false value is pushed onto the stack. Then 3 and 7 are pushed onto the stack. 7 and 3 are then popped off, and the value of 7==3, which is false, is pushed back onto the stack. The stack now has two values in it, both false. These two values are popped off for the and. The value of false and false, which is false, is pushed onto the stack. This is then popped back off, reversed by the not, and the value of true gets pushed onto the stack. This ends the calculation, and the expression, which is equivalent to !((7 == 3) && (3 >= 4)), has been calculated to be true.

The operators are organized by how many operands each takes.

Nullary operators

best2drop
Searches a player's inhand area for the best piece to drop, based on values given to pieces in the pieceval global array. It favors higher valued pieces. This was designed for use with Hostage Chess, though it may have other applications, since it searches the starpath, which is used in any game with drops.
best2free
Searches the opponent's prison for the most valuable hostage that may be freed. The prison is defined in the prison global array. This was designed for use with Hostage Chess and may have little application to other games, since most games do not include a prison.
boardflags
Returns sorted list of all spaces with a flag set. Useful for recording the position of each move to enforce 3-times repetition rule.
capture
This indicates whether the last move was a capture. Equivalent to "nor == old @ == old void". Nota Bene: This operator is useful only for code that evaluates a move after the move has been made. If you need your code to evaluate potential moves, you should use the empty operator to test whether your destination is empty. If you need your code to evaluate both past and potential moves, you need to use something like this: cond empty #0 capture (not empty #1), where #0 is the origin and #1 is the destination. If the piece has just moved, its origin will be empty, and capture should be used. If the piece hasn't moved, no capture has been made, and your code will need to check for potential capture by checking the contents of the destination.
captured
Returns the last piece captured. Returns @ when the last move was to an empty space. Returns - when it was to a non-space.
destination
Returns value of dest at the time the expression is evaluated. This is what you want in a function that needs this value, since dest would return its value at the time of function definition, not at the time the function is called.
excode
Returns the value of the expanded FEN code, which is sort of useless, because it is an array, and it is of the original position, not the current position.
false
Returns the boolean false value.
fencode
Returns FEN code for the current position.
flags
Returns an array of all flags.
lastfile
Returns the numeric index of the last file. This would be 7 for Chess, since 0 is the first file.
lastmoved
Returns the last piece to move. Same as the substitution keyword moved, but returns the up-to-date value each time the expression is evaluated. Useful in functions, where this distinction is important.
lastrank
Returns the numeric index of the last rank. This would be 7 for Chess, since 0 is the first rank.
mln
Returns value of $mln. This value gets updated by moveindex between each move, and it serves as the index value for the array of moves. It keeps track of how far along the game is and may stand for move line. Internally, this index value is used to return the values for thismove and turn.
movenum
Returns the value of the $movenum variable, used to keep track of the number of the latest move in the game. This is not useful except in the Pre-Game or Post-Game code, since it does not increase from 0 to the latest move as the moves get processed. Instead, it starts out as the latest move number even at the beginning of processing the moves.
nil
Returns the @ symbol, used internally to identify the contents of an empty space.
nolower
Returns an array of all spaces whose piece labels are not entirely lowercase, retaining key values from original array. Useful for generating array of spaces with no Black pieces on them.
noupper
Returns an array of all spaces whose piece labels are not entirely uppercase, retaining key values from original array. Useful for generating array of spaces with no White pieces on them.
null
Returns a null string.
onlylower
Returns an array of all spaces whose piece labels are entirely lowercase, retaining key values from original array. Useful for generating an array of all spaces occupied by Black pieces.
onlyupper
Returns an array of all spaces whose piece labels are entirely uppercase, retaining key values from original array. Useful for generating an array of all spaces occupied by White pieces.
opponent
Returns the userid of the opponent.
piececount
Returns a two-dimensional array where each key is the label for a type of piece in the game, and each value is how many there are of that piece on the board. When a game is programmed to change the pieces before the game actually begins, it is useful to set the system variable originalpieces to this at the end of the pre-game section. This will allow for accurate calculations of captured pieces without requiring the GAME Code program to handle this detail itself.
piecekeys
Returns an array of all piece labels recognized by Game Courier for this particular game. It should generally be the pieces on the board when the game began.
pieces
Returns an array of all spaces on the board with pieces.
player
Returns the userid of the current player.
screen
Returns the coordinate of the last piece used as a screen when the last hopping move was checked. A screen is the piece a hopping piece hops over to capture another piece.
spaces
Returns an array of all board coordinates.
thismove
Returns the move entered by the player. This value changes from move to move within the same script, and it counts a move as the entire series of move primitives made by one player on a single turn. It is useful when you need to parse a move and handle each part separately for a multi-move variant. Checking whether it is null is useful for checking whether it is the beginning of the game. This value is determined by returning the move indexed to the current value of mln. It is set after the pre-move code and before the post-move code. So it cannot be used in the pre-move code to identify the current move.
true
Returns the boolean true value.
turn
Returns the number of the current turn. Turn numbering begins with 1, and a whole turn contains one move by each player. The turn number is determined by returning the turn number indexed to the current value of mln. This value changes after running the pre-move code for the first player and before running the post-move code. So, to identify the current move, you should test it against the value for the previous turn in the pre-move code for the first player but against the value for the current turn in the pre-move code for the second player and in the post-move code.
user
Returns the userid of the user who is signed in.
void
Returns a -, which is used in the Forsythe code and the $space array to represent a space that is part of the representation of the board but does not officially belong to the board. This is needed to avoid writing the - in commands, since this character is also used as the operator for making moves, and its presence in a move indicates that it should not be evaluated as a command.
whitespace
ws
Outputs a space character.

Unary operators

abs
Returns the absolute value of the operand.
alias
Returns the alias of a piece or coordinate if there is one, or just the piece or coordinate if there isn't.
bitnot
Returns the bitwise not of the operand.
bits
Returns the number of bits in a byte.
check
Used in combination with target. Checks whether the operand matches the value previously set by target. If there is a match, it exits the expression with a value of true. It otherwise allows evaluation of the expression to continue but pushes nothing onto the output stack. Target and check are somewhat analogous to switch and case, but they work in an opposite way. While case allows execution of code to begin, check stops further execution of code. Target and check were designed for the purpose of optimizing the code required for checking for the presence of certain pieces at certain locations, most typically pieces that might be checking the King, giving a double entendre significance to the operator name.
chr
Returns ASCII character whose ordinal value is given. chr 45 is useful for putting a hyphen in a string that may be printed in messages.
color
Returns the color index of a given coordinate. The color index of a space is initially given in the Board field of a preset. It is an integer between zero and the total number of colors minus one, as defined in the Colors or Patterns field. The color index of a space may be changed with the recolor command.
const
Returns the value of the named constant.
count
Returns how many elements are in an array.
count_values
Returns an array keyed to the values of an array, with each element set to how many times its key appeared as a value in the original array.
dec
Returns the operand minus one.
dechex
Converts a decimal (base 10) numeral to a hexadecimal (base 16) numeral.
empty
Returns boolean value indicating whether space indicated by operand is empty. Interprets off-board spaces as not empty.
eval
When its operand is an array, it recursively calls the Polish notation calculator to evaluate it as a Polish notation expression. This is useful when you use parentheses to limit the arguments passed to an operator with variable arity.
even
Returns true if the number following it is even, false if it's not.
findinhand
Returns the location of the first piece it finds in-hand that matches the wildcard pattern or false if none found. Searches the inhand area, as defined by starpath, for a piece that matches the wildcard pattern passed to it.
file
Parses coordinate and returns number used to represent file internally. These would 0 to 7 for Chess.
filename
Parses coordinate and returns id used for the file. These would be a to h for Chess.
flag
Returns the boolean value of the flag named by the operand.
flipcase
Flips the case of op1 from lower to upper or vice versa. Uses the same function as the flip command
global
Returns the value of the named global variable. These are the PHP variables that are global to Game Courier itself, not simply global variables within the scope of the GAME Code program. This function will not work for $password.
hexdec
Converts a hexadecimal (base 16) numeral to a decimal (base 10) numeral.
inc
Returns the operand plus one.
isalnum
Returns whether op1 is entirely alphanumeric.
isalpha
Returns whether op1 is made up entirely of alphabetic characters.
isconst
Returns true when the name that follows belongs to a constant, false otherwise. Used to test for the existence of a constant, even when the constant has a value of false, which just returning the value of the constant, as const does, would not catch.
isdigit
Returns whether op1 is made up entirely of digits.
isfunc
Indicates whether op1 is a function name
islower
Indicates whether string in operand is entirely lowercase.
issub
Indicates whether op1 is a subroutine name.
isupper
Indicates whether string in operand is entirely uppercase.
isvisible
Indicates whether a space is visible. An invisible space starts with !. Other spaces are considered visible.
keys
Returns an array of the keys to an array.
literal
Returns an array literal if passed an array, or a function literal if passed a function name.
neg
Returns negative of numeric operand.
not
Reverses the boolean value of the expression.
odd
Returns true if the number following it is odd, false if it's not.
onboard
Indicates whether the indicated space is on the board. "onboard ##" is equivalent to "not equal space ## void".
ord
Returns ordinal value of given ASCII character.
rank
Parses coordinate and returns number used to represent file internally. These would be 0 to 7 for Chess.
rankname
Parses coordinate and returns id used for the file. These would be 1 to 8 for Chess, but they would be a to i for Shogi.
remove
Removes the piece at the specified location, replacing it with an empty space, the @ character. Returns the result of this operation, which is normally true.
reverse
Returns reversed array or string. Reverses order of elements in array or order of characters in string.
sign
Returns 1 if op1 is positive, 0 if it is zero, and -1 if it is negative.
sort
Returns case-sensitive natural sort of array. A natural sort puts a2 before a10, for example. This is more useful for sorting coordinates than a normal sort.
space
Returns the value of the space whose coordinate is given. This may be a piece, @ for an empty space, or - for a non existant space.
target
Specifies which pieces to search for with check. To specify more than one piece, the pieces should be placed together in an array. This can be done with the array operator or by placing parentheses around them. Since the target variable is static, it can be set once, then used with recursively called user-defined functions. Since expressions are evaluated back-to-front, the target operator should appear after the check operators it is used with.
tolower
Converts string in operand to entirely lowercase.
toupper
Converts string in operand to entirely uppercase.
trim
Trims whitespace off both ends of a string.
twinonfile
Given a coordinate, it checks whether the file occupied by the piece on that coordinate is occupied by another piece of the same type and color. Designed for enforcing the Shogi rule against dropping a Pawn on a file already occupied by a friendly Pawn.
unique
Given an array, it returns an array where each value is represented only once.
var
Returns value of user-defined variable, which has previously been set with the set command.

Dual Unary/Binary operators

These can handle either one or two operands. For some logical operations, it takes only one operand to know whether it will be true or false. For example, x and y is false if x is false, no matter what y is. Likewise, x or y is true if x is true, no matter what y is. The same principle works for the negations of these, nand and nor. So, when there is only one operand available, and its value is enough to settle the value of the operation, each of these logical operators breaks from the expression and returns the known value right away. When the value of the sole operand is not enough to settle the value of the operation, it lets the expression continue without adding any new values to the stack. When two operands are available, each logical operator just evaluates the logical expression with both values and adds the value to the stack. The expression breaking behavior of these operators is useful for avoiding unnecessary calculation and for breaking out of recursive functions. The unless and onlyif functions also work with one or two operands.

and
&&
With two operands, this returns true if both operands are true, false otherwise. When the operands are arrays, it evaluates op1 first, then evaluates op2 only if op1 turned out true. With only one value, exits the expression with a value of false when op1 is false; otherwise continuing to evaluate the expression when op1 is true. Because of this, the expressions and op1 op2 and op1 and op2 will give the same result. The latter is more efficient, because it will exit the expression early if op2 is false.
or
||
With two operands, this returns true when either operand is true, false otherwise. When the operands are arrays, it evaluates op1 first, then evaluates op2 only if op1 turned out false. With only one value, it exits the expression with a value of true when op1 is true, otherwise continuing to evaluate the expression when op1 is false. Because of this, the expressions or op1 op2 and op1 or op2 will give the same result. The latter is more efficient, because it will exit the expression early if op2 is true.
nand
With two operands, this returns true if either operand is false, false if both are true. This is a shortcut for not and op1 op2, which by De Morgan's Law is equivalent to or not op1 not op2. When the operands are arrays, it evaluates op1 first, then evaluates op2 only if op1 turned out true. With only one value, it exits the expression with a value of true when the operator is false; it otherwise continues to evaluate the expression. Despite this, the expressions nand op1 op2 and op1 nand op2 will not give the same result. This is due to the negative nature of this operator. The expression nand op1 op2 is actually equivalent to not op1 nand op2.
nor
With two operands, this returns true if neither operand is true, false if either is true. This is a shortcut for not or op1 op2, which by De Morgans Law is equivalent to and not op1 not op2. When the operands are arrays, it evaluates op1 first, then evaluates op2 only if op1 turned out false. With only one value, it exits the expression with a value of false when the operator is true; it otherwise continues to evaluate the expression. Despite this, the expressions nor op1 op2 and op1 nor op2 will not give the same result. This is due to the negative nature of this operator. The expression nor op1 op2 is actually equivalent to not op1 nor op2.
onlyif
Allows evaluation of an expression to continue onlyif op1 is true. Breaks from an expression and returns the value of op2 (or op1 if no second operand is available) when op1 is false. Used for recursion in user defined functions.
unless
Allows evaluation of the expression to continue unless op1 is true. Breaks from an expression and returns the value of op2 (or op1 if no second operand is available) when op1 is true. Used for recursion in user defined functions.

The following table lists the truth value returned for each pair of op1 and op2:

op1op2andornandnor
TTTTFF
TFFTTF
FTFTTF
FFFFTT

Binary operators

!==
Evaluate strict non-identity, which is true if either the value or the variable type is different.
<=
Less than or equal to comparison
>=
Greater than or equal to comparison.
<<
Left shifts op1 by the number of bits specified in op2. Equivalent to op1 times 2 to the power of op2.
>>
Right shifts op1 by the number of bits specified in op2. Equivalent to dividing op1 by 2 the number of times specified by op2, discarding the remainder each time.
base
Converts a base ten number to the specified base. The new base is given first as op1, then the number to convert as op2.
bitand
&
Returns the bitwise AND of the two operands. Every bit that is on in both operands is turned on in the result.
bitor
|
Returns the bitwise OR of the two operands. Every bit that is on in one or both operands is turned on in the result.
bitxor
Returns the bitwise XOR of the two operands. Every bit that is on in one operand and off in the other is turned on in the result.
char
Returns character number op2 from the string op1. The first character is number 0.
cmp
Returns 1 is op1 is greater than op2, -1 if op2 is greater than op1, and 0 if both are equal.
direction C1 C2
Returns the direction of movement from coordinate C1 to coordinate C2. The direction is given in terms of north, south, east, and west. Technically, north is the direction of increasing rank values, and east is the direction of increasing file values. Generally, north is the forward movement for White, and east is movement to White's right. South is the opposite of north, and west is the opposite of east. The returned value is a string made up of one or more of the letters n, s, e, and w. Diagonal and angular directions are given with combinations of letters. Each diagonal or angular direction begins with either s or n. An angular direction may repeat the s or n one or more times. Then comes e or w. An angular direction may repeat this one or more times. Here are some examples: direction a1 h1 is n; direction a1 a8 is ne; and direction g1 d7 is nnw.
distance
Returns distance between two coordinates, measured as the least number of one-space moves it would take to reach one square from the other. Returned value will match the perimeter of op1 that op2 is found in, and vice versa.
div
/
Returns integer result of op1 / op2.
elem
Returns element op1 of array op2. If op2 is just the name of an array, it is assumed to be a root-level array. But op1 may also be a whole array. In this manner, elem may be used for finding values in multidimensional arrays. For example "elem elementone elem arrayone myarrayofarrays" would find $myarrayofarrays[$arrayone][$elementone].
equal
==
Returns boolean value of op1 == op2.
explode
Returns explode(op1, op2), using the PHP explode function. This returns an array of elements in string op1 as separated by op1.
fnmatch
Returns whether the wildcard pattern in op1 matches the string in op2.
gcd N1 N2
Returns the greatest common denominator of two numbers. This is the highest number that will evenly divide into both.
greater
>
Returns boolean value of op1 > op2.
hamming
Returns the hamming distance between two strings of the same length. This is the number of positions at which two strings are different. A string has a hamming distance of zero from itself. A coordinate normally has a hamming distance of 1 from any space in the same rank or file.
identical
===
Returns boolean value of op1 === op2, meaning they are equal and of the same type.
join
.
If op1 and op2 are both strings, it returns the concatenation of op1 and op2, with op1 first. If op1 and op2 are both arrays, it returns an array of every combination of each element in op1 concatanated with each element of op2 on its right. These are grouped by the element in op2. To switch this, just sort the array afterwards. If one operand is a string and the other is an array, it returns an array of all concatanations between the string and each element of the array that are joined in the same order as the two operands are given.
less
<
Returns boolean value of op1 < op2.
levenshtein
Returns the Levenshtein distance, a.k.a. edit distance, between two strings. This is the minimum number of insertions, deletions, and substitutions it takes to transform one string into the other.
max
Returns max(op1, op2), which is the value of whichever has the greater value.
merge
Merges two arrays into a single array.
min
Returns min(op1, op2), which is the value of whichever has the lesser value.
minus
-
Returns op1 - op2.
mod
%
Returns op1 % op2, which is the integer remainder of op1 / op2. More precisely, x mod y = x - floor(x / y)*y. When y is zero, PHP's % operator will return a division by zero error. But the same operator in GAME Code will return the value of x. Although the value of x/y may be undefined when y iz zero, the product of anything times 0 is 0, making the value of floor(x/y) irrelevant to the calculation. So, when op2 is zero, the division gets skipped, the value of floor(x / y)*y is taken to be zero, and when that is subtracted from x, the value is still x.
mult
*
Returns the product of op1 times op2, op1 * op2.
onfile
Returns whether there is a piece of type op2 on the file op1. Useful for evaluating potential Pawn drops in Shogi.
path
Returns an array of all coordinates for the shortest path of the smallest leaps in the same direction from op1 to op2, exclusive. The smallest leap will be calculated by dividing both the distance in ranks and the distance in files by their lowest common denominator. The number of leaps along the path from op1 to op2 will be equal to the lowest common denominator of their rankwise and filewise distances. The origin and destination spaces are not included in the path. When the shortest path is a single leap, the returned array will be empty.
plus
+
Returns the sum of op1 plus op2, op1 + op2.
pow
Returns the result of op1 to the power of op2.
rand
Returns a random number between op1 and op2.
range
Returns an array of all values from op1 to op2.
regmatch
Returns whether the regular expression in op1 matches the string in op2. The underlying function is preg_match in PHP.
revealed
Given two coordinates, this moves along the line between them from op1 until it reaches an occupied space or goes off the board. When it reaches an occupied space, it returns the coordinate of the space. When it does not reach an occupied space, it returns false. It is useful for finding a space from which there may be a revealed check by giving it the King's coordinate and the coordinate of a recently vacated space.
same
Does a case insensitive comparison of two strings, returning true if they are equivalent, false if they are not.
samecase
Returns true is both op1 and op2 are strings of the same case. Two strings are the same case when all alphabetic characters in both are all lowercase or all uppercase, or when both have alphabetic characters in both upper and lowercase, or when neither has any alphabetic characters. Some examples of strings in the same case include "k" and "e1", "P" and "Q", "aP" and "Ap", and "5" and "@".
slope
Returns the slope between two coordinates, using the formula m = (x1-x2)/(y1-y2).
strstr
Searches for op2 in op1, returning position, starting with 0. Returns false if not found.
unequal
!=
Returns boolean value of op1 != op2.
xor
Returns the boolean value of op1 xor op2, which is true when they have different truth values, false when they are the same.

Ternary Operators

behindscreen
Given a coordinate and the dimensions of a single step away from the space, given in x y form, it rides away from the space one step at a time, hopping over the first piece found, then returning the label for the next piece found. Used to check whether a King is in check from a piece that captures by hopping, such as a Cannon.
checkmaxsteps
Checks whether a move made up of up to op3 steps from one adjacent space to another can go from op1 to op2.
checknsteps
Checks whether a move made up of exactly op3 steps from one adjacent space to another can go from op1 to op2.
cond
Returns op2 when op1 is true, op3 when op1 is false. Note that it will evaluate op3 and op2 before op1 unless they are encapsulated in parentheses. This is important to know if you intend to use cond in a recursive function. When both op2 and op3 are in parentheses, it will conditionally evaluate one or the other, depending upon the truth value of op1. Note that the expression that evaluates to op1 should not be in parentheses unless you want it to evaluate to true for anything but the empty set.
insight
Returns the id of the first piece that would be reached by riding from space op1 at op2 files and op3 ranks per step. When no piece is in sight, false is returned.
leaps
Given a coordinate and a distance given in x y form, it returns an array of every space that distance away from the space whose coordinate was given. For example, leaps h1 1 0 would return the array (g1 h2). The array may have as few as one space, leaps a1 1 1 or as many as eight, leaps e4 1 2. Used for generating an array of all spaces a piece may legally step one space to. Useful when generating possible moves while checking for stalemate.
ray
Given a coordinate and a step given in x y form, it returns an array of every space that can be reached by one or more instances of that step. The step here is in a single direction.For example, ray e4 1 1 would return f5, g6, and h7 on a Chess board. Used for generating an array of all spaces a piece may legally ride to. Useful when generating possible moves while checking for stalemate and the game includes hopping pieces, such as the Cannon.
rays
Given a coordinate and a distance given in x y form, it returns an array of every space that distance away, or any multiple of that distance away, from the space whose coordinate was given. For example, rays e4 1 0 would return the array of spaces in the e file or 4th rank besides e4. The spaces in the array may come from as few as one direction of movement, as in rays a1 1 1, or from as many as eight directions of movement, as in rays e4 1 2. Used for generating an array of all spaces a piece may legally ride to. Useful when generating possible moves while checking for stalemate and the game includes hopping pieces, such as the Cannon.
ride
Given a coordinate and a direction away from it given in x y form, it returns an array of all empty spaces and the first occupied space found while moving away from op1 in the direction defined by op2 and op3.
substr
Returns substring of op1, starting at op2, with 0 for the first character, and continuing for op3 spaces. When op2 is negative, it starts its count from the end of the string. If op3 is negative, that many characters will be omitted from the end of the string. If op3 is 0, the rest of the string will be returned.
what
Given a coordinate and two numbers, returns the contents of the space that is op2 files and op3 ranks away from the space whose coordinate is given in op1. Instead of two numbers, it may be given a logical direction by preceding the direction with logic, as in what a1 logic n.
where
Given a coordinate and two numbers, returns the coordinate of the space that is op2 files and op3 ranks away from the space whose coordinate is given in op1. Instead of two numbers, it may be given a logical direction by preceding the direction with logic, as in what a1 logic n.

Tetrary Operators

checkahop
Checks whether the move from op1 to op2 was a legitimate hopping move, consisting of leaps of op3 files and op4 ranks. A hopping move must hop over one screen. This operation checks only in the direction described. Negative numbers may be used for op3 and op4 to reverse directions. Positive directions go from a1 to h8 in Chess.
checkaleap
Checks whether the move from op1 to op2 was a legitimate leap of op3 files and op4 ranks. This operation checks only in the direction described. Negative numbers may be used for op3 and op4 to reverse directions. For example, "or checkaleap 2a 3c -1 2 checkaleap 2a 3c 1 2" would check whether the move from 2a to 3c was one a White Shogi Knight could make.
checkaride
Checks whether the move from op1 to op2 was a legitimate riding move, consisting of leaps of op3 files and op4 ranks. This operation checks only in the direction described. Negative numbers may be used for op3 and op4 to reverse directions. For example, "checkaride 9a 9d 0 -1" would check whether the move from 9a to 9d was one a Black Shogi Lance could make.
checkgrasshop
Checks the legality of a Grasshopper move. The Grasshopper is a fairy piece that moves and captures by jumping to the space immediately after an occupied space.
checkhop
Checks whether the move from op1 to op2, or vice versa, was a legitimate hopping move, consisting of leaps of op3 files and op4 ranks, or of op4 ranks and op3 files. A hopping move must hop over one screen. This operation checks symmetrically in all directions. Negative values for op3 and op4 have no special meaning, because only their absolute values are used. For example, "checkhop a4 g4 0 1" would check whether this move was a legitimate move for a Cannon in Korean Chess.
checkleap
Checks whether the move from op1 to op2, or vice versa, was a legitimate leap of op3 files and op4 ranks, or of op4 ranks and op3 files. This operation checks symmetrically in all directions. Negative values for op3 and op4 have no special meaning, because only their absolute values are used. For example, "checkleap b8 c6 1 2" would check whether this move was a legitimate Knight move.
checklongleap
Checks the legality of a Longleaper move, a piece found in Ultima that can capture multiple pieces by leaping over them.
checkride
Checks whether the move from op1 to op2, or vice versa, was a legitimate riding move, consisting of leaps of op3 files and op4 ranks, or of op4 ranks and op3 files. This operation checks symmetrically in all directions. Negative values for op3 and op4 have no special meaning, because only their absolute values are used. For example, "or checkride d1 g4 0 1 checkride d1 g4 1 1" would check whether this move was one a Queen could make.
inrange
Returns the first piece that can be found by making up to op4 leaps away from op1, each leap defined as op2 files and op3 ranks away. Returns false if no piece was found. Similar to insight but for short-range pieces. Used to indicate whether the King is in check from a short-range rider. See the cwda include file, used for Chess with Different Armies, for an example of its usage.
voidleap
Checks the legality of a voidleap from op1 to op2 in a direction defined by op3 and op4. This is a one space move that may pass over void, i.e. nonspace, identified in Game Courier with a hyphen, -, for the piece value. This is for the Voidrider from Voidrider Chess.
voidride
Checks the legality of a voidride from op1 to op2 in a direction defined by op3 and op4. This is a move that may carry the piece's space across void to a void location or leap across void. This is for the Voidrider from Voidrider Chess.

Hexary Operators

checkatwostep
Checks whether a two step move from op1 to op2 could be made with the first step of op3 files and op4 ranks, and the second step of op5 files and op6 ranks. The first step should be to an empty space. This operation checks only in the direction described. Negative numbers may be used for op3 and op4 to reverse directions. For example, "checkatwostep e2 e4 0 1 0 1" would check whether a piece stepped foward two spaces, as a Pawn can on its first move in Chess.
checktwostep
Checks whether a two step move from op1 to op2 could be made with a first step of op3 files and op4 ranks, and a second step of op5 files and op6 ranks, or if it could be made with a first step of op4 files and op3 ranks and a second of op6 files and op5 ranks. For example, "checktwostep b1 c3 0 1 1 1" checks whether the move from b1 to c3 could be made by a Knight in Chinese Chess.

Multiple Arity Operators

These operators pop off a multiple number of arguments. When the first element on the stack is an array, some of them will pop off the array, base its calculations on the elements of the array, then push the result onto the stack. Otherwise, most of them use the entire stack for their calculations. Some use only the stack, and one, fn, pops off only as many as it needs.

allequal
allfalse
alltrue
anyfalse
anytrue
If the value on top of the stack is an array, it is popped off, and the operation is performed on its elements. But if it is not an array, the operation is performed on every element in the stack, and the result replaces the old stack. allequal checks whether all elements of an array or stack are equal to each other. allfalse checks whether all elements are false. alltrue checks whether all elements are true. anyfalse checks whether any element is false. anytrue checks whether any element is true. Note that allfalse and anytrue always give opposite results for the same data, as do alltrue and anyfalse. Unlike the logical operators, these functions do not evaluate parenthesized expressions.
andsum
Does a binary AND on a set of integers and returns the result. They may be specified in an array or as a series of arguments.
array
Makes an array of all elements in the stack, empties the stack, then pushes the array onto the stack.
assoc
Makes an associative array out of all the elements in the stack, empties the stack, then pushes the array onto the stack. Instead of using all elements as values, it alternates between using an element as a key and as a value. For example, "set qq assoc b B r R" should set qq equal to the array ("b" => "B", "r" => "R").
checkapath
Checks whether a piece may go along a specific unobstructed path from op1 to op2 according to a path given in an array as op3 or given as the remaining arguments. The path should be described as a series of paired numbers, the first number giving the number of files to move, and the second giving the number of ranks to move.
checkpath
Checks whether a piece may go along a symmetrically defined unobstructed path from op1 to op2 according to a path given in an array as op3 or given as the remaining arguments. The path should be described as a series of paired numbers, the first number giving the number of files to move, and the second giving the number of ranks to move.
findpiece pattern [first|last] C1 ... Cn
Searches for the first or last piece in the given list of coordinates that matches the given wildcard pattern. The coordinates may be given as a list or as an array. Returns coordinate of found piece or false if piece is not found. If the first or last keyword is not specified, the default behavior is to find the first piece.
fn name arguments
The fn function calls a user defined function, specified by its name. The contents of the function determine how many arguments it requires. It pops off as many arguments as needed and pushes the result onto the stack. The function may be any Polish notation expression, even including other user defined functions. Recursive functions are possible with the onlyif or unless operators, but not with the cond operator.
fn (expression) arguments
When given an expression in an array instead of a name, it treats it as an unnamed lambda function. For example fn (* #0 #1) 5 7 will return 35. This allows you to create a function you will use in only one place without naming it. It also allows you to have the program construct functions before using them.
intersection
Returns the intersection of two arrays. The first array must be represented as an array. If the second argument is not an array, an array is made from the remaining arguments. So intersection (a b c d e f g h) (a e i o u) gives the same result as intersection (a b c d e f g h) a e i o u
list
If given an array, it returns a space-separated string containing the elements of the array. Otherwise, it join all elements of the stack into a space-separated string, empties the stack, and pushes the new string onto the stack.
logleap from to ...
Determines whether a piece at from can leap to a space at to by moving in one of the logical directions that follow. Logical directions are defined by the map and link commands. This function can work for both simple leapers and lame leapers. A simple leaper requires a simple direction, while a lame leaper requires a series of directions inside a pair of parentheses. This series of directions gives a path the lame leaper must follow to get to its destination. Its path must be unblocked, but it cannot stop anyplace on its path before its destination. For the sake of efficiency, this function can take multiple directions or multiple sets of directions, and test them in turn until a legal move to to is found.
logleaps from directions
Using a coordinate of a space and a list of logical directions, this returns an array of the spaces that can be reached by moving in those directions. This is useful for finding the moves a piece may possibly take when checking the effects of possible moves in a subroutine for checkmate or stalemate. It is like the leaps function but works with logical coordinates.
lograys from directions
Using a coordinate of a space and a list of logical directions, this returns an array of all spaces that can be reached by moving in straight lines from that space in the directions indicated. Like logride, it may also take a series of directions inside parentheses. It then follows these directions sequentially, pushing each space it finds into an array. It will repeat the last direction indefinitely, which is good for calculating the possible moves of winding pieces. To calculate the moves of limited-range riders, the last direction in a sequence should be a non-direction. Any alphabetic string should do, so long as it is not used for a direction. I recommend using stop to make your code more readable. This function is useful for finding the spaces straight riders, winding riders, and short-range riders may move to when using logical coordinates, which is useful in subroutines checking for checkmate or stalemate.
logride from to ...
Determines whether a piece at from can ride to a space at to by means of a sequence of leaps in logical directions. Logical directions are defined by the map and link commands. This function is good for simple riders, winding riders, short-range riders, winding short-range riders, and turning riders. A simple rider just needs a simple direction, which gets repeated until the destination is reached. A winding rider uses a series of directions given inside a pair of parentheses. A short-range rider uses a series of directions that end with a non-direction. The same direction can be repeated for a simple short-range rider, while different directions may be used for a winding short-range rider. A turning rider needs directions in a nested pair of parentheses. The directions before the second pair of parentheses indicate the beginning of a turning rider's move, and what comes in the inner pair of parentheses indicates how the turning rider continues to repeat its move.
match op1 op2 ...
When op2 is an array, indicates whether op1 matches any element in op2. Otherwise, it indicates whether op1 matches any following argument.
mates
Makes a reciprocal associative array out of all the elements in the stack, empties the stack, then pushes the array onto the stack. For each pair of elements, each element is made a key in the array for the other. For example, "set qq mates b B r R" should set qq equal to the array ("b" => "B", "B" => "b", "r" => "R", "R" => "r").
mergeall
Merges the elements of any number of arrays, as well as lone elements, into a single array without any duplicates. This function takes the rest of the line as input, discarding empty values, and adding lone values into an array before merging all the arrays into one.
orsum
Does a binary OR on a set of integers and returns the result. They may be specified in an array or as a series of arguments.
sub name arguments
Calls the named subroutine and sends the rest of the stack as the subroutine's arguments. Returns the value of the subroutine.
sum
Adds up all elements in the stack or in a given array, then pushes the result onto the stack.

Control Structures

If you plan to use GAME Code for more than simple tasks, such as for enforcing the rules of a game, you will need to know about control structures. These are ways of controlling which code gets executed when. Control structures may be used to conditionally execute code, to repeat code, and to better organize code by separating it into separate modules.

Conditionals

Conditionals evaluate expressions for truth or falsehood, and they execute certain code depending upon the value of the expression. Zero and empty values are taken to be false, while non-empty and non-zero values are taken to be true. All expressions should be written in recursive Polish notation.

if condition:
  code;
elseif condition:
  code;
elseif condition:
  code;
else:
  if condition:
    code;
  else:
    code;
  endif;
endif;

The if, elseif, else, and endif statements work together to create a series of tests that stops once one test turns up true. The if command is used for the first test of the series. All additional tests after the first are done with elseif. When the condition belonging to an if or elseif turns out to be true, the code following it gets executed. On reaching the next elseif or else statement, the code stops executing, and the program jumps to the endif statement. The else statement is used to introduce the code that executes when all the if and elseif tests have failed. The only statements that are required for this control structure are if and endif. The if statement must begin the structure, and the endif statement must end it. The use of elseif and else are optional.

When you follow an if by another if before reaching its matching endif, then you have created a nested set of if statements. The inner if will have a higher scope, and you will need to close it with its own endif before closing the outer if. Note that an else followed by an if will raise the scope, but elseif will not.

verify condition;
Used to conditionally exit a subroutine or the main program. When used at the base level of the program, it exits the program if the condition turns out false. When used within a subroutine, it returns from the subroutine. It will exit a subroutine or the program when its condition turns out to be false. It will allow the program to continue without interruption when it can verify that its condition is true. When used to exit a subroutine, it will return the value of false.

Switch and Case

switch expression:
  case label:
    code;
    break;
  case label:
  case label:
    code;
    break;
  case label label:
    code;
    break;
  default:
    code;
endswitch;

A switch-case block works as a computed goto for the body of code that fall between the switch command and the endswitch command. The switch command calculates the value of an expression, and when it is equal to one of the case labels, it jumps to the first line following the appropriate case label. It otherwise jumps to the line following the default label, assuming there is one, or to the end of the switch block. Since execution of lines continues until a break or endswitch command, you should normally place a break at the end of each separate body of code that belongs to a different case.

As shown to the left, multiple case statements can lead to the same body of code, and a single case statement may be used for multiple labels. Case labels may be numeric values, Boolean values, or strings, but they should not be arrays.

Although a series of case labels superficially resembles a series of if and elseif statements, and although they can sometimes be used for the same purpose, they are not at all the same thing. The case labels must be scalar constants, and their order does not matter, because this is a computed goto, not a series of tests. Although the PHP version of switch and case do work as a series of tests and allow expressions for cases, the version of switch and case used here is based on C, which allows only constant labels for cases. The reason for doing it this way is efficiency. A computed goto gets where it's going faster than a series of tests. If you ever do need to do a series of tests, if, elseif, and else do the job just fine.

For and Do Loops

The for and foreach commands are used with the next command to create finite loops that iterate over the elements of an array. The do and loop commands are used to create potentially infinite loops that repeat while or until a condition is true. The break, continue, and redo commands interrupt the usual execution of for and do loops.

for (key, val) array:
  if condition:
    continue;
  endif;
  foreach val array:
    if condition:
      redo;
    endif;
    if condition:
      break;
    endif;
    code;
  next;
next;

for x range 1 10:
  echo x;
next;

The for and foreach commands are presently the same command with different names. They are based on the foreach command in Perl and PHP, which iterates through the elements of an array. The array may be expressed by parentheses, which will be handled by the line parser, by inserting an array variable with a # in front, which will also be handled by the parser, or by including an expression that will evaluate to an array. One or two iteration variables may be given to the for or foreach command. When only one is given, it will hold the value of each array element. When two are given, they must be given as an array of two names, and the first will hold the key of each element, while the second will hold the value.

The loop will end when the end of the array is reached. But it may be stopped prematurely by the break command. A continue command will stop execution of an iteration and cause the loop to go to the next array element. If the end has been reached, it will stop. A redo command goes to the beginning of an iteration without going to the next array element. It could be used to create an infinite loop with a for loop. These three commands are normally used with conditions, though they could be used unconditionally.

Loops may be nested inside each other, as shown to the left. Each next corresponds to the closest previous for or foreach that doesn't correspond to another. In the example shown, the inner next goes with the foreach, while the outer next goes with the for.

The bottom example shows how a for loop can mimic the behavior of a for next loop in BASIC. The range operator used here creates an array of integers from 1 to 10, which the loop effectively counts through.


do while condition:
  code;
loop;

do:
  code;
loop until condition;

do:
  code;
  if condition:
    break;
  endif;
loop;

do until condition:
  if condition:
    redo;
  elseif condition:
    continue;
  endif;
loop while condition;

do:
  code;
loop never;

The do command begins a loop, and the loop command ends it. Each command can take a condition with either the while or until keyword. A do while loop, shown at the top left, acts as a while loop does in C or PHP, and do loop until, shown just below it, works as a do until loop does in C or PHP. The first is useful when your loop might not need to loop at all, and the second is useful when your loop should loop at least once. Unlike its counterparts in C and PHP, the do loop, which is based on the same construct in BASIC, has a richer syntax. It allows until at the beginning and while at the end, one apiece at each end, and even neither at each end. With no conditions at each end, it creates an infinite loop unless a break command is used to exit the loop. A break command will exit from the innermost do loop, for next loop, or switch statement it is found in.

As with for loops, the redo and continue commands may be used to redirect the flow of a loop. The redo command, borrowed from Perl, jumps back to the beginning of an iteration without checking any of the conditions of the loop. A continue command jumps to the bottom condition of a loop. So, a continue command would cause a loop to stop if the right conditions were met, but a redo command could create an infinite loop that disregards the conditions of the loop.

One more condition available at the end of a loop is never. This is useful when you want to raise the scope to use some local variables. Also, giving a while condition to do and a never condition to loop works like a simple if statement.


set i 0;
do while < i 10:
  code;
  inc i;
loop;

The style of for loop offered by C and PHP is not available in GAME Code, but its behavior can be duplicated with a do while loop as shown in this example. The initialization part of the for loop occurs just before the do command. The condition part of the for loop is the condition for the do while statement, and the increment part of the for loop is done just before the loop command. This example loops ten times, counting from zero to nine.

Including Files

include name [if condition]
Includes a file of GAME Code. The file must be stored in the /play/pbm/includes/ directory. It should have a single word name with a .txt extension. The name given to the command should match only the basename of the file. An optional condition may follow the name. If the condition evaluates to false, the file won't be included. This is useful for conditional inclusion of files that remains at the base level. When no condition has been given, or the condition evaluates to true, Game Courier will try to include the appropriate file. Unless the file is missing or has already been included, the included file will be converted into an array of program lines and appended to the end of the program. The included code will be executed immediately, then execution will be returned to the line immediately following the include command. The included code will not be encapsulated as a subroutine. So you may not call it again with the gosub command, but you may call any subroutines that you have stored in the include file. The include command may not be used in loops, subroutines, or conditionals. The only place to use it is in the Pre-Game code or other include files. Each include file will run at the main level of the program. This allows include files to be included in include files.
end
The end command unconditionally ends the program no matter where it appears. Game Courier automatically puts it at the end of the program it generates, and the developer never needs to put it in. The only code that will ever follow end is code added by the include command. The only real purpose of the end command is to end the program before the included code begins.
lib
This command is automatically prepended to any included code that gets added to the program. It identifies which include file the code following it comes from. It does nothing, and its only purpose is to make the code more legible when someone is reading it.
endlib
Marks the end of a library and returns execution to the line following the line that included it.

Restricting User Input

By default, a player can enter any type of move, any number of move primitives, and even lines of GAME Code as a single move. This freedom is great for allowing Game Courier to support almost any Chess variant, but when you're coding the rules for a particular game, restricting user input will make it much easier to write code that fully enforces the rules.

setsystem maxmove ##
Setting the value of maxmove to anything above zero limits the number of separate moves a player can enter as part of his fullmove. A value of 2 is suitable for Chess and most of its variants, because a second move is sometimes required for a promotion. A value of 1 is suitable for Chinese Chess and many other games without any promotions. A value of zero, which is the default, will allow an unlimited number of separate moves.
ban
The ban command bans certain commands and types of moves from the moves entered by players. It has no effect on the other code in a program. Any GAME Code command following the ban command is banned from user input. Besides the names of commands, ban accepts these keywords:
ban none clears the banlist, so that nothing is banned.
ban commands bans all GAME Code commands and subroutines from user input except for resign and drawn.
ban allmoves bans all the move types described with the keywords listed below. It is a shortcut to typing them all in. The use of this keyword should be followed by the allow command to make some exceptions.
ban captures bans captures by displacement, which are of the form "C1-C2" or "P C1-C2". It is useful for Checkers, in which pieces capture only by jumping over each other.
ban changes bans changing an arbitrary piece to another, of the form P-C1, where C1 is occupied, and its occupant was not the last piece to move. Does not ban promotions.
ban deletions bans moves that would remove a space from the board, which are of the form "-C1".
ban drops bans dropping a captured piece onto an empty space, of the form P*C1, as is done in Shogi and related games but not in Chess or most of its variants.
ban freedrops bans dropping a new piece onto an empty space, of the form "P-C1". Free drops are used in Go but rarely used in Chess variants.
ban hostages bans hostage exchanges, of the form "P-p" or "p-P", which are used mainly in Hostage Chess.
ban moves bans moves from one space to another, which are of the form "C1-C2" or "P C1-C2".
ban offboard bans any move to an off-board location within the grid the board has been defined in. Useful for non-rectangular boards.
ban promotions bans promoting to another piece the piece that just moved.
ban suicides bans moves that simply remove a piece from the board, which are of the form "C1-" or "@-C1".
allow keyword/command number [keyword/command] [number] ...
The allow command makes selected exceptions to the commands and types of notation banned by the ban command. It accepts a series of word/number pairs. The word should be a GAME Code command or one of the keywords described under ban. The number should be the ordinal value of a single move in a full move. After a command or type of movement has been banned, this command makes exceptions for selected parts of a full move. For example, allow moves 1 captures 1 promotions 2 allows the first part of a full move to be a piece move, capturing or non-capturing, and it allows the second part to be a promotion. This is suitable for Chess and many of its variants.

Functions and Subroutines

GAME Code allows you to make and use your own functions and subroutines. The general difference between them is that functions are meant to return values and should have no side effects, whereas subroutines are meant mainly for producing side effects and don't have to return values. But this distinction gets blurred, because subroutines may return values and don't have to produce side effects, and functions may produce side effects by calling subroutines that do produce them. So let me make the distinction more concrete. In GAME Code, a function is a one-line Polish Notation expression that includes placeholders for arguments, whereas a subroutine is made up of lines of code that fall between an introductory sub command and a concluding endsub command.

Subroutines

The sub and endsub commands are used for defining a subroutine. The gosub command is used for executing a subroutine, and the return command may be used for exiting a subroutine and returning a value. The verify command will also exit a subroutine. A subroutine is like a function, but, with the exception of arguments, it uses global variables by default, and it can be treated as nothing more than a body of code that can be reused.

Nevertheless, a subroutine can behave as a function, and subroutines can be made recursive. The local and my commands can create local variables, and the static command can create static variables, like what are commonly used in the functions of other programming languages. The arguments passed to the subroutine are available in two ways. First, the arguments are copied to the variables listed as parameters of the subroutine. These variables all have local scope. But this might not yield all the arguments, since it is possible to pass more arguments than a subroutine's parameter list is ready for. To handle a variable number of arguments, all arguments passed to a subroutine are also available in an array called subargs. Note that subargs has my scope, not ordinary local scope. Values passed through the parameter list are visible in subroutines called from the subroutine, so long as the names don't get reused, but the subargs array holds arguments only for the subroutine call it was created for.

sub name parameters
Begins the definition of a subroutine and lists a set of parameters for argument values. A subroutine is the code from the sub command to the closing endsub command. A subroutine name may not match any command name. All arguments passed to a subroutine are treated as local. All code in a subroutine is skipped over unless it is called with a gosub. When a subroutine uses the same label as a previous subroutine, the label gets transferred to the new subroutine.
endsub
Ends the definition of a subroutine. If the subroutine was being executed because of a gosub, execution gets returned to the line immediately following the gosub.
return
Exits from an active subroutine, returning to the line immediately following the gosub, and optionally returning a value. It is not required for exiting a subroutine, since endsub will do that when no return is present, but it may be used for exiting a subroutine early or for passing a value from the subroutine.
verify
Verifies that the expression following it is true. If it is, it allows the subroutine to continue. If it is not true, it exits the subroutine, returning a value of false.
gosub label arguments
Goes to a subroutine at a different location. The subroutine must have been defined before the gosub line. The arguments are passed to the parameter list of the sub command. Any value returned by the subroutine will be placed in the variable RESULT. The gosub command is not always necessary. When a subroutine name appears as the first word in a line of code, the subroutine will be called so long as the name is unused for pieces and spaces. But since it is useful to name subroutines after pieces, the gosub command remains useful. The Polish notation calculator has a sub operator that behaves like gosub except that it directly returns the value of the subroutine and may be used in expressions. It may be used in conditionals, loops, and the setting of variable values.

User Defined Functions

copyfn newname oldname
Creates a clone of a function with a new name.
def name expression
The def command lets you create a one-line function that can be accessed with the fn operator of the Polish notation calculator. The first argument is the name of the function, and the remaining arguments define the function. The function's name should not match any built-in function name used by the Polish notation calculator. Otherwise, you will get unwanted results. The function should be defined as a Polish notation expression. It may also include placeholders for arguments. Each placeholder should begin with the number sign and be followed only by digits, such as #0, #2, etc. The number following the number sign indicates which argument it is a placeholder for. #0 is a placeholder for the first argument, #1 for the second argument, etc. The highest numbered placeholder should not exceed the number of different placeholders that you use. So, for example, if you use #4 as a placeholder, you should also include #3, #2, and #1.
fn name arguments
This is an operator that can be used in any Polish notation conditional expression. It lets you use a user defined function, specified by its name, or provided namelessly as an array. Which it does depends upon whether its first argument is a string or an array. The latter allows the use of nameless lambda functions. The contents of the function determine how many arguments it requires. It pops off as many arguments as needed and pushes the result onto the stack. The fn operator may be used within the function definition to call itself recursively.
and condition
or condition
nand condition
nor condition
Besides their usual behavior of evaluating a logical relation between two operands, these can also evaluate a logical relation with only one operand. If we look at the truth table showing the truth values for each of these logical operations, we can see that in some cases, the value of one operand is enough to determine the truth value:
#0 | #1 | and | or | nand | nor
 T |  T |  T  | T  |  F   |  F
 T |  F |  F  | T  |  T   |  F
 F |  T |  F  | T  |  T   |  F
 F |  F |  F  | F  |  T   |  T
 
For and, a false value for either operand makes the whole expression false, while for nand, which is equivalent to not and, it makes the whole expression true. For or, a value of true for either operand makes the whole expression true, while for nor, which is equivalent to not or, it makes the whole expression false. Whenever one value is enough to determine the value of the logical expression, it breaks out of the whole expression it is evaluating, returning as its value the value of the logical expression. For example, == 77 * 4 9 and != 7 7 or != 8 9 would evaluate != 8 9 first and return true without evaluating the rest of the expression. So, for a false value, and breaks out with a value of false, and nand breaks out with a value of true, while for a true value, or breaks out with a value of true, and nor breaks out with a value of false. Otherwise, these operators simply allow the expression to continue without adding anything to the stack. For example, == 77 * 4 9 and != 7 7 or != 8 8 first evaluates != 8 8 to false, continues to != 7 7, which is evaluates as false, and then since the operator is and, it returns false without continuing with the rest of the expression. By returning nothing when it doesn't break, it allows multiple instances of variable arity operators in the same line. Consider an expression like or match insight #k 0 1 R Q match insight #k 1 0 R Q. Since match will use any arguments available, this would not work right. Instead of returning true if either match is true, or false otherwise, it would add the value of the right-most match to the list of operands for the left-most match, which would return true only if the left-most match is true. But by putting the or between the two match expressions, the expression match insight #k 0 1 R Q or match insight #k 1 0 R Q gives the correct results.
onlyif condition expression
unless condition expression
Originally designed to enable recursion, these functions are more efficient replacements for cond. While cond takes three arguments, each of these takes only two. For all three, the first argument will be a condition. Using the same three expressions, here are examples of all three:
print cond bitand 1 5 "Odd" "Even";
print "Odd" onlyif bitand 1 5 "Even";
print "Even" unless bitand 1 5 "Odd";
The condition bitand 1 #0 is a test for whether a number is odd, and all three expressions will print the word "Odd". The expressions using onlyif and unless should be read from left to right. The first of these will print "Odd" only if 5 is odd. Otherwise, it will print "Even". The second will print "Even" unless 5 is odd, in which case it will print "Even". Note that the word preceding the operator, "Odd" in the case of onlyif or "Even" in the case of unless, are not parts of the expression evaluated by the operator. Instead of simply returning values, these two control the flow of the function. The onlyif operator allows the function to continue only if the condition is true, breaking out if it is false, and the unless operator allows the function to continue unless the condition is true, in which case it breaks out. When it does allow the function to continue, it discards the values of both expressions following it. When it doesn't allow the function to continue, it breaks out, returning the value of the second expression following it, or, if there is no second value, the boolean value false. By having a function call itself to the left of one of these operators, you can create a recursive function that does not fall into an infinite loop.

Lambda Functions

A lambda function is a nameless function that is defined on the spot. A lambda function is written and stored as an array, but to tell arrays and lambda functions apart, I have created a separate type for them. To create a lambda function object, write your function inside parentheses, or inside quotation marks, and place the keyword lambda in front of it. For example:

set cube lambda (* * #0 #0 #0);
print fn #cube 5; // Prints 125
set square "* #0 #0";
print fn #square 6; // Prints 36

Some built-in functions are designed for doing advanced operations with lambda functions.

aggregate lambda_function array
For each element of the array, this runs the lambda function, using the array element as an argument, which is recognized within the lambda function as #0. If the array element is itself an array, its first element is #0, its second #1, and so on. Each time the lambda function produces a nonzero value, it pushes that value into an array. When it's finished, it returns this array. Note that this function ignores array keys, and the array it returns is an indexed array, not an associative array. It is most useful for creating arrays with different values than the original array.
filter lambda_function array
This runs the lambda function on each element of the array, and it returns back a subset of the original array, complete with the same keys and values, just in case the original array was an associative array whose keys need to be preserved. To determine which elements to include in this subset, it uses the lambda function to filter out elements. The lambda function normally takes two arguments, #0 for the key and #1 for the value. When the value is an array, its first element is #1, its second #2, and so on. Since the filter function will return the original key and value when the lambda function has a true value, there is no need to include the return value in the lambda function. This can be used, among many other things, for finding spaces with certain pieces on them. For example, set a filter lambda (islower #1) spaces; will return an associative array of all the spaces with Black pieces.
allfalse (or nonetrue) lambda_function array
alltrue lambda_function array
anyfalse lambda_function array
anytrue (or any) lambda_function array
Like aggregate above, these go through an array element by element, running the function on each element, but instead of returning an array, they return true or false, and instead of always going through the whole array, they break out early as soon as the return value can be known. allfalse (or nonetrue) will return false if any function call has a true result, otherwise returning false. alltrue returns false if any function call returns false, otherwise returning true. anyfalse returns true if any function call has a false result. anytrue (or any) returns the argument for the first function call with a nonzero result, which will be interpreted as true in any conditional expression, otherwise returning false. For example, set k any lambda (#0 onlyif == space #0 k) spaces will return the position of the Black King.

Since you can turn a string into a lambda function, it is possible to write code that creates specialized lambda functions.

def doublesquare fn lambda join "* #0 " #0 + #0 #0;
print fn doublesquare 5; Prints 50

In this example, the #0 inside quotation marks is a parameter of the lambda function, but outside parentheses, it is a parameter of the doublesquare function. What this does is add a number to itself, then passes the doubled number to a lambda function that multiplies it by the original number. Breaking it down, it looks like this with 5 as the argument:

lambda join "* #0 " #0 + #0 #0
lambda "* #0 5" + 5 5
(* #0 5) 10
(* 10 5)
50

Recursion

A recursive function or subroutine is one that calls itself until a certain condition is met. When writing subroutines, it is more efficient to write your code in terms of loops, but that isn't an option for functions. First, let me point out that you should not use cond for recursion. Since it evaluates all arguments before evaluating its condition, using cond would create an infinite loop. Take this, for example:

def ODDRAND cond bitand #0 1 fn ODDRAND rand 1 100 #0

It looks like this will return any odd input and otherwise pick random numbers between 1 and 100 until it picks an odd number, which it will then output. But it won't. Since it starts evaluation from the end, it will repeatedly call itself without ever finishing, which will create an infinite loop. To avoid this, use one of the following in place of cond: onlyif, unless, and, or, nand, or nor. Here's an example that will do what the first was intended to do:

def ODDRAND fn ODDRAND rand 1 100 unless bitand #0 1 #0;

Here is another example of recursion. This function will calculate the factorial of a number. A factorial is the product of an integer times every postive integer less than it until 1. For example 5! = 5*4*3*2*1 = 120.

def fac * #0 fn fac dec #0 unless <= #0 1 1;

In each of these examples, each function is being told to call itself unless a certain condition is true. Here's how it works. It evaluates each expression backwards. First, the unless operator takes two values. The first will be a condition, and the second will be a value that it will return if it breaks from the function without completing it. It will allow the function to continue unless the condition following unless is true. In that case, it will return the value passed to it as its second argument. Unlike most operators, unless adds nothing to the stack. If its condition is false, it lets the function continue, and it discards the values that were passed to it. This brings it to the part where it calls itself. It will keep calling itself until the condition following unless is met. This will be the first time that any call to the function returns a value. Using this value, the function will complete itself and return a value. This same process will repeat until every instance of the function called returns a value. Finally, the first instance of the function to be called will be the last to return a value, and that value will be the one returned within the context of the rest of the program.

To better illustrate what is going on, let me rewrite the factorial function as a subroutine.

sub fac num:
  if <= #num 1:
    return 1;
  else:
    return * #num sub fac dec #num;
  endif;
endsub;

And since loops are more efficient than recursive subroutines, let me rewrite this as a loop:

sub fac num:
  set product 1;
  do until <= #num 1:
    set product * #product #num;
    dec num;
  loop;
  return #product;
endsub;

Optimization

Why Optimize?

Since I began programming computers, there has been a rapid evolution in their capabilities. In the early days, it was important to optimize every bit of code, because the computers then had very limited memory and very slow processors. With today's fast computers, optimization might not seem as important. But it can still matter. Consider that interpreted languages are slower than compiled languages. Any program not written into machine code has to be translated into machine code. A compiled language, such as C, saves time by doing the translation only once before running the program. An interpreted language, such as BASIC, does the translation each time it runs a program. Now consider that GAME Code is not only an interpreted language but one that it written in another interpreted language. GAME Code is written in PHP, which is written in C, which is already compiled into machine code. So, a GAME Code program will be slower than a PHP program, which will itself be slower than a C program. Furthermore, PHP imposes a time limit on how long it waits for a page to load. When a page does not load fast enough, PHP will stop execution of it and complain that it is taking too long. This is yet another reason to optimize code for speed.

Minimizing Time Hogs: Where to Check for Win/Loss/Draw Conditions

Let's start with one of the biggest processing-time hogs. Checking for check, checkmate and stalemate takes considerably longer than checking whether a single move is legal. It involves checking whether several different pieces can attack the King, it explores the possible moves available to the King, and it checks the legality of various potential moves. If all of this gets done after every single move, it will eventually slow Game Courier down enough to exceed PHP's time limit on loading a page. While it should be done after every move, it only has to be done once after each move. By placing code for check, checkmate, and stalemate in the Post-Game sections, it gets executed after each player moves. By preventing any move that leaves a player in check, checkmate, or stalemate, it allows us to assume that no prior move in the game left either player in check, checkmate, or stalemate. Furthermore, by using won, lost, and drawn commands to mark the end of the game by checkmate or stalemate, it prevents further moves from being made after the game ends. So the Post-Game sections are the only place where code is needed to check for check, checkmate, stalemate, or any other win/loss/draw conditions, and it saves a great deal of processing time to not place this code anywhere but there.

Checking the Legality of a Move: If-Elseif, Switch-Case, or Functions and Subroutines

When you want to check the legality of a move, the code used to evaluate the legality of the move will be determined by whatever piece was moved. There are three main ways of doing this. One is with a series of if and elseif statements, testing whether it is one piece after another. This is inefficient, because it evaluates multiple expressions until it finds the code for the piece that moved. By using switch and case, you can avoid evaluating multiple expressions, because it works as a computed goto. The switch statement evaluates the expression once and goes directly to the appropriate case statement. But even more efficient than this is the use of functions. GAME Code lets you use variables to specify function names. By defining functions named after the piece labels, you can use the label for a piece to call a function that evaluates whether the piece has made a legal move. In some cases, subroutines should be used instead of functions, because moving a piece may have side effects, such as moving the Rook while castling or taking a Pawn by en passant. In many of my include files, perhaps all of them, I have provided functions and subroutines for evaluating the legality of moves by different pieces. Besides the improvement in efficiency, this has the benefit of allowing you to reuse the same code in multiple places, such as a subroutine for telling whether the King is in check. This is done in some of my include files, such as xiangqi and chess2.

Functions or Subroutines

In general, functions are faster than subroutines, because a function is a single line of code, whereas a subroutine is multiple lines of code. But it also depends on what your code is doing. For repetitive tasks, the looping structures available to subroutines are considerably faster and more efficient than having a function do the same thing by recursion. In tests I ran, a recursive function couldn't iterate any more than 107 times before hanging indefinitely, and it took between 4 to 5 times as long as a for loop took to count to 107. Bear in mind that this reduction in speed is due to the recursion, not to functions being slower. Another test revealed that subroutines handle recursion even more poorly than functions do. A recursive subroutine could iterate no more than 52 times, and it took longer than the recursive function iterating 107 times. In another comparison between functions and subroutines, I have programmed Chess in two different ways. One way tells whether the King is in check with a function that checks the spaces the King could be attacked from for the pieces that could attack it from those spaces. The other way tells whether a King is in check with a subroutine that loops through the enemy pieces, testing whether any can legally move to the King's space. In tests I ran of the time each takes, the function proved much faster than the subroutine. Functions and subroutines each have their place. Functions are good for tests that just need to return a value. Subroutines are good when you need to change the board, write to the screen, loop through values, or set values of flags, variables, or constants. Subroutines are also easier to debug and understand. The subroutine I just mentioned has its uses for Chess variants with pieces different from those in Chess, such as Cannons, and it doesn't have to be rewritten for games with different pieces. In contrast, the function used to tell whether the King is in check is designed specifically for the pieces in Chess and must be rewritten for games with additional pieces. Customizing your code to a specific game can speed it up but slow down your development. You have to balance which is more important.

Optimizing Functions

When checking the legality of a move with a function, you can optimize your code by making use of the built-in operators designed for this purpose. Note that operators for checking the legality of a certain type of move normally comes in two forms. For example, checkaleap will check the legality of a single leap, whereas checkleap will check the legality of any leap of the specified distance away. The first gives you precision when you need it, while the second is more efficient when it is all you need to do the job. To illustrate the difference, here are two functions for checking the legality of a Knight move:

def N checkaleap #0 #1 2 1 or checkaleap #0 #1 -2 1 or checkaleap #0 #1 2 -1 or checkaleap #0 #1 -2 -1 or checkaleap #0 #1 1 2 or checkaleap #0 #1 -1 2 or checkaleap #0 #1 1 -2 or checkaleap #0 #1 -1 -2;
def N checkleap #0 #1 2 1;

The second does the same job as the first but is much more efficient. To learn more about optimization, let's consider how the first could be made even less efficient. Notice that each checkaleap statement is separated by an or. GAME Code's functions use prefix notation, which always puts the operator to the left of the operands. So you might expect the function to look like this instead:

def N or or or or or or or checkaleap #0 #1 2 1 checkaleap #0 #1 -2 1 checkaleap #0 #1 2 -1 checkaleap #0 #1 -2 -1 checkaleap #0 #1 1 2 checkaleap #0 #1 -1 2 checkaleap #0 #1 1 -2 checkaleap #0 #1 -1 -2;

This function would calculate the value of every checkaleap statement before doing any logical operations. The one that separates each pair of checkaleap statements with an or is more efficient, because it takes advantage of the or statement's ability to break out of an expression and immediately return a true value when it is given a single operand with a true value. So it will evaluate checkaleap statements only until it finds one that is true, then the function will immediately return true without evaluating the rest.

The general principle here is to make a function do no more than is necessary to calculate its value. Taking advantage of the short-circuiting ability of logical operators helps with this. It also helps to write a function to perform easier operations before more complex operations. Consider this function for a Clodhopper move from Storm the Ivory Tower:

def C cond cond empty #0 (not capture) (empty #1) (checkride #0 #1 1 1 or checkride #0 #1 0 1) (checkhop #0 #1 1 1 or checkhop #0 #1 0 1) and fn legaldir #0 #1;

Each piece in this game is restricted to moving in the directions indicated by arrows on the squares. The first thing this function does is calculate whether the move is in a legal direction with "fn legaldir #0 #1". Remember that GAME Code begins evaluation of a function from the end, not from the beginning. If its not in a legal direction, that's all it needs to know that the move is illegal, and it avoids calculating whether the move is otherwise legal. When and gets a single false value, it short-circuits the expression and returns a false value.

As a game progresses, it will be filled with a series of legal moves, and it will run the code for checking the legality of these moves each time it runs through the code. Although you could place this code in the Post-Game sections, it is not recommended, because there may be side effects to some moves, such as en passant capture, promotion, moving another piece to a different location, etc. So this code should be placed in the Post-Move sections. What you can bear in mind is breaking out of a function early is not so useful in contexts where the function will rarely have cause to break out early. For example, the chess include file has code for testing whether the King is in check from a specific piece. This code has been designed to break out early if the King is in check, but most of the time, the King will not be in check, because the code will come at the end of a legal move that did not leave the King in check. In this example, the first function is from the chess include file, and the second might be a faster way to accomplish the same thing when the King is not in check, because the match command handles all comparisons at once:

def KNIGHT check what #0 1 2 check what #0 -1 2 check what #0 1 -2 check what #0 -1 -2 check what #0 2 1 check what #0 -2 1 check what #0 2 -1 check what #0 -2 -1 target #1;
def KNIGHT match #1 what #0 1 2 check #0 -1 2 what #0 1 -2 what #0 -1 -2 what #0 2 1 what #0 -2 1 what #0 2 -1 what #0 -2 -1;

Variables, Constants, and Flags

Variables of higher precedence are accessed faster than variables of lower precedence. To maximize the speed at which variables are accessed, which might shave microseconds off the speed of an operation, use my scoped variables in your subroutines. Just bear in mind that my scoped variables cannot be accessed by other subroutines. Also, constants are accessed faster than variables. If you use a value that will never change, you can speed up your code a little bit by using a constant for it. Flags are accessed just as fast as constants. When all you need is a boolean value with global scope, a flag is your best choice.

Speed Benefits of Prefix Notation

Let me also point out some of the optimizations built into GAME Code. Functions make use of prefix notation, which is more optimized than the more usual infix notation. Prefix notation puts operators in an unambigous order, so that matters of precedence never arise. In contrast, infix notation puts operators in an ambiguous order that gets resolved either by precedence of operators or by parentheses. Consider the infix expression 4 + 5 * 6. Should it be (4 + 5) * 6, which is 54, or 4 + (5 * 6), which is 34? Parentheses disambiguate these two expressions, and so does order of precedence. Since multiplication precedes addition, it should be evaluated as 4 + (5 * 6). The thing is that this disambiguation is an extra step that prefix notation is able to avoid. The usual way for a computer to handle infix notation is to translate it into postfix or prefix notation and go from there. Working directly with prefix notation avoids this step. Prefix notation represents the two expressions above as * + 4 5 6 and as + 4 * 5 6, and it does not include any ambiguous expression that might be either one. Besides being more optimized than infix notation, prefix notation is not so unfamiliar to computer programmers. It is commonly used in Lisp and related languages, such as the language used for Zillions of Games, and it is the usual way to call functions in most programming languages.

To Optimize or not to Optimize

While optimization is important, it isn't always best to favor optimization over other considerations, such as development time, ease of understanding your code, and the ability to debug your code. Subroutines can sometimes be easier to write, understand, and debug. These are reasons for favoring subroutines even when functions would be more efficient. Generally, a function should be limited to a single easily understood task, such as checking the legality of a single move by a specific type of piece. You might make your code more efficient with long, complex functions, but it could also make your code harder to read and understand. In the end, use your judgement.

Special Considerations

Any given preset can be used for either a game or a fairy chess problem. Unlike a regular game, a fairy chess problem will not begin with the usual setup coded for use with the game. To accommodate both games and problems, make the same information about the game available whether it is a game played from the beginning or a problem that starts with a different setup. In particular, you should take these steps:

  1. If variables are used to keep track of the positions of the kings in the game, set these variables to the result of a search, such as set k findpiece k spaces; and set K findpiece K spaces;.
  2. If you use variables to keep track of which pieces a pawn may promote to, explicitly set their values to what they should be instead of calculating them from which pieces are on the board in the opening setup.

Debugging

Whenever your code produces a syntax error, you will get an error report and a full, formatted listing of the GAME Code program Game Courier has generated. This will provide useful data on what you need to fix.

If you know that something is wrong but Game Courier is not giving you any error messages, you can force it to show you the full listing of a program by adding "&showcode=true" to the URL.

dump
Prints out every user variable, organized by scope and subroutine.
echo message
The echo command may be used in your code to print messages. This can be used for printing the values of variables. Precede any variable with the pound sign, #, so that it gets preprocessed into its value. Note that the echo command is limited to 64 uses in a program. This is a security precaution to prevent its use in infinite loops.
printr variable_name
Prints out the contents of the named variable. Its name should not be preceded by a # sign unless you are using one variable to name another.

Tutorials

A language reference is useful, but it doesn't go into how to do things with the language. That's what tutorials and examples are for. Let's start with the tutorials I have written. These cover many of the basic things you want to do for any game you program, such as enforcing rules and displaying legal moves. Dates are given after each, and, of course, the more recent tutorials are more relevant.

Programming Unusual Topologies with Logical Coodinates

When I decided to work on programming Circular Chess, the need for a new method arose. The previous methods, from early code in Anatomy of a Preset to the chess2 methods, all used the same built-in functions to evaluate piece movement. These functions all worked on the assumption that the board was a fixed plane of coordinates that extended outward from an origin point. This worked well enough for two-dimensional games whose positions can be plotted with Cartesian coordinates, but it doesn't work so well for three-dimensional games and other games with unusual topographies. In Circular Chess, the ranks are circular, looping back into themselves, so that the a and p files are adjacent. A King, for example, should be able to move directly from one of these files to the other. But in the usual mathematical way of representing boards, these files are at opposite ends, and the functions for checking piece movement would have to get more complicated, perhaps even being replaced by subroutines. Instead of doing that, I wrote some commands and built-in functions for using logical coordinates. If you have programmed games for Zillions-of-Games, then you will already be familiar with logical coordinates. Instead of being represented by their distance from an origin point, logical coordinates are abstractions whose relations to other coordinates are determined by defining directions from them and where those directions lead. In Circular Chess, for example, I might say that moving clockwise from a1 leads to b1, and moving counterclockwise from a1 leads to p1. I could actually call these directions by any names I choose, such as north and south, or forward and backward. The commands I wrote for defining the logical coordinates on a board are called map and link. The map command creates a large set of logical coordinates at once. It is useful for quickly creating logical coordinates whose relations match the usual mathematical coordinates. The link command defines directions between individual pairs of coordinates. Here is how I defined the cooordinates in Cicular Chess:

map n 0 1 s 0 -1 w -1 0 e 1 0; // Orthogonal directions
map nw -1 1 ne 1 1 sw -1 -1 se 1 -1; // Diagonal directions
map nne 1 2 nnw -1 2 sse 1 -2 ssw -1 -2; // Hippogonal directions
map nee 2 1 nww -2 1 sww -2 -1 see 2 -1; // Hippogonal directions

Note that I didn't use the link command. Instead, I extended the file labels (listed in the Files field) to start repeating themselves. For it to map the hippogonal directions for Knight moves, I ended it with the first two files it began with. If I hadn't extended it, these commands would have worked for defining the directions normally used in Chess. If you were programming a 3D game, you could add additional directions, such as u (for up), d (for down), un, us, ue, uw, dn, ds, de, dw, une, dne, etc. To do this, you would need to establish the distance between planes and factor that into your direction definitions. Assuming that planes are 8x8 with a distance of 9 ranks between them, here are some examples:

map u 0 9 d 0 -9; // Straight up and down
map un 0 10 us 0 -8 uw -1 9 ue 1 9; // Slanted up directions
map une 1 10 unw -1 10 use 1 -8 usw -1 -8; // Diagonal up directions

Having a distance of 9 between 8x8 planes allows you to place barriers between them of non-space, indicated by hyphens in the FEN code. If you place no barriers between them, then you can unlink planes with the unlink command.

Examples

Besides learning the GAME Code language from this reference manual, you can gain deeper knowledge of it by studying actual examples. I have programmed several games in this language, and the code is available for you to study and learn from. The code for a game is normally split between the preset itself, which focuses on the rules of the specific game, and an include file, which includes various functions and subroutines that will be used by the GAME Code program. These frequently include functions for evaluating the legality of a piece's move, functions or subroutines for spotting check, and subroutines for castling, checkmate and/or stalemate. Many games can use the ones written for Chess, while other games require specialized versions.

For the basics, study these presets and their include files:

  • Chess and its include file chess.
  • My alternate Chess preset and its include file chess2 - This is an alternate way to program Chess that can be easily adapted to more Chess variants than the other way of programming Chess.
  • Chinese Chess and its include file xiangqi.
  • Shogi and its include file shogi.

For examples of presets that make use of include files designed for other games, study these presets and their include files:

For examples of more advanced programming techniques, study these presets and their include files:

For additional examples, look at the other include files in the includes directory and also study the presets that use them. You can normally tell what game an include file is for by its name.


Written by Fergus Duniho
WWW Page Created: 12 August 2003.