Plugin Specification
Want to write an AI engine to use with Qianhong? It's not too difficult if you have some programming experience and a Windows/DOS compiler.
It turns out that, with the addition of plugin capability, Qianhong is sort of like
a WinBoard for Chinese Chess. I hadn't heard of WinBoard when I made the plugins, but
the structure is pretty similar: a GUI that uses piped I/O to communicate with AI
engines. Maybe Qianhong will grow into a Xiangqi WinBoard... who knows. From a glance
at the
WinBoard site,
though, it appears that WinBoard has been around a long time and has a huge following.
The following pages describe the Qianhong plugin protocol:
A Qianhong AI plugin is simply a Windows console program that is capable of reading standard input and writing standard output. Qianhong runs the plugin executable as a detached process with its standard I/O redirected to anonymous pipes. A text-based protocol, which consists of only a handful of simple commands, is used to communicate with the plugin.
As an example, the following text shows the first part of a game against QHPlugin.exe (the default Qianhong AI engine) on a level 3 setting:
LEVEL 3 (Qianhong sets the AI level) OK - Set AI level to 3 (Plugin accepts it) PLAY H2-E2 (Qianhong plays a move: round 1, red) OK (Plugin accepts it) AI (Qianhong asks for AI to move) B9-C7 (Plugin plays a move: round 1, black) PLAY E2-E6 (Qianhong plays a move: round 2, red) OK (Plugin accepts it) AI (Qianhong asks for AI to move) C7-E6 (Plugin plays a move: round 2, black) UNDO (Qianhong backs out last move) OK (Plugin accepts it)
That's the basic interface. Now for the details: 2. Plugin Modes.
Plugins are run in one of two modes, as specified by a command-line parameter: "-info" and "-plugin". The info mode is used during Qianhong startup. It allows Qianhong to query the plugin for a description of its capabilities. The plugin mode is used to actually play a game of Xiangqi.
When the plugin is run with a "-info" argument, all it has to do is print a standard list of information and exit. The information is of the format:
Protocol Version AI Engine Name LEVELS <N> (N lines of levels) UNDO <0/1> HINTS <0/1> RULES <0/1> BGTHINK <0/1> TIMEOUT <0/1> (Additional lines of Info) ENDINFOTake the info from QHPlugin.exe as an example (you can see this yourself by running "<Qianhong dir>\Plugins\Qianhong\QHPlugin.exe -info"):
C:\Qianhong\Plugins\Qianhong>qhplugin.exe -info QHPLUGIN V1.3 Qianhong LEVELS 3 1 - Very Easy 2 - Easy 3 - Smarter UNDO 1 HINTS 1 RULES 1 BGTHINK 0 TIMEOUT 0 Qianhong AI engine for Qianhong v3.1 By Jeremy Craner, 2001-2004 ENDINFO
Protocol Version The first line is the plugin protocol version. It should read "QHPLUGIN V1.3" (though V1.2 is still supported). The version number allows for future expansion.
AI Engine Name The second line gives the AI engine name that appears in the game. You'll want to keep it short because the player name boxes are not very big...
Levels The third line tells how many different AI levels the plugin has. The subsequent lines list each level, one per line, with the number and any additional text you want to use for description. Levels must be designated by a number. The extra text (preceded by a space) is optional.
Undo This tells Qianhong whether the UNDO command is supported. Use 0 for no, 1 for yes.
Hints This tells Qianhong whether the HINTS command is supported. Use 0 for no, 1 for yes.
Rules This tells Qianhong whether the BAN command is supported. Use 0 for no, 1 for yes.
BGThink This tells Qianhong whether the BGTHINK command is supported. Use 0 for no, 1 for yes.
Timeout This tells Qianhong whether the TIMEOUT command is supported. Use 0 for no, 1 for yes.
Additional Info Following the hints line, all lines up to the ENDINFO line are treated as additional info that appears in the "Choose AI Engine" dialog box. Blank lines may be used for formatting.
When the plugin is run with a "-plugin [debug]" argument, it is to play a game. Qianhong redirects STDIN and STDOUT to pipes so it can communicate with the plugin. The plugin reads commands from STDIN, takes appropriate action, and writes responses to STDOUT. All commands (except one, but you'll see that later) require a response. The plugin must flush STDOUT each time it finishes writing a response so that the data will be sent through the pipe. Failure to flush the stream will cause Qianhong to wait indefinitely for the data.
The optional "debug" argument is used when Qianhong is run in plugin debugging mode. (Run Qianhong with "plugin_debug" as the first argument.) In this mode, the plugin will have a console and may output anything it wants to the console by writing to STDERR. Of course, you can also write to a file (or something else) if you like. The debug mode is for your own benefit; use it as you see fit.
The next section, 3. Commands, describes the commands and their associated responses.
Qianhong sends the following commands to the plugins. Each command is discussed in detail below. Command and response words are in ALL CAPS, though your plugin may choose to recognize lower-case commands as well.
Required:
LEVEL [new-level]
FEN <FEN-string>
PLAY <ICCS-move>
LOAD <count> ...
AI
ABORT
QUIT
Optional:
UNDO
HINTS
BAN <count> ...
BGTHINK <ON|OFF>
TIMEOUT
A note on responses: All responses must end with a newline character ('\n'). Expected responses vary by command, but the two most common responses are OK and ERROR. Both of these may be followed (on the same line) by additional text as desired. Errors will usually be reported in a Qianhong message box, in which case the user will be able to read the text description of the error.
| Command | LEVEL |
| Response | <current-level> |
| Description | For a LEVEL command with no parameter, reply with the current level number. |
| Command | LEVEL <new-level> |
| Responses | OK [text] ERROR [text] |
| Description | For a LEVEL command with a parameter, set the current level to the one specified by the given number. Reply OK if successful, or ERROR if the number is out of range. |
| Command | FEN <FEN-string> |
| Responses | OK [text] ERROR [text] |
| Description | This command instructs the plugin to set the board using the
FEN string (see
www.nchess.com/fen.html for details on FEN for Chinese Chess).
Red will always be on the bottom (i.e. the last line of the string).
Reply OK if the board is set, or ERROR if something goes wrong. |
| Command | PLAY <ICCS-move> |
| Responses | OK [text] ERROR [text] |
| Description | This tells the plugin to play the given move. The move parameter is in ICCS notation of the form "A0-A1". Looking down on a board with red on the bottom, A0 is the lower-left corner (where red's left chariot starts) and I9 is the upper-right corner (where black's left chariot starts). So the move "A0-A1" would move the piece in the near corner of red's ninth file up one spot. (See notation conventions in 4. Tricky Stuff for more.) Reply OK if the move is made, or ERROR if something goes wrong. |
| Command | LOAD <count> \n [ICCS-move \n] ... |
| Responses | OK [text] ERROR [text] |
| Description | Tells the plugin to play a list of moves. This allows Qianhong to load a whole sequence of moves much quicker than using multiple PLAY commands. The parameter is the number of moves, which are given in ICCS format, one-per-line, following the LOAD command. |
| Command | AI |
| Responses | <ICCS-move> ERROR [text] ABORTED |
| Description | Tells the plugin to move for the current player and report
the move. The plugin responds with the move in ICCS notation of the form "A0-A1", or
ERROR if something goes wrong. If the plugin's AI engine takes more than a second to
respond, the plugin must keep watching STDIN for new commands, and interrupt
the AI engine if a command comes before the engine is done thinking. In this case,
the plugin should respond with ABORTED, then process the next command as normal.
Qianhong typically only aborts the AI command when the user closes the app or quits the current game. The exception is with the TIMEOUT command, which, if supported, is sent to cause the AI to stop thinking and reply with the best move it has come up with so far. |
| Command | ABORT |
| Response | (none) |
| Description | The ABORT command is used when an AI or HINTS command is in progress and Qianhong needs to cancel it and get the plugin back to a ready state. Since the plugin must abort AI and HINTS commands when any new command is sent, this is just a way to stop the AI engine without causing a new command to execute. The plugin does not reply to the ABORT command directly; the only response is from a terminated AI or HINTS command that responds with ABORTED. |
| Command | QUIT |
| Response | BYE |
| Description | This command tells the plugin to stop running and exit. The plugin responds with BYE when it shuts down. (If the plugin doesn't respond or close, Qianhong will give it about a second and then kill it. This is a last resort that may leave resources open, so the plugin should be sure to shut down gracefully when it is told to quit.) |
| Command | UNDO |
| Responses | OK [text] ERROR [text] |
| Description | Tells the plugin to undo the last move. The plugin
responds with OK if it can undo it, or ERROR if something goes wrong (or if no moves
have been played yet). The plugin may choose not to implement this command (to the dismay of users =) by specifying "UNDO 0" in the info mode. |
| Command | HINTS |
| Responses |
<hint [description]> \n [hint [description] \n] ... ENDHINTS ERROR [text] ABORTED |
| Description | Requests hints on the current move from the plugin.
This is basically the same as the AI command except that: (1) the plugin does not play
a move, (2) the plugin may suggest more than one move, and (3) the plugin may describe
the move(s) to the user. The nominal response is one or more ICCS moves, one per line, followed by a line that says ENDHINTS. Moves should be listed in order from best to worst; illegal moves must not be listed. Each ICCS move may be followed (on the same line) by additional text describing the move. Other responses are ERROR and ABORTED. (Since this command may take more than a second to execute, it should be interruptible by ABORT and TIMEOUT--see the AI command for more.) The plugin may choose not to implement this command (to the dismay of users =) by specifying "HINTS 0" in the info mode. |
| Command | BAN <count> \n [ICCS-move \n] ... |
| Responses | OK [text] ERROR [text] |
| Description | Tells the plugin that the listed moves are considered
illegal for the next AI or HINTS command. This allows Qianhong to moderate the game like
a referee, and lets the plugins choose alternate moves accordingly. The parameter is the number of banned moves, which are given in ICCS format, one-per-line, following the BAN command.
The plugin may choose not to implement this command by specifying "RULES 0" in the info mode. In this case, if the plugin plays a banned move, Qianhong will call the game a forfeit. (Forfeits are not pretty, so plugins should support this command if at all possible.) |
| Command | BGTHINK <ON|OFF> |
| Responses | OK [text] ERROR [text] |
| Description | This command instructs the plugin to turn its background thinking on or off. Qianhong disables background thinking when two plugins are playing each other or when the user manually disables it. (Qianhong will always tell the plugin to turn BG thinking on or off at the start of each game.)
If the plugin does not support BG thinking (as specified by "BGTHINK 0" in the info mode, it does not need to support this command. |
| Command | TIMEOUT |
| Responses | (none) |
| Description | This command is sent by Qianhong after the user-specified time limit is up and the AI or HINTS command has not completed. This command similar to the ABORT command. In fact, the only difference is that the AI must stop thinking and return a valid move or hints list instead of giving the ABORTED response. As with the ABORT command, the only response is from a pending AI or HINTS command. (The plugin must not send a response if the AI is idle.)
The plugin may choose not to implement this command by specifying "TIMEOUT 0" in the info mode. |
That's it for the commands. If you have questions about them, or if my descriptions are not very clear, there are a few things you can do to better understand the protocol:
The next section, 4. Tricky Stuff, describes things you should watch out for when writing your plugin.
Testing Your Plugin
When you run Qianhong with the "plugin_debug" parameter, the "Choose AI Engine" dialog
shows a button you can use to run a set of tests on the plugins. Use this feature to
help ensure your plugin handles the commands correctly.
Piped I/O
Be sure to flush STDOUT after every response!
Response Time
If your AI takes more than a second for the AI and HINTS commands (most engines will),
then you must come up with some way to respond quickly to any incoming command.
The best way is probably to use a separate thread for your AI engine. You
might also use polling, but you'll need to use a non-blocking read for the input.
Notation Conventions
Red is always on the "bottom" for ICCS moves and FEN strings. The following diagram
shows the ICCS notation coordinates and FEN row ordering (rows are described left-to-right):
(Black)
A B C D E F G H I
9 [r][h][e][a][k][a][e][h][r] 9 (first FEN row)
| | | | \|/ | | | |
8 |--+--+--+--+--+--+--+--| 8 (2nd FEN row)
| | | | /|\ | | | |
7 |-[c]-+--+--+--+--+-[c]-| 7 (3rd FEN row)
| | | | | | | | |
6 [p]-+-[p]-+-[p]-+-[p]-+-[p] 6 (4th FEN row)
| | | | | | | | |
5 |-----------------------| 5 (5th FEN row)
| |
4 |-----------------------| 4 (6th FEN row)
| | | | | | | | |
3 (P)-+-(P)-+-(P)-+-(P)-+-(P) 3 (7th FEN row)
| | | | | | | | |
2 |-(C)-+--+--+--+--+-(C)-| 2 (8th FEN row)
| | | | \|/ | | | |
1 |--+--+--+--+--+--+--+--| 1 (9th FEN row)
| | | | /|\ | | | |
0 (R)(H)(E)(A)(K)(A)(E)(H)(R) 0 (last FEN row)
A B C D E F G H I
(Red)
Player Turns
Red goes first, unless a FEN command changes it to black's turn. When the plugin gets an
AI (or HINTS) command, it is to play (or think) for whichever side is to move next.
The AI is never explicitly told which side it is playing.
BG Thinking
If you implement background thinking, you should start thinking after an AI command, and think ahead for the same color that the AI command moved for. If something unexpected comes along (UNDO, BAN, PLAY an unanticipated move, etc.), you'll have to bail on the thinking. Since a plugin is only used for one side of the game (except when a human is playing his/her self--which doesn't use AI commands), you won't get AI commands for both sides of the board.
Copyright © 2004 Jeremy Craner