Game Courier supports many different games. Here is one picked at random:
Dr. Who Chess - Variant based on the popular TV seiries

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 presets for Game Courier. If all you want to do is use already made presets, 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.

Customizing a Preset

If there is already a preset for a game you want to play, but you would like it to use different graphics, then all you need to do is to create a customized version of the preset for your own use. You can reuse a customized preset by saving an URL or a short form that will be given to you in Customize mode.

The first step to customizing a preset is to select one and click on the "Customize" button while in Menu mode. This will put you in Customize mode. While in this mode, you will be able to change parameters that affect the appearance of the preset. These same parameters can be edited in Edit mode, but for brevity's sake most will be described only in this section. Although you could use Edit mode to create customized clones of existing presets, 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 preset by its author, 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 preset 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. It is less confusing for the average user.

The parameters you can change in Customize mode are as follows:

Shape

This field controls the shape of the cells or the board. The options are square, horizontal hexagonal, vertical hexagonal, circular, custom grid, and custom coordinates. When you're customizing a preset, you will rarely need to change this unless you are changing to or from the custom grid shape. So, as far as customizing goes, you don't need to know a lot about the differences between the available options. They will be described in greater detail in the section on Edit mode. One important thing to know here is that the combination of shape and rendering method (described in the next section) determines how the board is made. This table shows how the board is made for each combination, and it blacks out any combination that doesn't work.

ASCIITableCSSPNG, GIF or JPG
SquareDraws ASCII diagramGenerates board from scratch; draws as tableUses background image for board, or generates board from tile imageGenerates board from scratch; draws as image
Horizontal HexagonalGenerates board from scratch; draws as table with auto-generated images for cell backgroundsUses background image for board
Vertical Hexagonal
Circular
Custom GridUses background image for board, or generates board from tile image
CustomUses background image for board

Rendering Method

This controls the method used for rendering the board. The available methods are these:

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 sole advantage of this option is that it will 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.

HTML Table

This method renders boards as HTML tables. It can be used for square boards and both types of hexagonal board, but it cannot be used with custom grids or custom coordinates. It is most naturally used for boards with square spaces. Each space is just a table cell, and the color of a space is rendered as the cell's background color. It can also be used for hexagonal boards. Since table cells are rectangular, it renders hexagonal boards by generating and arranging small PNG images that it uses as background images, by means of CSS, for table cells. So, this method for generating hexagonal boards requires a browser that supports both PNG images and CSS.

This method is recommended for square boards, because it uses minimal graphics, making it quicker to download, and it is compatible with most browsers. But it is not recommended for hexagonal boards. For one thing, it limits the colors you may choose from, because it builds a hexagonal board from multi-colored PNG images with standardized names. Also, the result doesn't always look so good, spaces come in only a few standard sizes, and the coordinates cannot always be written close to the actual board. But mainly, the PNG method, which I developed after this method, is much better suited for hexagonal boards. It doesn't require CSS, it can write all coordinates near the board, spaces can be any color from #000000 to #FFFFFF, spaces are sized to fit the pieces, and it gives you only one file to download.

CSS Code

This method makes use of Cascading Style Sheets. Known by the abbreviation CSS, this is available on any modern web browser, such as Internet Explorer, Firefox, Safari or Opera. This method uses a background image for the board, and it positions pieces by means of absolute positioning. It can be used with every board shape, but it does not offer the advantage of automatically generating boards from scratch. It always requires some background image. There are two ways of using this method. One way is to use an image of the whole board. This is useful for games such as Smess, Chinese Chess, or 3D Chess, whose boards cannot be generated by any method Game Courier has at its disposal. The other way is to use a small image that will tile. The most useful tile image is a square of four square spaces. This can be used to generate square boards of various sizes and shapes. But this technique is not useful for generating hexagonal boards. To use the CSS method for a hexagonal board, you would need an image of the whole board. When you're using a colorful JPG image for a board, the CSS method is better than the JPG method, because it will reuse the same images, allowing download time to speed up once all the graphics are cached.

PNG, GIF, or JPG Image

Each of these methods renders a board as a graphic image file. The available formats are PNG, GIF, and JPG, and the rendering method chosen determines which to use. The board is generated by PHP functions and stored in a temporary directory. These methods can be used with any board shape except custom boards. They can automatically generate square, hexagonal, and circular boards from scratch, and they can make use of background images with the Custom Grid shape. These three methods function almost identically, differing mainly in the type of file generated. The GIF and PNG methods are good for small-palette images, while the JPG method is good for true color images.

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.

JPG Images

The JPG format supports true color images well. It is usually the best method to use if you need to resize a board or use JPG images in its construction. 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. The JPG method will normally create smaller true color images than the PNG method will, but they will show some distortion. When you're working with only a small palette, JPG images will be larger than GIF or PNG files. Like GIF, JPG files are supported on all graphical web browsers.

PNG Images

The PNG format can support images of any size palette. It compresses small-palette images better than GIF does, resulting in smaller file sizes. It renders more accurate true color images than JPG does, but it will not compress them nearly as well, resulting in larger file sizes. It is normally intended for small-palette images that don't need to be resized. Resized images will look better than with JPG or GIF, but the images will be larger. Support of the PNG format is not as omnipresent as support of the GIF or JPG formats, but it is commonly supported in modern browsers. It was created to replace GIF at a time when the patent on GIF hindered the development of free software for creating GIF images.

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.

Background1

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 them all. You may select a new background image with this item. The difference between using whole board images and small tiled images has already been described under the description for the CSS method.

Note that 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 50,50.

Note that the PNG and JPG methods flip the whole board image for the second player, but the CSS method does not. This is because the PNG and JPG methods can, and the CSS method can't.

Background2

This field is no longer used. It was originally for a second background image. This is useful for asymmetrical boards that appear different to each side, such as the triangular board of Klin Zha. Second background images are still used, but they are now hardcoded into Game Courier. Instead of specifying two board images in Edit mode, boards that go together are paired together in a file that gets included by Game Courier. This makes it easier for players to customize the appearance of the games they are playing. If you design two asymmetric board images, you should contact Fergus Duniho about having Game Courier recognize that they are paired together.

Board

The ASCII, Table, GIF, PNG, and JPG methods can automatically generate boards according to a specified pattern for checkering the board. It is this pattern that is stored in this field. It is rare that you will ever need to change this parameter when you are only customizing a preset. But here is an account of it. Each digit in the board pattern represents one of the colors or patterns listed in the Colors, Hex Colors, or Patterns field. Patterns is used for ASCII diagrams, Hex Colors for hexagonal boards rendered by the table method, and 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 Forsythe code, which is described in the section on Edit mode. 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 pattern for that rank 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. Cavalier Chess uses "10.21." for a three colored board, and Chessgi uses a pattern that almost 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. This value has been used for Shatranj and Chaturanga.

Colors

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

Hex Colors

This lists up to ten colors that may be used in automatically generating hexagonal boards with the Table method. All colors must be specified by name, and you are limited to the following colors: red, green, blue, orange, yellow, indigo, violet, cyan, magenta, black, white, firebrick, olivedrab, and royalblue. These include the three primary colors of the spectrum (red, green, blue), the three secondary colors of the spectrum (cyan, magenta, yellow), the three primary colors of paint (red, yellow, blue), the three secondary colors of paint (orange, green, magenta), the seven colors of the rainbow (red, orange, yellow, green, blue, indigo, violet), the colors of the French, British, and American flags (red, white, blue), the traditional colors of the Chess board (black, white) and a few other colors that are suitable for Chess boards (firebrick, olivedrab, royalblue).

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 Board parameter, described above.

Font

This menu selects the font used by the GIF, PNG, and JPG methods for displaying the coordinates. These methods cannot use fonts from your computer. They can only use fonts stored on our web server. I have included a selection of fonts at the root of the website, located in a directory that is not accessible to the web. The script can read these fonts, but you can't download them from the website. Some of the fonts are freely available from other websites, and most come from CD-ROMs I own.

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. First, I included both serif and sans serif fonts, and I included representatives of different types of serif and sans serif fonts. Serif fonts can be oldstyle, modern, revival/transitional, slab serif, and flare serif. Except for modern, I included at least one of each. Centime and Nadine are both oldstyle fonts. Benguiat is a revival font. Courier is a slab serif font. And Flair is a flare serif font. Sans Serif fonts include gothic (or grotesque), geometric, and humanist styles. I included the most popular representative of each. Helvetica is the most popular gothic sans serif, Futura the most popular geometric sans serif, and Optima the most popular humanist sans serif. I also included some sans serifs specifically designed for legibility. These include an optical character recognition font, as well as two of Microsoft's web fonts, Trebuchet and Verdana. I included regional fonts for Germany, Japan, and China. Since Japan and China don't actually use the Latin alphabet, these fonts are not actually of these regions. They merely resemble native writing in some way. I also included historical fonts that resemble types of writing from the Middle Ages, such as Cloister, Druid, Enchantment, and Templar. And I included a few other display fonts, such as AdLib, Review, TechSchool, and Uncollage.

Point Size

This lets you choose the point size for the font used by the GIF, PNG, and JPG rendering methods.

Scale

This is a percentage value that an auto-generated GIF, PNG, or JPG image should be rescaled to. The default value is 100, which doesn't change the size at all. Lower values than 100 are useful for reducing the size of a board image that would otherwise be too big for the browser window.

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.

Border Color

This specifies the color of the border used in Table mode. It may be entered as a hexadecimal color code or by name.

Text Color

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

Border Size

This specifies the minimum width and height of the border used in Table mode. It is measured in pixils.

Editing a Preset

You can enter Edit mode by clicking on the "Edit" button in the menu for a preset. You can also get there by clicking the "Editor" button on the index page. If you plan to make a preset for a game that is similar to an already existing template, it is best to begin with it as a template instead of starting from scratch.

Edit mode should be reserved for designing new presets, for editing presets you have already designed, and for creating fairy chess problems. If all you want to do is customize an existing preset to use graphics of your liking, then you should use Customize mode instead of Edit mode. Edit mode lets you change all the parameters that can be changed for defining a game. This includes every parameter you could change in Customize mode plus the following::

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 exiting 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.

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.

Name of 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. When you create a minirules file for displaying the rules to your game, its basename should be the game ID for the game, and its extension should be ".php".

Rules

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.org/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.org/pbm/d.chess/chess.html, but there is no webpage there. Yet if you want to refer to a page in the play.chessvariants.org subdomain, then this is the thing to do. Just enter the URL relative to the http://play.chessvariants.org/pbm/ directory. For example,"../erf/MiniChss.html" would point to the page at http://play.chessvariants.org/erf/MiniChss.html. If the webpage is offsite, then you must enter the full URL, including the http:// part at the beginning.

Shapes

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.

Horizontal Hexagonal Cells


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

Horizontal hexagonal cells 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.

Vertical Hexagonal Cells

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

Vertical hexagonal cells 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.


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.


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.

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 coodinate 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 pixil 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.

Code

This field is for a line of Forsythe code that describes the opening position of the game. Game Courier represents the board with a kind of Forsythe code that has been modified for use with variants. Forsythe code 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 uses a version of Forsythe code that has been expanded to handle a variety of different boards and pieces. It takes some inspiration from Hans Boedlander's Fairy Forsythe-Edwards Notation, but it is not the same.

Game Courier's extended version of Forsythe code works with all types of boards, not just 8x8 square Chess boards. The coordinates of most boards are reprented by ranks and files. These may not always be at right angles to each other, but that is irrelevant to the use of Forsythe code 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 Columns parameter to know how long a rank should be. The 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-retangular 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 expanded Forsythe 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 many were made back when only individual letters could be used to represent pieces.

The remaining modifications to Forsythe 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 Forsythe 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.

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 acceptible 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 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 acceptible 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 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 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.

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.

Side

This menu lets you select which player's turn it is. For any game preset, this should be set to the first name listed in the Sides field. This should be changed only for presets of fairy chess problems in which it is the second player's turn to move. For example, in a problem in which Black is to move, this could be set to Black instead of White.

Columns

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

Automatic Moves

This is where code goes for either automating complicated moves or for enforcing the rules of a game. All code should be written in GAME Code, an interpreted programming language designed specifically for Game Courier. What code goes where depends upon what it does.

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 including include files.

Pre-Move1

This code gets evaluated 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-Move2

This code gets evaluated 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-Move1

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-Move2

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.

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. 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.

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.

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 distingiush 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.

Displaying a Fairy Chess Problem

You can use Game Courier not only to play games but to display fairy chess problems. You do this in basically the same way as you would design a preset for a game. Begin with a pre-existing preset, and go into Edit mode. Change the Forsythe code in the Code field to the position of pieces in the problem. Set the Side field to whichever player is supposed to move first in the problem. Within the Pre-Game field, use the say command to display information about the problem, such as "Mate in two; White to move." If you are basing your problem on a preset that enforces the rules, and it uses variables to keep track of the King's current location, you should set these variables to the current locations of the Kings. The same goes for any other royal piece. Give your problem a name in the Settings Name field, fill in your userid and password, and save it as a settings file. Copy the URL given to you, and tack on "&submit=Move" to the end. You can then include the modified URL in a webpage or comment, and others will be able to view your problem and try out solutions. If your problem was based on a rule-enforcing preset, it should automatically tell users when they have entered a correct solution to a mate-in-one problem. Here is an example of what I've just described:

Writing a Minirules File

A minirules file is a brief summary of the rules that gets inserted into a page for a specific game. This file's name should be the same as the game's name, except that it should be all lowercase, all spaces should be underscores, any nonstandard alphabetic characters should be replaced with their 7-bit ASCII equivalents, and the extension should be ".php". For example, yang_qi.php is the minirules file for Yáng Qí. The minirules file should just state the rules briefly, describe the pieces, and give no more history of the game than maybe who invented it. It is not intended as a detailed description of the game. That is what the webpage on the game is for. All the minirules file is for is to briefly remind players how to play without the need to go to another page.

You can have it display the pieces of the game in whatever piece set has been chosen by using the showpiece function. This is important, because it really helps the user when the rules illustrate the pieces with the same images used on the board. This function takes two argument. The first is the letter identifying the piece, and the second is text to display underneath the piece, identifying what it is called. This function should be used in a table, because it creates a table cell that shows the piece and its name. Here is an example of its usage:

<TABLE BORDER=3><TR>
<?
showpiece("K", "King");
showpiece("Q", "Queen");
showpiece("R", "Rook");
showpiece("B", "Bishop");
showpiece("N", "Knight");
showpiece("P", "Pawn");
?>
</TR></TABLE>

If you are an editor of this site, I recommend looking at some of the minirules files to understand what they should look like.

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. I use and recommend Ultimate Paint. It will let you create GIF, PNG, and JPG files, which are the three acceptible file types for images on web pages. It provides many standard tools for manipulating images, many filters, and even the ability to custom design your own filters. I made use of this ability to write a filter for drawing circular boards, which you can download here: circular-chess.afs.

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. This program begins with the code entered into the Pre-Game field. It then follows this with the code from the Pre-Move and Post-move fields. Unlike the code from the Pre-Game field, which it just adds as is, it encapsulates the code from these fields into separate subroutines. When Game Courier first encounters the code from these fields, it will simply mark the locations of the subroutines and skip over them. Finally, it adds the moves and the Post-game code. 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 can be used for looking at the move as a string. Between this and the move, it includes a gosub to the appropriate Pre-Move subroutine. After the move, it includes a gosub to the appropriate Post-Move subroutine. The program ends with the Post-game code that follows the last move. Which body of Post-game code it executes depends on which player moved last. Here is a basic outline of what this 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:

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 Shogi.
conserve
A directive to tell the program to conserve the number of spaces throughout the game. When a move is to an off-board position, it deletes the space that the piece moved from. Useful in Voidrider Chess.
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.
right
Drops the piece on a randomly selected empty space from among those between the last space listed and the last 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.
kamikaze [P]
If the last piece to move was of type P, and the last move was a capture, it empties the space the piece moved to. This is useful for Kamikaze captures in Kamikaze Mortal Shogi. If no piece type is specified, the last space moved to is emptied if the move was a capture. This is useful for Kamikaze Chess.
link direction-name (C1 C2) ...
Adds the named logical direction to specified spaces on the logical map of the board. It takes a series of coordinate pairs, each in a pair of parentheses. It defines the direction for the first space in the pair, indicating that it goes to the second space in the pair. Direction names are not symmetrical, because that would be kind of stupid. This is similar to how Zillions of Games does the same kind of thing. See map below for further details on logical directions.
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, copies C1's flag to C2, and unsets C1's flag. Does not set $oldpiece, $origin, or $dest. Useful for the first part of an en passant move in some automated games.
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. 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, Hexcolors, or Patterns field, and they have previously been used in the Board field. 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.
unlink C1 ... Cn
unlink (C1 ... Cn) ...
unlink ((C1 ... Cn) (Co ... Cz)) ...
Unlinks spaces from each other that have been linked with logical directions by map or link. Coordinates may be actual coordinates or wildcard patterns, and they may appear outside parentheses, inside single parentheses, or inside nested parentheses. Outside of parentheses, the coordinate gets unlinked from everything, and everthing gets unlinked from it. If a wildcard pattern is given, every coordinate matching the pattern gets completely unlinked. So, unlink * would remove all links. Inside one pair of parentheses, every coordinate listed within the same set of parentheses gets unlinked from each other. If a wildcard is used, it unlinks every coordinate matching the wildcard from every other coordinate listed and from any coordinate matching another wildcard, but it does not unlink every coordinate matching the wildcard from every other coordinate matching the same wildcard. So, unlink (e* f*) would unlink every coordinate in the e file from every coordinate in the f file and vice versa, but it would leave the coordinates in the e file linked to each other, and it would leave the coordinates in the f file linked to each other. Inside nested parentheses, it unlinks everything in one set of parentheses from everything in any other set of parentheses. So, on a normally linked chessboard, unlink (e1 e2 e3 e4 e5 e6 e7 e8) (f1 f2 f3 f4 f5 f6 f7 f8)) is equivalent to unlink (e* f*). When wildcards are used inside nested parentheses, they effectively expand into the coordinates they match. So, unlink ((e*) (f*)) is equivalent to unlink (e1 e2 e3 e4 e5 e6 e7 e8) (f1 f2 f3 f4 f5 f6 f7 f8)), as well as to unlink (e* f*). However, unlink ((e* f*) g*) is not equivalent to unlink (e* f* g*). The former would unlink anything in the e or f file from anything in the g file and vice versa, whereas the latter would unlink anything in the e, f, or g files from anything in the other two files. Note that all unlinking is symmetrical. When any two coordinates are unlinked, each gets unlinked from the other. For asymmetrical unlinking, use the link command to reestablish one of the links after unlinking with this command. Because the parser interprets anything beginning with "?" as a flag, you should avoid using wildcard pattern beginning with "?". Since coordinates are usually of fixed length anyway, a "*" should usually work just as well as a "?" at the beginning.
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.

Input and Revision Commands

In the case of ambiguous or incomplete moves, these commands will rewrite the move made by the player. Some of these commands ask for input from the player to resolve ambiguous moves. These commands are primarily useful for writing code that lets a player make all moves with the mouse.

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.
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.
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.
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.

Output Commands

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.
say text
Displays a message in boldface above the board. Repeated uses will not display multiple messages, and only the message given in the last use of say will be displayed. Useful for displaying messages about the status of the game, such as "Check!", "Checkmate! White wins!", "Stalemate! Drawn game!", etc. Also useful for displaying information about a fairy chess problem, such as "Mate in one; White to Move."

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 get replaced by its value. For example, "echo #v" becomes "echo 5". But it doesn't work entirely like preprocessing code. 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. When a variable is limited to the scope it was created in, it does not exist in wider scopes. The other difference is between dynamic and 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 supercede all dynamic variables with the same name but wider scope. So local variables supercede global variables, and local variables of narrower scope supercede 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 subrountine 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, writing, 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.
die message
Prints error message to page and exits program. Useful for code that checks legality of moves.
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 variable [many|sub] 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.
sub name [arguments]
Calls the named subroutine with a gosub, optionally passing arguments to it, and sets the variable to the return value of the subroutine.
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.
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. 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:
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.
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.
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.
origin
This is the coordinate that a piece was last moved from. It can be accessed in commands with the origin keyword.
dest
This is the coordinate that a piece was last moved to. It can be accessed in commands with the dest keyword.
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.
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.

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.
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.
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.
keys
Returns an array whose values were the keys of the input array.
lastfile
Returns the numeric index of the last file. This would be 7 for Chess, since 0 is the first file.
lastrank
Returns the numeric index of the last rank. This would be 7 for Chess, since 0 is the first rank.
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.
piecekeys
Returns the piecekeys array.
pieces
Returns an array of all pieces on the board.
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. May only be used after a move is made.

true
Returns the boolean true value.
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, Hexcolors, 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.
findinhand
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.
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.
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.
var
Returns value of user-defined variable, which has previously been set with the set command.

Dual Unary/Binary operators

The four asymetrical logical operators can handle either one or two operands. It sometimes takes only one operand to know whether the whole operation is true or false. For example, x and y is false if y is false, no matter what x is. Likewise, x or y is true if y is true, no matter what x 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, 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 shift operator. Returns op1 << op2. Quick multiplication by 2 op2 times.
&rt;&rt;
Right shift operator. Returns op1 >> op2. Quick division by 2 op2 times but without a remainder. 4 >> 1 = 2. 5 >> 1 = 2.
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.
<<
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.
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.
htmllink
Returns an HTML link with op1 as the URL and op2 as the text.
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.
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.
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 "@".
search
Searches for op1 in array op2, returning the key for op1 in op2 if found. Otherwise returns false.
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
Returns the contents of the space that is op2 files and op3 ranks away from the space whose coordinate is given in op1.
where
Returns the coordinate of the space that is op2 files and op3 ranks away from the space whose coordinate is given in op1.

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. 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 when or unless operators, but not with the cond operator.
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. This is useful for finding the spaces 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").
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 offerred 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.
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 may return a value to a set, if, or elseif command. 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, and it is the only command that will return a value from a subroutine.
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

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. This function lets the Polish notation calculator call itself recursively. But you should be aware that recursive functions will not work as intended if you use cond. Consider this example: def ODDRAND cond bitand #1 1 fn ODDRAND rand 1 100 #1. 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. Unlike its ?: counterparts in C or PHP, cond always evaluates both parts of the expression before it ever gets to the operator. So, if you try to do recursion with cond, you will get an infinite loop. In place of cond use 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 #1 1 #1;.

def fac * #1 fn fac dec #1 unless equal #1 1 1;

onlyif condition expression
unless condition expression
These functions were designed to enable recursion in one-line Polish notation functions. Depending on the value of the condition following it, each one breaks out of the function and returns the value of the expression following the condition, or, if no expression follows the condition, the value of the condition itself. The unless allows evaluation of the expression to continue unless the condition is true, while the onlyif operator allows evaluation of the expression to continue only if the condition is true. So, unless breaks on a false condition, and onlyif breaks on a true condition. Since Polish notation is evaluated from back to front, breaking out of the function causes anything preceding the break to not be evaluated. In a recursive function, a call to itself should appear before the onlyif or unless that breaks out of the function. In that way, the function can eventually return output without endlessly calling itself.
and condition
or condition
nand condition
nor condition
Besides their usual behavior of evaluating a logical relation between two operands, these can sometimes evaluate a logical relation with only one operand, allowing them to exit the expression without evaluating the rest of it. This is what they do when only one operand is available. And when the information given isn't enough to evaluate the whole expression, its evaluation continues without adding anything new to the stack. This breaking ability makes them useful for recursion. By returning NULL when it doesn't break, it allows multiple instances of variable arity operators in the same line. Consider an expression like match insight #k 0 1 R Q or match insight #k 1 0 R Q. Since match will use any arguments available, or match insight #1 0 1 #2 match insight #1 1 0 #2 would not work right, because the match after or would use the value of the other match in computing its own value, leaving or with only the value of the closer match. But by splitting them up with ors, neither uses the other's value in its own computations, and the expression calculates its result correctly.

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 3 or checkaleap #0 #1 -2 3 or checkaleap #0 #1 2 -3 or checkaleap #0 #1 -2 -3 or checkaleap #0 #1 3 2 or checkaleap #0 #1 -3 2 or checkaleap #0 #1 3 -2 or checkaleap #0 #1 -3 -2;
def N checkleap #0 #1 2 3;

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 3 checkaleap #0 #1 -2 3 checkaleap #0 #1 2 -3 checkaleap #0 #1 -2 -3 checkaleap #0 #1 3 2 checkaleap #0 #1 -3 2 checkaleap #0 #1 3 -2 checkaleap #0 #1 -3 -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.

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.

Examples and Tutorial

While developing GAME Code, I have come up with different ways of doing the same things. I have usually developed new ways of doing things when the old ways wouldn't work for some games. The original way that I programmed Chess is described in the article Anatomy of a Preset. While the features it describes are still part of the language, and what it describes should still work, it has long been outdated. Its approach is to use a bunch of if-then statements.

Programming Chess with Functions & Subroutines

Soon after writing that article, I developed a method of programming games that relies on functions. This is used in the Chess preset and its chess include file. This approach relies on three sets of functions. The first set is used to test the legality of piece moves. Examples look like this:

def N checkleap #0 #1 1 2;
def B checkride #0 #1 1 1;
def R checkride #0 #1 1 0;
def Q fn B #0 #1 or fn R #0 #1;
def K checkleap #0 #1 1 1 or checkleap #0 #1 1 0;
def P checkaleap #0 #1 1 1 or checkaleap #0 #1 -1 1;

A second set is used to tell whether the King is in check. The basic idea is to look out from the King's location for any pieces that could be checking it. Some examples look like this:

def WPAWN match P what #0 1 -1 what #0 -1 -1;

def BPAWN match p what #0 1 1 what #0 -1 1;

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 WAZIR check what #0 0 -1 check what #0 -1 0 check what #0 0 1 check what #0 1 0 target #1;

def FERZ check what #0 -1 -1 check what #0 -1 1 check what #0 1 -1 check what #0 1 1 target #1;

def KING fn WAZIR #0 #1 or fn FERZ #0 #1;

def ROOK check insight #0 0 -1 check insight #0 -1 0 check insight #0 0 1 check insight #0 1 0 target #1;

def BISHOP check insight #0 -1 -1 check insight #0 -1 1 check insight #0 1 -1 check insight #0 1 1 target #1;

// These two functions are the culmination of the previous functions.;
// They are used to test whether a given space is attacked by pieces from the other side.;

def ATTACKEDBYB fn KING #0 k or fn BPAWN #0 or fn KNIGHT #0 n or fn ROOK #0 (r q) or fn BISHOP #0 (b q);
def ATTACKEDBYW fn KING #0 K or fn WPAWN #0 or fn KNIGHT #0 N or fn ROOK #0 (R Q) or fn BISHOP #0 (B Q);

A third set is used to tell what spaces a piece might be able to move to, which is used by the stalemated subroutine to tell whether any pieces can legally move. Since a separate checkmated subroutine is used when the King is in check, the stalemated subroutines assumes the King is not in check, and it saves time by checking only the first move a piece can make in any direction. If it could make this move legally, it could make any subsequent move in the same direction. Here are some examples of these functions:

def PL array where #0 0 1 where #0 -1 1 where #0 1 1;
def pl array where #0 0 -1 where #0 -1 -1 where #0 1 -1;
def NL leaps #0 1 2;
def BL leaps #0 1 1;
def RL leaps #0 1 0;
def QL merge leaps #0 1 0 leaps #0 1 1;
def KL merge leaps #0 1 0 leaps #0 1 1;

This method also makes use of various subroutines, such as checks, checkmated, stalemated, and castle, as well as subroutines for the King and Pawn moves, since these sometimes include behaviors that functions cannot handle, such as en passant and promotion for Pawns, and castling for Kings. The main advantage of this method over other methods is that it is better optimized for efficiency. The main disadvantage is that it works for fewer games. The chess include file is used for games besides Chess, and other examples of its use can be found in the presets for Big Board Chess, Grotesque Chess, whose grotesque include file includes it, Extra Move Chess, whose extramove include file includes it, and Fischer Random Chess, whose fischer include file includes it.

Programming Shogi

The same methods described above also worked well for Shogi. See the Shogi preset and its shogi include file for details. Since Shogi uses mostly different pieces and allows pieces to be dropped, it got its own include file. Study that file, and you will see the same ideas at work as described above. The Shogi include file was also used with the Kamikaze Mortal Shogi preset. The Hex Shogi 91 preset uses a very similar include file called hexshogi. It differs from the Shogi include file mainly in how it defines piece movement.

Programming Xiangqi and Other Games with Cannons

Chinese Chess could not be programmed in the same way, because it used Cannons, which capture by hopping over an intervening piece. This made it difficult to check for Cannon checks by looking out from the King's perspective, or rather General's perspective in this game. Also, with Cannons in the game, the stalemated subroutine would have to check up to every possible move a piece could make, because any move might make it the screen for a Cannon, which would put the General in check. So the Chinese Chess preset and xiangqi include file handled things differently. Instead of testing for check by looking out from the General's perspective, it scanned the board for enemy pieces and checked whether any could legally move to the General's space, using a subroutine which looked like this:

sub checked general:
  local piece from;
  if isupper space #general:
    def enemies onlylower;
  else:
    def enemies onlyupper;
  endif;

  for (from piece) fn enemies:
    if fn #piece #from #general:
      return true;
    endif;
  next;

  return false;
endsub;

Since its stalemated subroutine could not make the same assumptions that the stalemated subroutine for Chess was making, the checkmated and stalemated subroutines got consolidated into a single stalemated subroutine. Instead of using a checkmated subroutine when the General was in check and the stalemated subroutine only when the General was not in check, it used stalemated subroutine whether or not the King was in check and identified checkmate simply as check plus stalemate. The xiangqi include file gets used by the Korean Chess preset and its janggi include file. The Storm the Ivory Tower preset and its ivorytower include file use basically the same approaches.

Programming Chess Variants with both Cannons and Pawns

Since the code for Chinese Chess could not be used for Chess, and the code for Chinese Chess could not be used for Chess, I developed a new include file, called chess2, which could enforce the rules of Chess and make use of Cannons. While the original chess include file used three sets of functions, this new include file used only two sets of functions. The first set is used to check the legality of piece moves. It is mostly the same as described earlier, but now these functions were also being used for potential Pawn moves, which necessitated some modifications to the Pawn functions. Compare these functions to the ones above:

def P and == var ep join filename #1 rankname #0 checkleap #0 #1 1 1 or and == rankname #0 var wpr checkatwostep #0 #1 0 1 0 1 or checkleap #0 #1 0 1 and empty #1 or and islower space #1 checkleap #0 #1 1 1 and > rank #1 rank #0;

def p and == var ep join filename #1 rankname #0 checkleap #0 #1 1 1 or and == rankname #0 var bpr checkatwostep #0 #1 0 -1 0 -1 or checkleap #0 #1 0 1 and empty #1 or and isupper space #1 checkleap #0 #1 1 1 and < rank #1 rank #0;

While functions could be used for potential Pawn moves, subroutines were still required for actual Pawn moves. The other set of functions was for telling what spaces a piece might move to. Unlike the same functions used in the chess include file, these had to include all possible moves. Compare these with the same functions above:

def PL array where #0 0 2 where #0 0 1 where #0 -1 1 where #0 1 1;
def pL array where #0 0 -2 where #0 0 -1 where #0 -1 -1 where #0 1 -1;
def NL leaps #0 1 2;
def BL rays #0 1 1;
def RL rays #0 1 0;
def QL merge rays #0 1 0 rays #0 1 1;
def KL merge leaps #0 1 0 leaps #0 1 1;

As with Chinese Chess, no checkmated subroutine was used, and checkmate was defined as check plus stalemate.

Although this method is less efficient than the earlier method, it is useful for more variants, particularly variants with Cannons, and it is easier to adapt it to new games, because it doesn't require as many new functions to be written. Other presets using the chess2 include file include Gross Chess, Victorian Chess, Hostage Chess, whose hostagechess2 include file includes it, and Voidrider Chess, whose voidrider include file includes it.

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.

Learn by Example

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:

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. 

/home1/chessvar/public_html/play/pbm/devguide.html

Credits

Author: Fergus Duniho.

See also

Comments

DateNameRatingCommentEdit
This item is a reference work,
It belongs to categories: Not categorized
It was last modified on: 2010-12-11
 Author: Fergus  Duniho. Game Courier Developer's Guide.
2011-02-07Fergus Duniho Verified as Fergus DunihoNoneAdded subsection on adding comments, which I forget to document earlier. Also fixed a bug that wouldn't let comments be used in code entered into the forms in edit mode. Comments can now be entered anywhere in your code.View [*]
2011-02-06Fergus Duniho Verified as Fergus DunihoNoneJust added unlink command for use with logical directions. Useful for unlinking separate planes of a 3D game from each other before adding in directions that go from one plane to another.View [*]
2010-12-31Fergus Duniho Verified as Fergus DunihoNone

As an update to my last comment here, the new input and revision commands are called appendmove, ask, askpromote, continuemove, redomove, and rewritemove. They are all described in Input and Revision Commands. The continuemove command is what I earlier called extendmove. I have just made use of it with Extra Move Chess to handle double moves.

While working on that game, I discovered a good use for a do-while loop that ends with a never condition. I previously mentioned that this will function like a simple if statement. Although it doesn't have the benefit of adding elseif conditions, it can sometimes be more useful than a simple if statement, because it allows the use of break or continue to exit it early or the use of redo to return to the beginning. In Extra Move Chess, I had code that I wanted to execute if the player made a second move, but if the player passed the second move with the pass command, I wanted to skip over most of this code. So I put it in a do-while/loop-never loop and used break to exit early if the move equaled the pass command.

View [*]
2010-12-12Fergus Duniho Verified as Fergus DunihoNoneIn a move toward making Game Courier more user-friendly, I have added some commands that allow a player to create moves longer than a single move primitive by using the mouse. I have already used them with Shogi and Chess to handle promotions with the mouse. If you want to use them with the presets for your games, details are now on this page. Briefly, the new commands are appendmove, ask, askpromote, and extendmove.View [*]
2010-11-27Fergus Duniho Verified as Fergus DunihoNone

Attention Game Courier Developers:

If you have programmed any presets to enforce the rules, and you use variables to keep track of the location of the King or other royal piece, you will need to make a slight modification to your code for your preset to work properly with fairy chess problems. In most of the presets I've programmed, I have code that looks like this:

set K e1; set k e8;

To work with fairy chess problems, in which the Kings might be found anywhere on the board at the beginning of the problem, this code needed to be changed to this:

set K findpiece K spaces; set k findpiece k spaces;

This change will allow Game Courier to know the position of the Kings when a fairy chess problem begins, allowing it to properly use code for recognizing check and checkmate.

I am currently going through my own presets, making the appropriate modifications. For some games with different royal pieces, this code has to be modified.

View [*]
Number of ratings: 5, Average rating: Excellent, Number of comments: 115

List all comments and ratings for this item.

Add a comment or rating for this item.


The Chess Variant Pages

http://www.chessvariants.org/play/pbm/devguide.html
Last Modified: Sun, 07 Aug 2011 08:58:05 -0600
[info] [links] [edit] [quick edit]