Checked in the Fairy-Max 4.8 M package
authorH.G. Muller <h.g.muller@hccnet.nl>
Thu, 14 Jan 2010 22:12:20 +0000 (23:12 +0100)
committerH.G. Muller <h.g.muller@hccnet.nl>
Thu, 14 Jan 2010 22:12:20 +0000 (23:12 +0100)
Makefile [new file with mode: 0644]
README [new file with mode: 0644]
changelog [new file with mode: 0644]
copyright [new file with mode: 0644]
data/fmax.ini [new file with mode: 0644]
data/qmax.ini [new file with mode: 0644]
fairymax.6 [new file with mode: 0644]
fairymax.c [new file with mode: 0644]
fmax.6.pod [new file with mode: 0644]
maxqi.c [new file with mode: 0644]

diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..b389dc9
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,42 @@
+srcdir = .
+
+CC=gcc
+CFLAGS += -O2
+
+
+ALL= fairymax shamax maxqi
+
+all: ${ALL}
+
+fairymax: fairymax.c
+       $(CC) $(CFLAGS) -DINI_FILE=\"/usr/share/games/fairymax/fmax.ini\" fairymax.c -o fairymax
+
+shamax: fairymax.c
+       $(CC) $(CFLAGS) -DINI_FILE=\"/usr/share/games/fairymax/fmax.ini\" -DSHATRANJ fairymax.c -o shamax
+
+maxqi: maxqi.c
+       $(CC) $(CFLAGS) -DINI_FILE=\"/usr/share/games/fairymax/qmax.ini\" maxqi.c -o maxqi
+
+install: ${ALL} ${srcdir}/data/*
+       cp -u ${srcdir}/fairymax /usr/games
+       cp -u ${srcdir}/shamax /usr/games
+       cp -u ${srcdir}/maxqi /usr/games
+       install -d -m0755 /usr/share/games/fairymax
+       cp -u ${srcdir}/data/* /usr/share/games/fairymax
+       install -d -m0755 /usr/share/man/man6
+       cp -u ${srcdir}/fairymax.6.gz /usr/share/man/man6
+
+clean:
+       rm -f ${ALL}
+
+dist-clean:
+       rm -f ${ALL} *~ data/*~
+
+uninstall:
+       rm -f /usr/share/games/fairymax/*
+       rmdir /usr/share/games/fairymax
+       rm -f /usr/share/man/man6/fairymax.6.gz
+       rm -f /usr/games/fairymax
+       rm -f /usr/games/shamax
+       rm -f /usr/games/maxqi
+
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..db5e7c9
--- /dev/null
+++ b/README
@@ -0,0 +1,30 @@
+This package contains the sources of the XBoard-compatible Chess and
+Chess-variant engine Fairy-Max, and its dedicaed derivatives ShaMax 
+(for Shatranj) and MaxQi (for XiangQi = Chinese Chess). A Makefile
+is provided to compile and install them. Normally this would require only
+the command (given from the main directory of the package):
+
+sudo make install
+
+This will install the executables in /usr/games, (where XBoard expects
+them), and their data files in /usr/share/games/fairymax.
+
+Should you want to compile by hand, you could use the following 
+commands:
+
+gcc -O2 fairymax.c -o fairymax
+
+gcc -O2 fairymax.c -DSHATRANJ -o shamax
+
+gcc -O2 maxqi.c -o maxqi
+
+In this case you will get versions that expect their fmax.ini or qmax.ini
+files in the current direcory. To change the default path of the ini files,
+you can include the argument 
+
+-DINI_FILE=\"pathname\"
+
+to the gcc compilation command line.
+
+H.G.Muller
+
diff --git a/changelog b/changelog
new file mode 100644 (file)
index 0000000..3c4f32a
--- /dev/null
+++ b/changelog
@@ -0,0 +1,61 @@
+/***************************************************************************/
+/* micro-Max version 4.8 (~1950 characters) features:                      */
+/* - recursive negamax search                                              */
+/* - all-capture quiescence search with MVV/LVA priority                   */
+/* - (internal) iterative deepening                                        */
+/* - best-move-first 'sorting'                                             */
+/* - a hash table storing score and best move                              */
+/* - futility pruning                                                      */
+/* - king safety through magnetic frozen king                              */
+/* - null-move pruning                                                     */
+/* - Late-move reductions                                                  */
+/* - full FIDE rules (expt minor promotion) and move-legality checking     */
+/* - keep hash + rep-draw detect                                           */
+/* - end-game Pawn-push bonus, new piece values, gradual promotion         */
+/***************************************************************************/
+/* The Fairy-Max version reads the piece description from a file fmax.ini  */
+/* The format supports many fairy pieces, including hoppers.               */
+/* f) now supports 15 piece types, by requisitioning WHITE bit             */
+/* g) supports larger board width.                                         */
+/* h) castling bug ('in-check by non-captures') corrected                  */
+/* i) rep-draw bug ('side-to-move') corrected                              */
+/* k) allow user underpromotions, recognize & ignore 'variant' command     */
+/* l) edit bug corrected (i & j file clear)                                */
+/* m) piece values no longer quantized, game-stage counting bug corrected  */
+/* n) edit-menu K-side castling bug corrected.                             */
+/* o) retrieve the requested variant from the .ini file                    */
+/* p) clear hash table on variant switch                                   */
+/* q) reduced piece-material count for better Pawn push                    */
+/* r) hash-table bug corrected (X still ORed with flags)                   */
+/* s) Bug that prevented initialization center points corrected            */
+/* t) castling bug after edit fixed                                        */
+/* u) converted to protocol 2; ping implemented                            */
+/* v) white e.p. rights hash bug fixed;                                    */
+/* w) piece indicators programable, multi-path support                     */
+/* x) e.p. changed to support Berolina Pawns                               */
+/* y) capture value of 6-7th-rank Pawn reduced in Shatranj                 */
+/* z) bug in promotion input corrected                                     */
+/* A) stalemate-detection bug in printResult fixed                         */
+/* B) Invalidate hash on game-level promotion (might be under-promotion!)  */
+/* C) King move evaluation based on negative piece value in stead of nr    */
+/* D) WB memory command added, undo fixed                                  */
+/* E) 15th piece read in                                                   */
+/* F) accepts ini fileargument                                             */
+/* G) bug in calculation ASCII promotion character fixed                   */
+/* H) unified normal and shatranj source                                   */
+/* J) rewrite under-promotion code, fixes persistent bug there             */
+/* K) o[] and oo[] made int to make fairymax work on big-endian machines   */
+/* L) added Resign option feature (using new WB protocol)                  */
+/* M) char -> signed char for better portability                           */
+/***************************************************************************/
+
+4/6/2009 Unified source of ShaMax and Fairy-Max into single fmax.c file, and
+         created this ChangeLog from the until then self-documenting source.
+
+6/2/2009 Promotion code rewitten to not refer to default piece characters.
+
+9/3/2009 Fixed big-endian bug in reading inifile (char with int format),
+         and added some option features to make Fairy-Max useful as test
+         engine for GUIs that want to implement the WB protocol extensions.
+
+9/16/2009 made signedness of char in AI explicit
diff --git a/copyright b/copyright
new file mode 100644 (file)
index 0000000..1eeedf6
--- /dev/null
+++ b/copyright
@@ -0,0 +1,25 @@
+This package was debianized by H.G.Muller<h.g.muller@hccnet.nl> on
+Fri Jun  5 20:42:56 CEST 2009.
+
+Upstream Author(s): 
+
+    H.G. Muller <h.g.muller@hccnet.nl>
+
+Copyright: 
+
+    Copyright (C) 2009 H.G. Muller 
+
+License:
+
+    Fairy-Max 4.8 is free software, and you have permission do
+    with it whatever you want, whether it is commercial or not.
+    Note, however, that Fairy-Max can easily be configured through
+    its fmax.ini file to play Chess variants that are legally pro-
+    tected by patents, and to do so would also require permission 
+    of the holders of such patents. No guarantees are given that 
+    Fairy-Max does anything in particular, or that it would not 
+    wreck the hardware it runs on, and running it is entirely for 
+    your own risk.
+
+The Debian packaging is (C) H.G.Muller<h.g.muller@hccnet.nl>.
+
diff --git a/data/fmax.ini b/data/fmax.ini
new file mode 100644 (file)
index 0000000..64bd2ac
--- /dev/null
@@ -0,0 +1,393 @@
+version 4.8(w)\r
+8x8\r
+6 4 5 7 3 5 4 6\r
+6 4 5 7 3 5 4 6\r
+p:74 -16,24 -16,6 -15,5 -17,5 \r
+p:74  16,24 16,6 15,5 17,5\r
+k:-1  1,34 -1,34 1,7 16,7 15,7 17,7 -1,7 -16,7 -15,7 -17,7\r
+n:259 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7\r
+b:296 15,3 17,3 -15,3 -17,3\r
+R:444 1,3 16,3 -1,3 -16,3\r
+Q:851 1,3 16,3 15,3 17,3 -1,3 -16,3 -15,3 -17,3\r
+\r
+\r
+Some Common piece definitions:\r
+\r
+The board steps are encoded as follows:\r
+\r
+                      ^  toward 8th rank\r
+                      |\r
+      -52 -51 -50 -49 -48 -47 -46 -45 -44\r
+      -36 -35 -34 -33 -32 -31 -30 -29 -28\r
+      -20 -19 -18 -17 -16 -15 -14 -13 -12\r
+ <--   -4  -3  -2  -1 start 1   2   3   4   --> towards h file\r
+ to    12  13  14  15  16  17  18  19  20\r
+a-file 28  29  30  31  32  33  34  35  36\r
+       44  45  46  47  48  49  50  51  52\r
+                      |\r
+                      v  towards first rank\r
+\r
+SIMPLE LEAPERS\r
+Ferz:\r
+f:150 15,7 17,7 -15,7 -17,7\r
+Wazir:\r
+w:125 1,7 16,7 -1,7 -16,7\r
+Knight:\r
+n:325 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7\r
+Dabbabah:\r
+d:100 2,7 32,7 -2,7 -32,7\r
+Elephant:\r
+e:80 30,7 34,7 -30,7 -34,7\r
+Camel:\r
+C:225 13,7 47,7 49,7 19,7 -13,7 -47,7 -49,7 -19,7\r
+Zebra:\r
+Z:175 29,7 46,7 50,7 35,7 -29,7 -46,7 -50,7 -35,7\r
+Unicorn:\r
+u:-1 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7\r
+\r
+COMPOUND LEAPERS\r
+King:\r
+k:-1 1,34 -1,34 1,7 16,7 15,7 17,7 -1,7 -16,7 -15,7 -17,7 1,34 -1,34\r
+King (Shatranj, no castling):\r
+k:-1 1,7 16,7 15,7 17,7 -1,7 -16,7 -15,7 -17,7 1,34 -1,34\r
+King (Capablanca castling):\r
+k:-1 2,3034 -2,1034 1,7 16,7 15,7 17,7 -1,7 -16,7 -15,7 -17,7\r
+Commoner:\r
+m:260 1,7 16,7 15,7 17,7 -1,7 -16,7 -15,7 -17,7 \r
+Bison:\r
+1000 13,7 47,7 49,7 19,7 -13,7 -47,7 -49,7 -19,7 29,7 46,7 50,7 35,7 -29,7 -46,7 -50,7 -35,7\r
+Wildebeest:\r
+g:800 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7 13,7 47,7 49,7 19,7 -13,7 -47,7 -49,7 -19,7\r
+Carpenter:\r
+c:450 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7 2,7 32,7 -2,7 -32,7\r
+Kangaroo:\r
+o:450 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7 30,7 34,7 -30,7 -34,7\r
+High Priestess:\r
+h:625 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7 30,7 34,7 -30,7 -34,7 15,7 17,7 -15,7 -17,7\r
+Minister\r
+c:625 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7 2,7 32,7 -2,7 -32,7 1,7 16,7 -1,7 -16,7\r
+Crab:\r
+c:150 31,7 33,7 -14,7 -18,7\r
+Barc:\r
+b:150 14,7 18,7 -31,7 -33,7\r
+\r
+SEPARATE CAPTURES / NON-CAPTURES\r
+White Pawn:\r
+p:100 -16,6 -15,5 -17,5 -16,24\r
+White Pawn (Shatranj, no double move):\r
+p:100 -16,6 -15,5 -17,5\r
+White Berolina Pawn\r
+p:74 -15,24 -17,24 -16,5 -15,6 -17,6 \r
+Black Pawn:\r
+p:100 16,6 15,5 17,5 16,24\r
+Pegasus (moves as Queen, captures as Rook):\r
+S:500 1,2 16,2 15,2 17,2 -1,2 -16,2 -15,2 -17,2 14,5 31,5 33,5 18,5 -14,5 -31,5 -33,5 -18,5\r
+Keen (moves as King, captures as Queen):\r
+k:750  1,6 16,6 15,6 17,6 -1,6 -16,6 -15,6 -17,6 1,1 16,1 15,1 17,1 -1,1 -16,1 -15,1 -17,1 \r
+Quing (moves as Queen, captures as King):\r
+q:600  1,5 16,5 15,5 17,5 -1,5 -16,5 -15,5 -17,5 1,2 16,2 15,2 17,2 -1,2 -16,2 -15,2 -17,2 \r
+\r
+SLIDERS\r
+Bishop:\r
+b:350 15,3 17,3 -15,3 -17,3\r
+Rook:\r
+R:500 1,3 16,3 -1,3 -16,3\r
+NightRider:\r
+H:560 14,3 31,3 33,3 18,3 -14,3 -31,3 -33,3 -18,3\r
+Queen:\r
+Q:950 1,3 16,3 15,3 17,3 -1,3 -16,3 -15,3 -17,3\r
+\r
+LEAPER / SLIDER COMPOUNDS\r
+Archbishop:\r
+A:875 15,3 17,3 -15,3 -17,3 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7\r
+Caliph:\r
+C:875 15,3 17,3 -15,3 -17,3 13,7 47,7 49,7 19,7 -13,7 -47,7 -49,7 -19,7\r
+Marshall:\r
+C:900 1,3 16,3 -1,3 -16,3 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7\r
+Canvasser:\r
+C:900 1,3 16,3 -1,3 -16,3 13,7 47,7 49,7 19,7 -13,7 -47,7 -49,7 -19,7\r
+Amazon:\r
+A:1150 1,3 16,3 15,3 17,3 -1,3 -16,3 -15,3 -17,3 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7\r
+Crooked Bishop:\r
+B:900 15,1E003 17,1E003 -15,1E003 -17,1E003 15,FFFE0003 -17,FFFE0003 -15,FFFE0003 17,FFFE0003\r
+\r
+HOPPERS\r
+GrassHopper:\r
+G:200 1,F8 16,F8 15,F8 17,F8 -1,F8 -16,F8 -15,F8 -17,F8\r
+Cannon:\r
+C:400 1,BA 16,BA -1,BA -16,BA\r
+\r
+LAME LEAPERS\r
+Horse:\r
+N:5 16,1070 16,1F070 1,10070 1,FFFF0070 -16,1070 -16,1F070 -1,10070 -1,FFFF0070\r
+Xiangqi Elephant:\r
+E:1 15,70 17,70 -15,70 -17,70\r
+\r
+\r
+\r
+Syntax of a variant description:\r
+\r
+Each variant starts with the label "Game:" followed by the variant name.\r
+After that follow upto 18 lines with the description.\r
+\r
+Line 1:     Board size (files x ranks). Ranks must currently still be 8.\r
+Line 2:     initial setup of white pieces on back rank\r
+Line 3:     initial setup of black pieces on back rank\r
+Line 4-10:  Description of pieces present in the opening position\r
+Line 11-18: Description 8 additional piece types\r
+\r
+The rest of the lines is ignored, but some pre-cooked descriptions are\r
+provided for easy copying into the first positions.\r
+\r
+\r
+\r
+In case you want to build your own pieces, this is how it works:\r
+\r
+The piece-description lines have the following syntax:\r
+1) a piece-indicator character (lower case if piece should be centralized)\r
+2) a colon\r
+3) the internal value to be used for the piece (in centiPawn; Royal = -1)\r
+4) for each direction it moves in, a ray descriptor consisting of:\r
+   a) the initial step vector (on a 16x8 board, so 16 = straight ahead)\r
+   b) a comma\r
+   c) the move-mode descriptor, most easily given in hexadecimal, as the\r
+      individual bits specify the various options\r
+\r
+The individual bits in the move-mode descriptor have the following meaning:\r
+In the last hexadecimal digit:\r
+    1 capture allowed (of enemy piece; own pieces always block a move)\r
+    2 con-capture allowed (i.e. we can move here if the square is empty)\r
+    4 leaper, i.e. move terminates after one step (as opposed to slider)\r
+    8 hop over non-empty square (normally occupied squares terminate a move)\r
+Bits set in the forelast digits TOGGLE the corresponding bits in the last\r
+digit. For hoppers when they hop over something, for the other pieces after\r
+every step (so for normal pieces, better not set those bits!).\r
+\r
+The digit before that can only be 0 or 1; a 1 indicates the board should\r
+be treated as a cylinder, pieces crossing the right edge re-entering the\r
+board at the left, and vice versa.\r
+\r
+The higher-order bits toggle corresponding bits in the step vector,\r
+to allow zig-zag paths. Better not set those either, if a straight\r
+path is desired.\r
+\r
+Useful bit combinations for the last digit are:\r
+    3   normal slider\r
+    7   normal leaper\r
+    6   leaper that only moves (e.g. Pawn straight ahead)\r
+    5   leaper that only captures (e.g. Pawn diagonal)\r
+    1   slider that only captures\r
+    2   slider that only moves\r
+    0   pass through (for testing emptiness by Xiangqi Horse and Elephant)\r
+    4   reserved for skip-step of Pawn double move and castling\r
+    8   skip to hopper platform (1st part of Grasshopper move)\r
+    A   non-capture before hop (1st part of Cannon move)\r
+    C   must hop immediately\r
+\r
+For example, if the initial step vector equals 1, and the descriptor\r
+is 11003, the piece is an alternator (as no hop bit is set), and alternates\r
+the mode from 3 to 3 (as the toggle digit is 0), i.e. all steps are moves\r
+that can both capture and non-capture, and only captures terminate the ray.\r
+The step vector is toggled by 11, though, and thus alternates between 1\r
+and 10 (hex) = 16. So the piece zig-zags over the board, right, forward, right,\r
+forward, etc. Had the move attributes been 11032, captures would only\r
+be allowed on the odd steps (after moving right), while the even steps could\r
+only be non-captures (both the 1 and 2 bit are toggled). With 11030 the\r
+odd steps can only be skipped (if empty), and the even steps can both capture\r
+and non-capture, meaning the piece moves like a Bishop that can be blocked\r
+by a piece just next to the diagonal.\r
+\r
+If the first step is a slider, a second step is made (if the square was\r
+empty), but if the mode toggles to leaper, the move stops there (e.g. Horse).\r
+\r
+Hoppers MUST change into non-hoppers on hopping, i.e. the 8 bit of BOTH\r
+lower digits must be set. Otherwise results will be undefined.\r
+\r
+Note that the first two piece-describing lines MUST be for the white and\r
+black Pawn, respectively, or promotions will have undefined effects. Also\r
+note that uMax does do primitive evaluation of Pawn structure, which might\r
+become counter-productive if the Pawn move is changed.\r
+\r
+Castling is done with the Rook replacement (the piece that starts in the\r
+corner, whatever its type). If you don't want that, remove the castling\r
+moves from the King desription. If the castling initiator does not start\r
+in a central file, the results are currently undefined.\r
+\r
+\r
+For the truly lazy, a few complete game descriptions can be found below:\r
+\r
+// FIDE Chess (a.k.a. Mad Queen variant)\r
+Game: normal\r
+8x8\r
+6 4 5 7 3 5 4 6\r
+6 4 5 7 3 5 4 6\r
+p:74 -16,24 -16,6 -15,5 -17,5 \r
+p:74  16,24 16,6 15,5 17,5\r
+k:-1  1,34 -1,34 1,7 16,7 15,7 17,7 -1,7 -16,7 -15,7 -17,7\r
+n:259 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7\r
+b:296 15,3 17,3 -15,3 -17,3\r
+R:444 1,3 16,3 -1,3 -16,3\r
+Q:851 1,3 16,3 15,3 17,3 -1,3 -16,3 -15,3 -17,3\r
+f:481 13,FFFFF207 29,F207 46,F207 47,10207 49,10207 50,11207 35,11207 19,1207 -13,1207 -29,FFFF1207 -46,FFFF1207 -47,FFFF0207 -49,FFFF0207 -50,FFFEF207 -35,FFFEF207 -19,FFFFF207 \r
+\r
+// Arabic precursor of modern Chess\r
+Game: shatranj\r
+8x8\r
+6 4 5 3 7 5 4 6\r
+6 4 5 3 7 5 4 6\r
+p:100 -16,6 -15,5 -17,5 \r
+p:100 16,6 15,5 17,5\r
+k:-1  1,7 16,7 15,7 17,7 -1,7 -16,7 -15,7 -17,7\r
+n:450 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7\r
+b:110 30,7 34,7 -30,7 -34,7\r
+R:630 1,3 16,3 -1,3 -16,3\r
+q:180 15,7 17,7 -15,7 -17,7\r
+e:110 30,7 34,7 -30,7 -34,7\r
+f:180 15,7 17,7 -15,7 -17,7\r
+\r
+// Medieval intermediate between Shatranj and FIDE Chess\r
+Game: courier\r
+12x8\r
+6 4 8 5 10 3 7 9 5 8 4 6\r
+6 4 8 5 10 3 7 9 5 8 4 6\r
+p:65 -16,6 -15,5 -17,5 \r
+p:65 16,6 15,5 17,5\r
+k:-1  1,7 16,7 15,7 17,7 -1,7 -16,7 -15,7 -17,7\r
+n:300 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7\r
+b:366 15,3 17,3 -15,3 -17,3\r
+R:550 1,3 16,3 -1,3 -16,3\r
+f:120 15,7 17,7 -15,7 -17,7\r
+e:70 30,7 34,7 -30,7 -34,7\r
+w:100 1,7 16,7 -1,7 -16,7\r
+m:280 1,7 16,7 15,7 17,7 -1,7 -16,7 -15,7 -17,7 \r
+\r
+// The King moves as a Knight, and vice versa\r
+Game: knightmate\r
+8x8\r
+6 4 5 7 3 5 4 6\r
+6 4 5 7 3 5 4 6\r
+p:74 -16,24 -16,6 -15,5 -17,5 \r
+p:74  16,24 16,6 15,5 17,5\r
+u:-1  1,34 -1,34 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7\r
+m:222 1,7 16,7 15,7 17,7 -1,7 -16,7 -15,7 -17,7\r
+b:296 15,3 17,3 -15,3 -17,3\r
+R:444 1,3 16,3 -1,3 -16,3\r
+Q:851 1,3 16,3 15,3 17,3 -1,3 -16,3 -15,3 -17,3\r
+\r
+// Modern variant with two new pieces (Archbishop and Chancellor) on 10x8 board\r
+Game: capablanca\r
+10x8\r
+6 4 8 5 7 3 5 9 4 6\r
+6 4 8 5 7 3 5 9 4 6\r
+p:100 -16,24 -16,6 -15,5 -17,5 \r
+p:100 16,24 16,6 15,5 17,5\r
+k:-1  1,3034 -1,1034 1,7 16,7 15,7 17,7 -1,7 -16,7 -15,7 -17,7\r
+n:310 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7\r
+b:350 15,3 17,3 -15,3 -17,3\r
+R:475 1,3 16,3 -1,3 -16,3\r
+Q:950 1,3 16,3 15,3 17,3 -1,3 -16,3 -15,3 -17,3\r
+A:825 15,3 17,3 -15,3 -17,3 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7\r
+C:875 1,3 16,3 -1,3 -16,3 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7\r
+e:1000 15,7 17,7 -15,7 -17,7 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7 -1,7 1,7 -16,7 16,7 -1,34 1,34 -16,34 16,34\r
+\r
+// Gothic Chess is protected through U.S. patent #6,481,716 by Ed Trice.\r
+// Spreading it without license might be a criminal offense!\r
+Game: gothic\r
+10x8\r
+6 4 5 7 9 3 8 5 4 6\r
+6 4 5 7 9 3 8 5 4 6\r
+p:100 -16,24 -16,6 -15,5 -17,5 \r
+p:100 16,24 16,6 15,5 17,5\r
+k:-1 1,3034 -1,1034 1,7 16,7 15,7 17,7 -1,7 -16,7 -15,7 -17,7\r
+n:310 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7\r
+b:350 15,3 17,3 -15,3 -17,3\r
+R:475 1,3 16,3 -1,3 -16,3\r
+Q:950 1,3 16,3 15,3 17,3 -1,3 -16,3 -15,3 -17,3\r
+A:825 15,3 17,3 -15,3 -17,3 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7\r
+C:875 1,3 16,3 -1,3 -16,3 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7\r
+\r
+// Cylinder Chess (WinBoard / XBoard legality testing should be off toplay this!)\r
+Game: cylinder\r
+8x8\r
+6 4 5 7 3 5 4 6\r
+6 4 5 7 3 5 4 6\r
+p:100 -16,24 -16,6 -15,105 -17,105 \r
+p:100 16,24 16,6 15,105 17,105\r
+k:-1 1,34 -1,34 1,107 16,7 15,107 17,107 -1,107 -16,7 -15,107 -17,107\r
+n:350 14,107 31,107 33,107 18,107 -14,107 -31,107 -33,107 -18,107\r
+b:450 15,103 17,103 -15,103 -17,103\r
+R:525 1,103 16,3 -1,103 -16,3\r
+Q:1150 1,103 16,3 15,103 17,103 -1,103 -16,3 -15,103 -17,103\r
+\r
+// Berolina Chess. In WinBoard 4.3.15 you can play this with legality testing switched off
+Game: berolina\r
+8x8\r
+6 4 5 7 3 5 4 6\r
+6 4 5 7 3 5 4 6\r
+p:74 -15,24 -17,24 -16,5 -15,6 -17,6 \r
+p:74  15,24  17,24 16,5 15,6 17,6\r
+k:-1  1,34 -1,34 1,7 16,7 15,7 17,7 -1,7 -16,7 -15,7 -17,7\r
+n:259 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7\r
+b:296 15,3 17,3 -15,3 -17,3\r
+R:444 1,3 16,3 -1,3 -16,3\r
+Q:851 1,3 16,3 15,3 17,3 -1,3 -16,3 -15,3 -17,3\r
+\r
+// Modern variant with four new pieces in randomly chosen setup on 8x8 board\r
+Game: super\r
+8x8\r
+6 4 5 7 3 5 4 6\r
+6 4 5 7 3 5 4 6\r
+p:100 -16,24 -16,6 -15,5 -17,5 \r
+p:100 16,24 16,6 15,5 17,5\r
+k:-1  1,34 -1,34 1,7 16,7 15,7 17,7 -1,7 -16,7 -15,7 -17,7\r
+n:350 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7\r
+b:360 15,3 17,3 -15,3 -17,3\r
+R:575 1,3 16,3 -1,3 -16,3\r
+Q:900 1,3 16,3 15,3 17,3 -1,3 -16,3 -15,3 -17,3\r
+S:825 15,3 17,3 -15,3 -17,3 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7\r
+E:850 1,3 16,3 -1,3 -16,3 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7\r
+V:775 1,7 16,7 15,7 17,7 -1,7 -16,7 -15,7 -17,7 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7\r
+A:1200 1,3 16,3 -1,3 -16,3 15,3 17,3 -15,3 -17,3 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7\r
+o:700 2,7 30,7 32,7 34,7 -2,7 -30,7 -32,7 -34,7 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7\r
+g:640 1,7 16,7 15,7 17,7 -1,7 -16,7 -15,7 -17,7 2,7 30,7 32,7 34,7 -2,7 -30,7 -32,7 -34,7\r
+m:-1  1,34 -1,34 1,7 16,7 15,7 17,7 -1,7 -16,7 -15,7 -17,7 16,70 -16,70\r
+d:625 1,7 16,7 -1,7 -16,7 15,3 17,3 -15,3 -17,3\r
+\r
+Game: fairy\r
+8x8\r
+10 9 8 7 3 5 4 6\r
+10 9 8 7 3 5 4 6\r
+p:100 -16,24 -16,6 -15,5 -17,5 \r
+p:100 16,24 16,6 15,5 17,5\r
+k:-1  1,34 -1,34 1,7 16,7 15,7 17,7 -1,7 -16,7 -15,7 -17,7\r
+n:325 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7\r
+b:350 15,3 17,3 -15,3 -17,3\r
+R:500 1,3 16,3 -1,3 -16,3\r
+Q:950 1,3 16,3 15,3 17,3 -1,3 -16,3 -15,3 -17,3\r
+e:60 30,7 34,7 -30,7 -34,7\r
+H:560 14,3 31,3 33,3 18,3 -14,3 -31,3 -33,3 -18,3\r
+O:320 1,BA 16,BA -1,BA -16,BA\r
+A:875 15,3 17,3 -15,3 -17,3 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7\r
+C:900 1,3 16,3 -1,3 -16,3 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7\r
+v:850 1,7 16,7 15,7 17,7 -1,7 -16,7 -15,7 -17,7 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7\r
+Z:1260 1,3 16,3 -1,3 -16,3 15,3 17,3 -15,3 -17,3 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7\r
+m:275 1,7 16,7 15,7 17,7 -1,7 -16,7 -15,7 -17,7\r
+\r
+// Great Shatranj: modern variant with range-two leapers replacing sliders, on 10x8 board
+// Must be played with legality testing off in XBoard 4.4.0.\r
+Game: great\r
+10x8\r
+6 4 5 8 3 10 9 5 4 6\r
+6 4 5 8 3 10 9 5 4 6\r
+p:100 -16,6 -15,5 -17,5 \r
+p:100 16,6 15,5 17,5\r
+k:-1  1,7 16,7 15,7 17,7 -1,7 -16,7 -15,7 -17,7\r
+n:290 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7\r
+e:270 15,7 17,7 -15,7 -17,7 30,7 34,7 -30,7 -34,7\r
+w:300 1,7 16,7 -1,7 -16,7 2,7 -2,7 32,7 -32,7\r
+s:280 1,7 16,7 15,7 17,7 -1,7 -16,7 -15,7 -17,7\r
+g:640 1,7 16,7 -1,7 -16,7 2,7 -2,7 32,7 -32,7 15,7 17,7 -15,7 -17,7 30,7 34,7 -30,7 -34,7\r
+h:640 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7 15,7 17,7 -15,7 -17,7 30,7 34,7 -30,7 -34,7\r
+m:640 14,7 31,7 33,7 18,7 -14,7 -31,7 -33,7 -18,7 1,7 16,7 -1,7 -16,7 2,7 -2,7 32,7 -32,7\r
+\r
+// End of game file\r
diff --git a/data/qmax.ini b/data/qmax.ini
new file mode 100644 (file)
index 0000000..6e215db
--- /dev/null
@@ -0,0 +1,34 @@
+version 4.8(w)\r
+10x9\r
+11 9 4 8 3 8 4 9 11\r
+11 9 5 8 3 8 5 9 11\r
+p:100 -1,7\r
+p:100 1,7\r
+k:-1 1,C07 16,C07 -1,C07 -16,C07\r
+e:150 15,470 17,470 -15,470 -17,470\r
+e:150 15,870 17,870 -15,870 -17,870\r
+q:190 -1,7 16,7 -16,7\r
+q:190 1,7 16,7 -16,7\r
+A:200 15,C07 17,C07 -15,C07 -17,C07\r
+h:450 16,1070 16,1F070 1,10070 1,FFFF0070 -16,1070 -16,1F070 -1,10070 -1,FFFF0070\r
+C:460 1,BA 16,BA -1,BA -16,BA\r
+R:900 1,3 16,3 -1,3 -16,3\r
+\r
+\r
+// Chinese Chess\r
+Game: xiangqi\r
+10x9\r
+11 9 4 8 3 8 4 9 11\r
+11 9 5 8 3 8 5 9 11\r
+p:100 -1,7\r
+p:100 1,7\r
+k:-1 1,C07 16,C07 -1,C07 -16,C07\r
+e:150 15,470 17,470 -15,470 -17,470\r
+e:150 15,870 17,870 -15,870 -17,870\r
+q:190 -1,7 16,7 -16,7\r
+q:190 1,7 16,7 -16,7\r
+A:200 15,C07 17,C07 -15,C07 -17,C07\r
+h:450 16,1070 16,1F070 1,10070 1,FFFF0070 -16,1070 -16,1F070 -1,10070 -1,FFFF0070\r
+C:460 1,BA 16,BA -1,BA -16,BA\r
+R:900 1,3 16,3 -1,3 -16,3\r
+// End of game file\r
diff --git a/fairymax.6 b/fairymax.6
new file mode 100644 (file)
index 0000000..a84b44b
--- /dev/null
@@ -0,0 +1,236 @@
+.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32
+.\"
+.\" Standard preamble:
+.\" ========================================================================
+.de Sh \" Subsection heading
+.br
+.if t .Sp
+.ne 5
+.PP
+\fB\\$1\fR
+.PP
+..
+.de Sp \" Vertical space (when we can't use .PP)
+.if t .sp .5v
+.if n .sp
+..
+.de Vb \" Begin verbatim text
+.ft CW
+.nf
+.ne \\$1
+..
+.de Ve \" End verbatim text
+.ft R
+.fi
+..
+.\" Set up some character translations and predefined strings.  \*(-- will
+.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
+.\" double quote, and \*(R" will give a right double quote.  \*(C+ will
+.\" give a nicer C++.  Capital omega is used to do unbreakable dashes and
+.\" therefore won't be available.  \*(C` and \*(C' expand to `' in nroff,
+.\" nothing in troff, for use with C<>.
+.tr \(*W-
+.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
+.ie n \{\
+.    ds -- \(*W-
+.    ds PI pi
+.    if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
+.    if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\"  diablo 12 pitch
+.    ds L" ""
+.    ds R" ""
+.    ds C` ""
+.    ds C' ""
+'br\}
+.el\{\
+.    ds -- \|\(em\|
+.    ds PI \(*p
+.    ds L" ``
+.    ds R" ''
+'br\}
+.\"
+.\" If the F register is turned on, we'll generate index entries on stderr for
+.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
+.\" entries marked with X<> in POD.  Of course, you'll have to process the
+.\" output yourself in some meaningful fashion.
+.if \nF \{\
+.    de IX
+.    tm Index:\\$1\t\\n%\t"\\$2"
+..
+.    nr % 0
+.    rr F
+.\}
+.\"
+.\" For nroff, turn off justification.  Always turn off hyphenation; it makes
+.\" way too many mistakes in technical documents.
+.hy 0
+.if n .na
+.\"
+.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
+.\" Fear.  Run.  Save yourself.  No user-serviceable parts.
+.    \" fudge factors for nroff and troff
+.if n \{\
+.    ds #H 0
+.    ds #V .8m
+.    ds #F .3m
+.    ds #[ \f1
+.    ds #] \fP
+.\}
+.if t \{\
+.    ds #H ((1u-(\\\\n(.fu%2u))*.13m)
+.    ds #V .6m
+.    ds #F 0
+.    ds #[ \&
+.    ds #] \&
+.\}
+.    \" simple accents for nroff and troff
+.if n \{\
+.    ds ' \&
+.    ds ` \&
+.    ds ^ \&
+.    ds , \&
+.    ds ~ ~
+.    ds /
+.\}
+.if t \{\
+.    ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
+.    ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
+.    ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
+.    ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
+.    ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
+.    ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
+.\}
+.    \" troff and (daisy-wheel) nroff accents
+.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
+.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
+.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
+.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
+.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
+.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
+.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
+.ds ae a\h'-(\w'a'u*4/10)'e
+.ds Ae A\h'-(\w'A'u*4/10)'E
+.    \" corrections for vroff
+.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
+.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
+.    \" for low resolution devices (crt and lpr)
+.if \n(.H>23 .if \n(.V>19 \
+\{\
+.    ds : e
+.    ds 8 ss
+.    ds o a
+.    ds d- d\h'-1'\(ga
+.    ds D- D\h'-1'\(hy
+.    ds th \o'bp'
+.    ds Th \o'LP'
+.    ds ae ae
+.    ds Ae AE
+.\}
+.rm #[ #] #H #V #F C
+.\" ========================================================================
+.\"
+.IX Title "FMAX.6 1"
+.TH FMAX.6 1 "2009-06-05" "perl v5.8.8" "User Contributed Perl Documentation"
+.SH "NAME"
+fairymax \- xboard\-compatible chess and chess\-variant engine 'Fairy\-Max'
+.SH "SYNOPSIS"
+.IX Header "SYNOPSIS"
+\&\fBfairymax\fR [hashSize] [iniFile]
+.PP
+\&\fBshamax\fR [hashSize] [iniFile]
+.PP
+\&\fBmaxqi\fR [hashSize] [iniFile]
+.SH "DESCRIPTION"
+.IX Header "DESCRIPTION"
+\&\fBfairymax\fR is a program that plays chess and chess variants. 
+It uses the xboard/winboard chess-engine protocol to communicate.
+Apart from 'regular' chess (also known as the Mad-Queen variant),
+it can play Capablanca chess, gothic chess, knightmate, cylinder chess, 
+berolina chess, superchess and courier chess.
+Fairy-Max can be easily configured by the user to play other variants as well,
+by modifying the ini file.
+This ini file describes the rules of movement
+of the participating pieces and the initial board setup.
+.PP
+Fairy-Max can also play shatranj, 
+but in this case is not aware of the shatranj rule that a bare king loses.
+So it might play sub-optimally in the late end\-game.
+A version of Fairy-Max adapted to implement the baring rule is
+available under the name \fBshamax\fR.
+.PP
+Similarly, a version of Fairy-Max adapted to play Xiang Qi (Chinese Chess)
+is included in the fmax package as well.
+.PP
+\&\fBfairymax\fR is a derivative of the world's (once) smallest chess program 
+(source\-code wise), micro\-Max.
+The latter measures less that 2000 characters, (about 100 code lines),
+and has a computer rating of around 2050 on the \s-1CCRL\s0 rating list.
+Although this is about 1000 rating points behind the world champion,
+micro-Max still makes a quite tough opponent even for club players,
+although it is not unbeatable.
+.PP
+The main difference between micro-Max and Fairy-Max is that the latter loads
+its move-generator tables, which specify how the various pieces move,
+from an external file, so it can be easily adapted to incorporate un-orthodox pieces.
+For ease of use of the artificial\-intelligence, Fairy-Max is equipped with
+I/O routines that allow it to run with the xboard graphical user interface.
+.PP
+See \fIxboard\fR\|(6) for instructions about how to use \fBfairymax\fR through xboard. To
+start up quickly, you just need the command: \fBxboard \-fcp fairymax\fR.
+However, XBoard might not support symbols for every unorthodox piece in board sizes
+different from \fBbulky\fR, \fBmiddling\fR and \fBpetite\fR.
+It might thius be adviasable to specify a board size as well, e.g.
+\&\fBxboard \-fcp shamax \-boardSize middling \-variant shatranj\fR 
+to get correct display of the elephant and general pieces in shatranj.
+Note that to be able to play the chess variants,
+you will need xboard 4.3.14 or later.
+.PP
+The fmax.ini file from which Fairy-Max by default takes the piece and game definitions
+is a self-documenting text file,
+which contains instructions for how to define new pieces and chess variants.
+In addition it contains an extensive list of pre-defined pieces,
+incuding many not occurring in any of the pre-defined variants,
+which the user can draw on to define his own variants.
+.PP
+Amongst the move types supported by Fairy-Max are normal leaper and slider moves,
+(e.g. knight and rook),
+divergent moves (i.e. capture and non-capture moves can be different)
+hoppers (which jump over other pieces, such as the Chinese cannon or the grasshopper),
+lame leapers (the move of which can be blocked on squares they cannot move to,
+such as the Chinese horse and elephant),
+and any combination thereof,
+in every possible direction.
+The board width is configurable upto a width of 14 squares,
+and cylindrical boards (where left and right edge connect) are supported as well.
+.SH "OPTIONS"
+.IX Header "OPTIONS"
+.IP "\fBhashSize\fR" 8
+.IX Item "hashSize"
+If the first argument to fairymax is numeric,
+it is taken as an indicator for the amount of memory Fairy-Max is allowed to use
+for its internal hash table.
+The default value for this argument, 22, would result in a memory usage of 48MB.
+Each next-higher number doubles the memory usage, each next-lower halves it.
+Running with less than 6MB (i.e. argument 19) is not recommended.
+When fairymax is running under xboard 4.3.15 the hash-table size can be set 
+through the xboard menus,
+making this argument superfluous.
+.IP "\fBiniFile\fR" 8
+.IX Item "iniFile"
+A second or non-numeric first argument is taken as a filename.
+Fairy-max will use the mentioned file in stead of its default fmax.ini file
+to define the movement of pieces and initial setup of the variants.
+This makes it easier to define your own variants.
+.SH "SEE ALSO"
+.IX Header "SEE ALSO"
+\&\fIxboard\fR\|(6)
+.PP
+http://www.chessvariants.org/index/msdisplay.php?itemid=MSfairy\-max
+.PP
+http://home.hccnet.nl/h.g.muller/max\-src2.html
+.PP
+http://www.open\-aurec.com/wbforum/viewtopic.php?t=49439
+.SH "AUTHOR"
+.IX Header "AUTHOR"
+\&\fBFairy-Max\fR was written by H.G.Muller <h.g.muller@hccnet.nl>.
+.PP
+This manual page was generated with \fIpod2man\fR\|(1).
diff --git a/fairymax.c b/fairymax.c
new file mode 100644 (file)
index 0000000..8b7b45a
--- /dev/null
@@ -0,0 +1,813 @@
+/***************************************************************************/\r
+/*                               fairy-Max,                                */\r
+/* Version of the sub-2KB (source) micro-Max Chess program, fused to a     */\r
+/* generic WinBoard interface, loading its move-generator tables from file */\r
+/***************************************************************************/\r
+\r
+     /*****************************************************************/\r
+     /*                      LICENCE NOTIFICATION                     */\r
+     /* Fairy-Max 4.8 is free software, and you have my permission do */\r
+     /* with it whatever you want, whether it is commercial or not.   */\r
+     /* Note, however, that Fairy-Max can easily be configured through*/\r
+     /* its fmax.ini file to play Chess variants that are legally pro-*/\r
+     /* tected by patents, and that to do so would also require per-  */\r
+     /* mission of the holders of such patents. No guarantees are     */\r
+     /* given that Fairy-Max does anything in particular, or that it  */\r
+     /* would not wreck the hardware it runs on, and running it is    */\r
+     /* entirely for your own risk.  H.G,Muller, author of Fairy-Max  */\r
+     /*****************************************************************/\r
+\r
+#define MULTIPATH\r
+#define VERSION "4.8M"\r
+\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+#include <signal.h>\r
+#include <time.h>\r
+\r
+#ifndef INI_FILE \r
+#define INI_FILE "fmax.ini"\r
+#endif\r
+\r
+#ifdef WIN32 \r
+#    include <windows.h>\r
+#else\r
+#    include <sys/time.h>\r
+     int GetTickCount() // with thanks to Tord\r
+     { struct timeval t;\r
+       gettimeofday(&t, NULL);\r
+       return t.tv_sec*1000 + t.tv_usec/1000;\r
+     }\r
+#endif\r
+\r
+int StartKey;\r
+\r
+#define EMPTY -1\r
+#define WHITE 0\r
+#define BLACK 16\r
+\r
+#define STATE 128\r
+\r
+/* The following macros indicate the differences between Fairy-Max and its */\r
+/* dedicated Shatranj derivative ShaMax so that these can now be compiled  */\r
+/* from the same unified source file.                                      */\r
+/* Compile with gcc option -DSHATRANJ to build ShaMax.                     */\r
+#ifdef SHATRANJ\r
+#    define FAC 175\r
+#    define EG  13\r
+#    define NAME "ShaMax"\r
+#    define SHAMAX(x) x\r
+#    define FMAX(x)\r
+#else\r
+#    define FAC 128\r
+#    define EG  10\r
+#    define NAME "Fairy-Max"\r
+#    define SHAMAX(x)\r
+#    define FMAX(x) x\r
+#endif\r
+\r
+/* make unique integer from engine move representation */\r
+#define PACK_MOVE 256*K + L;\r
+\r
+/* convert intger argument back to engine move representation */\r
+#define UNPACK_MOVE(A) K = (A)>>8 & 255; L = (A) & 255;\r
+\r
+/* Global variables visible to engine. Normally they */\r
+/* would be replaced by the names under which these  */\r
+/* are known to your engine, so that they can be     */\r
+/* manipulated directly by the interface.            */\r
+\r
+int Side;\r
+int Move;\r
+int PromPiece;\r
+int Result;\r
+int TimeLeft;\r
+int MovesLeft;\r
+int MaxDepth;\r
+int Post;\r
+int Fifty;\r
+int UnderProm;\r
+int GameNr;\r
+int Resign;\r
+int Threshold = 800;\r
+int Score;\r
+char piecename[32], piecetype[32];\r
+char *inifile = INI_FILE;\r
+\r
+int Ticks, tlim, Setup, SetupQ;\r
+\r
+int GameHistory[1024];\r
+char HistoryBoards[1024][STATE], setupPosition[131];\r
+int GamePtr, HistPtr;\r
+\r
+#define W while\r
+#define K(A,B) *(int*)(T+A+S*(B&31))\r
+#define J(A) K(y+A,b[y])-K(x+A,u)-K(H+A,t)\r
+\r
+int U=(1<<23)-1;\r
+struct _ {int K,V;char X,Y,D,F;} *A;           /* hash table, 16M+8 entries*/\r
+\r
+int M=136,S=128,I=8e3,Q,O,K,N,j,R,J,Z,LL,      /* M=0x88                   */\r
+BW,BH,sh,\r
+w[16]={0,2,2,-1,7,8,12,23,7,5},                /* relative piece values    */\r
+o[256],\r
+oo[32],                                        /* initial piece setup      */\r
+of[256],\r
+od[16];                                        /* 1st dir. in o[] per piece*/\r
+\r
+signed char L,pl[17],\r
+b[513],                                        /* board: 16x8+dummy, + PST */\r
+T[4104],                                       /* hash translation table   */\r
+centr[32],\r
+n[]=".*XKNBRQEWFMACHG?x+knbrqewfmachg";        /* piece symbols on printout*/\r
+\r
+pboard()\r
+{int i;\r
+ i=-1;W(++i<128)printf(" %c",(i&15)==BW&&(i+=15-BW)?10:n[b[i]&31]);\r
+}\r
+         \r
+\r
+D(k,q,l,e,E,z,n)        /* recursive minimax search, k=moving side, n=depth*/\r
+int k,q,l,e,E,z,n;      /* (q,l)=window, e=current eval. score, E=e.p. sqr.*/\r
+{                       /* e=score, z=prev.dest; J,Z=hashkeys; return score*/\r
+ int j,r,m,v,d,h,i,F,G,P,V,f=J,g=Z,C,s,flag,FF;\r
+ signed char t,p,u,x,y,X,Y,H,B;\r
+ struct _*a=A+(J+(k+S)*E&U-1);                 /* lookup pos. in hash table*/\r
+ q-=q<e;l-=l<=e;                               /* adj. window: delay bonus */\r
+ d=a->D;m=a->V;X=a->F;Y=a->Y;                  /* resume at stored depth   */\r
+ if(a->K-Z|z&S  |                              /* miss: other pos. or empty*/\r
+  !(m<=q|X&8&&m>=l|X&S))                       /*   or window incompatible */\r
+  d=Y=0;                                       /* start iter. from scratch */\r
+ X=a->X;                                       /* start at best-move hint  */\r
+ W(d++<n||d<3||              /*** min depth = 2   iterative deepening loop */\r
+   z&S&&K==I&&(GetTickCount()-Ticks<tlim&d<=MaxDepth|| /* root: deepen upto time   */\r
+   (K=X,L=Y&~S,Score=m,d=3)))                  /* time's up: go do best    */\r
+ {x=B=X;                                       /* start scan at prev. best */\r
+  h=Y&S;                                       /* request try noncastl. 1st*/\r
+  P=d>2&&l+I?D(16-k,-l,1-l,-e,2*S,2*S,d-3):I;  /* search null move         */\r
+  m=-P<l|R<5?d-2?-I:e:-P;   /*** prune if > beta  unconsidered:static eval */\r
+  SHAMAX( if(pl[k]<=1&pl[16-k]>1)m=I-1; )      /* bare king loses          */\r
+  N++;                                         /* node count (for timing)  */\r
+  do{u=b[x];                                   /* scan board looking for   */\r
+   if(u&&(u&16)==k)                            /*  own piece (inefficient!)*/\r
+   {r=p=u&15;                                  /* p = piece type (set r>0) */\r
+    j=od[p];                                   /* first step vector f.piece*/\r
+    W(r=o[++j])                                /* loop over directions o[] */\r
+    {A:                                        /* resume normal after best */\r
+     flag=h?3:of[j];                           /* move modes (for fairies) */\r
+     y=x;F=FF=G=S;                             /* (x,y)=move, (F,G)=castl.R*/\r
+     do{                                       /* y traverses ray, or:     */\r
+      H=y=h?Y^h:y+r;                           /* sneak in prev. best move */\r
+      if(flag&1<<8)H=y=(y&15)>13?y+BW:(y&15)>=BW?y-BW:y; /* cylinder board */\r
+      if(y&S|(y&15)>=BW)break;                 /* board edge hit           */\r
+#ifdef MULTIPATH\r
+      if(flag&1<<9)                            /* if multipath move        */\r
+      {t=flag>>12;                             /* get dir. stepped twice   */\r
+       if(b[x+t]){if(b[y-2*t]|b[y-t])break;}else \r
+       if(b[x+2*t]&&b[y-t])break;              /* test if empty path exists*/\r
+      }\r
+#endif\r
+      m=E<16|(E^112)<16&&flag&1&y-E<2&E-y<2?I:m;      /* bad castling  */\r
+      if(p<3&y==E)H=z&127;                     /* shift capt.sqr. H if e.p.*/\r
+      t=b[H];\r
+      if(flag&1+!t)                            /* mode (capt/nonc) allowed?*/\r
+      {if(t&&(t&16)==k)break;                  /* capture own              */\r
+       i=w[t&15]+((t&192)>>sh);                /* value of capt. piece t   */\r
+       if(i<0)m=I,d=98;                        /* K capture                */\r
+       if(m>=l&d>1)goto C;                     /* abort on fail high       */\r
+       v=d-1?e:i-p;                            /*** MVV/LVA scoring if d=1**/\r
+       if(d-!t>1)                              /*** all captures if d=2  ***/\r
+       {v=centr[p]?b[x+257]-b[y+257]:0;        /* center positional pts.   */\r
+        b[G]=b[H]=b[x]=0;b[y]=u|32;            /* do move, set non-virgin  */\r
+        if(!(G&S))b[FF]=k+6,v+=50;             /* castling: put R & score  */\r
+        v-=w[p]>0|R<EG?0:20;                   /*** freeze K in mid-game ***/\r
+        if(p<3)                                /* pawns:                   */\r
+        {v-=9*((x-2&M||b[x-2]-u)+              /* structure, undefended    */\r
+               (x+2&M||b[x+2]-u)               /*        squares plus bias */\r
+              +(w[b[x^16]&15]<0))              /*** cling to magnetic K ***/\r
+              +(R-76>>2);                      /* end-game Pawn-push bonus */\r
+         b[y]+=V=y+r+1&S?647-p:2*(u&y+16&32);  /* upgrade P or convert to Q*/\r
+         V>>=sh;                               /* for Shatranj promo to F  */\r
+         i+=V;                                 /* promotion / passer bonus */\r
+        } if(z&S && GamePtr<6) v+=(rand()>>10&31)-16;\r
+        J+=J(0);Z+=J(4)+G-S;\r
+        SHAMAX( pl[k]-=!!t; )                  /* count pieces per side    */\r
+        v+=e+i;V=m>q?m:q;                      /*** new eval & alpha    ****/\r
+        C=d-1-(d>5&p>2&!t&!h);                 /* nw depth, reduce non-cpt.*/\r
+        C=R<EG|P-I|d<3||t&&p-3?C:d;            /* extend 1 ply if in-check */\r
+        do\r
+         s=C>2|v>V?-D(16-k,-l,-V,-v,/*** futility, recursive eval. of reply */\r
+                                     F,y&255,C):v;\r
+        W(s>q&++C<d); v=s;                     /* no fail:re-srch unreduced*/\r
+        if(z&S&&K-I)                           /* move pending: check legal*/\r
+        {if(v+I&&x==K&y==L)                    /*   if move found          */\r
+         {Q=-e-i;O=F;LL=L;\r
+          if(b[y]-u&15)b[y]-=PromPiece,        /* under-promotion, correct */\r
+                       J+=PromPiece;           /*  piece & invalidate hash */\r
+          a->D=99;a->V=0;                      /* lock game in hash as draw*/\r
+          R-=i/FAC;                            /*** total captd material ***/\r
+          Fifty = t|p<3?0:Fifty+1;\r
+                     return l;}                /*   & not in check, signal */\r
+         v=m;                                  /* (prevent fail-lows on    */\r
+        }                                      /*   K-capt. replies)       */\r
+        J=f;Z=g;\r
+        SHAMAX( pl[k]+=!!t; )\r
+        b[G]=k+6;b[FF]=b[y]=0;b[x]=u;b[H]=t;   /* undo move,G can be dummy */\r
+       }                                       /*          if non-castling */\r
+       if(v>m)                                 /* new best, update max,best*/\r
+        m=v,X=x,Y=y|S&F;                       /* mark non-double with S   */\r
+       if(h){h=0;goto A;}                      /* redo after doing old best*/\r
+      }\r
+      s=t;\r
+      if(flag&15^4|u&32||                      /* no double or moved before*/\r
+         p>2&&                                 /* no P & no lateral K move,*/\r
+         (b[G=r<0?x&~15:BW-1|x&112]-k-6        /* no virgin R in corner G, */\r
+         ||b[G^1]|b[G^2]|b[FF=r<0?G+3:G-2])    /* no 2 empty sq. next to R */\r
+        )t+=flag&4;                            /* fake capt. for nonsliding*/\r
+      else F=y;                                /* enable e.p.              */\r
+      if(s&&flag&8)t=0,flag^=flag>>4&15;       /* hoppers go to next phase */\r
+      if(!(flag&S))                            /* zig-zag piece?           */\r
+       r^=flag>>12,flag^=flag>>4&15;           /* alternate vector & mode  */\r
+     }W(!t);                                   /* if not capt. continue ray*/\r
+   }}\r
+   if((++x&15)>=BW)x=x+16&112;                 /* next sqr. of board, wrap */\r
+  }W(x-B);           \r
+C:FMAX( m=m+I|P==I?m:(X=Y=0); )                /* if stalemate, draw-score */\r
+  if(a->D<99)                                  /* protect game history     */\r
+   a->K=Z,a->V=m,a->D=d,a->X=X,                /* always store in hash tab */\r
+   a->F=8*(m>q)|S*(m<l),a->Y=Y;                /* move, type (bound/exact),*/\r
+  if(z&S&&Post){\r
+    printf("%2d ",d-2);\r
+    printf("%6d ",m);\r
+    printf("%8d %10d %c%c%c%c\n",(GetTickCount()-Ticks)/10,N,\r
+       'a'+(X&15),'8'-(X>>4),'a'+(Y&15),'8'-(Y>>4&7)),fflush(stdout);\r
+ }}                                            /*    encoded in X S,8 bits */\r
+if(z&4*S)K=X,L=Y&~S;\r
+ return m+=m<e;                                /* delayed-loss bonus       */\r
+}\r
+\r
+\r
+/* Generic main() for Winboard-compatible engine     */\r
+/* (Inspired by TSCP)                                */\r
+/* Author: H.G. Muller                               */\r
+\r
+/* The engine is invoked through the following       */\r
+/* subroutines, that can draw on the global vaiables */\r
+/* that are maintained by the interface:             */\r
+/* Side         side to move                         */\r
+/* Move         move input to or output from engine  */\r
+/* PromPiece    requested piece on promotion move    */\r
+/* TimeLeft     ms left to next time control         */\r
+/* MovesLeft    nr of moves to play within TimeLeft  */\r
+/* MaxDepth     search-depth limit in ply            */\r
+/* Post         boolean to invite engine babble      */\r
+\r
+/* InitEngine() progran start-up initialization      */\r
+/* InitGame()   initialization to start new game     */\r
+/*              (sets Side, but not time control)    */\r
+/* Think()      think up move from current position  */\r
+/*              (leaves move in Move, can be invalid */\r
+/*               if position is check- or stalemate) */\r
+/* DoMove()     perform the move in Move             */\r
+/*              (togglese Side)                      */\r
+/* ReadMove()   convert input move to engine format  */\r
+/* PrintMove()  print Move on standard output        */\r
+/* Legal()      check Move for legality              */\r
+/* ClearBoard() make board empty                     */\r
+/* PutPiece()   put a piece on the board             */\r
+\r
+/* define this to the codes used in your engine,     */\r
+/* if the engine hasn't defined it already.          */\r
+\r
+int PrintResult(int s)\r
+{\r
+        int i, j, k, cnt=0;\r
+\r
+        /* search last 50 states with this stm for third repeat */\r
+        for(j=2; j<=100 && j <= HistPtr; j+=2)\r
+        {\r
+            for(k=0; k<STATE; k++)\r
+                if(HistoryBoards[HistPtr][k] !=\r
+                   HistoryBoards[HistPtr-j&1023][k] )\r
+                   {\r
+                     goto differs;}\r
+            /* is the same, count it */\r
+            if(++cnt > 1) /* third repeat */\r
+            {\r
+                printf("1/2-1/2 {Draw by repetition}\n");\r
+                return 1;\r
+            }\r
+          differs: ;\r
+        }\r
+        K=I;\r
+        cnt = D(s,-I,I,Q,O,LL|4*S,3);\r
+        if(cnt>-I+1 && K==0 && L==0) {\r
+                printf("1/2-1/2 {Stalemate}\n");\r
+                return 2;\r
+        }\r
+        if(cnt==-I+1) {\r
+                if (s == WHITE)\r
+                        printf("0-1 {Black mates}\n");\r
+                else\r
+                        printf("1-0 {White mates}\n");\r
+                return 3;\r
+        }\r
+        if(Fifty >=100) {\r
+                printf("1/2-1/2 {Draw by fifty move rule}\n");\r
+                return 4;\r
+        }\r
+#ifdef SHATRANJ\r
+        if(pl[s]==1 && pl[16-s]==1) {\r
+                printf("1/2-1/2 {Insufficient mating material}\n");\r
+                return 4;\r
+        }\r
+        if(pl[s]<=1 && pl[16-s]>1) {\r
+                if (s == BLACK)\r
+                        printf("0-1 {Bare King}\n");\r
+                else\r
+                        printf("1-0 {Bare King}\n");\r
+                return 5;\r
+        }\r
+#endif\r
+        return 0;\r
+}\r
+\r
+\r
+InitEngine()\r
+{\r
+ int i, j;\r
+\r
+ N=32*S+7;W(N-->S+3)T[N]=rand()>>9;\r
+ srand(GetTickCount());\r
+}\r
+\r
+InitGame()\r
+{\r
+ int i,j;\r
+\r
+ for(i=0;i<16*BH;i++)b[i]=0;\r
+ K=BW;W(K--)\r
+ {b[K]=oo[K+16]+16;b[K+112]=oo[K];b[K+16]=18;b[K+96]=1; /* initial board setup*/\r
+  L=8;W(L--)b[16*L+K+257]=(K-BW/2)*(K-BW/2)+(L-3.5)*(L-3.5); /* center-pts table   */\r
+ }                                                   /*(in unused half b[])*/\r
+ Side = WHITE; Q=0; O=S;\r
+ Fifty = 0; R = 0;\r
+ for(i=0; i<BW; i++) if(i!=3) R += (w[oo[i]]/FAC) + (w[oo[i+16]]/FAC);\r
+ UnderProm = -1; pl[WHITE] = pl[BLACK] = 2*BW;\r
+}\r
+\r
+void CopyBoard(int s)\r
+{\r
+        int i, j, k, cnt=0;\r
+\r
+        /* copy game representation of engine to HistoryBoard */\r
+        /* don't forget castling rights and e.p. state!       */\r
+        for(i=0; i<BH; i++)\r
+        for(j=0; j<BW; j++)                 /* board squares  */\r
+            HistoryBoards[s][BW*i+j] = b[16*i+j]|64*(16*i+j==O);\r
+}\r
+                                         \r
+void PrintVariants()\r
+{\r
+        int i, j, count=0; char c, buf[80];\r
+        FILE *f;\r
+\r
+        f = fopen(INI_FILE, "r");\r
+        if(f==NULL) return;\r
+\r
+        /* search for game names in definition file */\r
+        do {\r
+           while(fscanf(f, "Game: %s", buf) != 1 && c != EOF) \r
+               while((c = fgetc(f)) != EOF && c != '\n');\r
+           if(c == EOF) break;\r
+           if(count++) printf(",");\r
+           printf("%s", buf);\r
+        } while(c != EOF);\r
+\r
+        fclose(f);\r
+}\r
+\r
+void PrintOptions()\r
+{\r
+       printf("feature option=\"Resign -check %d\"\n", Resign);\r
+       printf("feature option=\"Resign Threshold -spin %d 200 1200\"\n", Threshold);\r
+       printf("feature option=\"Ini File -file %s\"\n", inifile);\r
+       printf("feature option=\"Playing Style ;-) -combo Brilliant /// *Brave /// Beautiful\"\n");\r
+       printf("feature option=\"Dummy Slider Example -slider 20 0 100\"\n");\r
+       printf("feature option=\"Dummy String Example -file happy birthday!\"\n");\r
+       printf("feature option=\"Dummy Path Example -path .\"\n");\r
+       printf("feature option=\"Clear Hash -button\"\n");\r
+       printf("feature done=1\n");\r
+}\r
+                                         \r
+int LoadGame(char *name)\r
+{\r
+        int i, j, count=0; char c, buf[80];\r
+        static int currentVariant;\r
+        FILE *f;\r
+\r
+        f = fopen(inifile, "r");\r
+        if(f==NULL)\r
+        {   printf("telluser piece-desription file '%s'  not found\n", inifile);\r
+            exit(0);\r
+        }\r
+        if(fscanf(f, "version 4.8(%c)", &c)!=1 || c != 'w')\r
+        { printf("telluser incompatible fmax.ini file\n"); exit(0); }\r
+\r
+        if(name != NULL)\r
+        {  /* search for game name in definition file */\r
+           while(fscanf(f, "Game: %s", buf)!=1 || strcmp(name, buf) ) {\r
+               while((c = fgetc(f)) != EOF && c != '\n');\r
+               count++;\r
+               if(c == EOF) {\r
+                   printf("telluser variant %s not supported\n", name);\r
+                   fclose(f);\r
+                   return; /* keep old settings */\r
+               }\r
+           }\r
+           currentVariant = count;\r
+        }\r
+\r
+        /* We have found variant, or if none specified, are at beginning of file */\r
+        if(fscanf(f, "%dx%d", &BW, &BH)!=2 || BW>12 || BH!=8)\r
+        { printf("telluser unsupported board size %dx%d\n",BW,BH); exit(0); }\r
+\r
+        for(i=0; i<BW; i++) fscanf(f, "%d", oo+i);\r
+        for(i=0; i<BW; i++) fscanf(f, "%d", oo+i+16);\r
+        for(i= 0; i<=U; i++)\r
+            A[i].K = A[i].D = A[i].X = A[i].Y = A[i].F = 0; /* clear hash */\r
+        for(i=0; i<32; i++) piecetype[i] = 0;\r
+\r
+        i=0; j=-1; c=0;\r
+        while(fscanf(f, "%d,%x", o+j, of+j)==2 ||\r
+                                      fscanf(f,"%c:%d",&c, w+i+1)==2)\r
+        {   if(c)\r
+            { od[++i]=j; centr[i] = c>='a';\r
+              piecetype[c&31]=i; piecename[i]=c&31;\r
+            }\r
+            j++; o[j]=0;\r
+            /* printf("# c='%c' i=%d od[i]=%d j=%d (%3d,%8x)\n",c?c:' ',i,od[i],j,o[j-1],of[j-1]); /**/\r
+            c=0; if(i>15 || j>255) break;\r
+        }\r
+\r
+        fclose(f);\r
+       sh = w[7] < 250 ? 3 : 0;\r
+}\r
+\r
+int main(int argc, char **argv)\r
+{\r
+        int Computer, MaxTime, MaxMoves, TimeInc, sec, i, j;\r
+        char line[256], command[256], c, cc;\r
+        int m, nr;\r
+        FILE *f;\r
+\r
+        if(argc>1 && sscanf(argv[1], "%d", &m)==1)\r
+        { U = (1<<m)-1; argc--; argv++; }\r
+        A = (struct _ *) calloc(U+1, sizeof(struct _));\r
+        if(argc>1) inifile = argv[1];\r
+\r
+       signal(SIGINT, SIG_IGN);\r
+        printf("tellics say     " NAME " " VERSION "\n");\r
+        printf("tellics say     by H.G. Muller\n");\r
+        printf("tellics say Gothic Chess is protected by U.S. patent #6,481,716 by Ed Trice.\n");\r
+        printf("tellics say Falcon Chess is protected by U.S. patent #5,690,334 by George W. Duke\n");\r
+        InitEngine();\r
+        LoadGame(NULL);\r
+        InitGame();\r
+        Computer = EMPTY;\r
+        MaxTime  = 10000;  /* 10 sec */\r
+        MaxDepth = 30;     /* maximum depth of your search */\r
+\r
+        for (;;) {\r
+               fflush(stdout);\r
+                if (Side == Computer) {\r
+                        /* think up & do move, measure time used  */\r
+                        /* it is the responsibility of the engine */\r
+                        /* to control its search time based on    */\r
+                        /* MovesLeft, TimeLeft, MaxMoves, TimeInc */\r
+                        /* Next 'MovesLeft' moves have to be done */\r
+                        /* within TimeLeft+(MovesLeft-1)*TimeInc  */\r
+                        /* If MovesLeft<0 all remaining moves of  */\r
+                        /* the game have to be done in this time. */\r
+                        /* If MaxMoves=1 any leftover time is lost*/\r
+                        Ticks = GetTickCount();\r
+                        m = MovesLeft<=0 ? 40 : MovesLeft;\r
+                        tlim = (0.6-0.06*(BW-8))*(TimeLeft+(m-1)*TimeInc)/(m+7);\r
+                        if(tlim>TimeLeft/15) tlim = TimeLeft/15;\r
+                        PromPiece = 0; /* Always promote to Queen ourselves */\r
+                        N=0;K=I;\r
+                        if (D(Side,-I,I,Q,O,LL|S,3)==I) {\r
+                            Side ^= BLACK^WHITE;\r
+                            if(UnderProm>=0 && UnderProm != L)\r
+                            {    printf("tellics I hate under-promotions!\n");\r
+                                 printf("resign { underpromotion } \n");\r
+                                 Computer = EMPTY;\r
+                                 continue;\r
+                            } else UnderProm = -1;\r
+                            printf("move ");\r
+                            printf("%c%c%c%c",'a'+(K&15),'0'+BH-(K>>4),\r
+                                          'a'+(L&15),'0'+BH-(L>>4));\r
+                            printf("\n");\r
+                            m = GetTickCount() - Ticks;\r
+\r
+                            /* time-control accounting */\r
+                            TimeLeft -= m;\r
+                            TimeLeft += TimeInc;\r
+                            if(--MovesLeft == 0) {\r
+                                MovesLeft = MaxMoves;\r
+                                if(MaxMoves == 1)\r
+                                     TimeLeft  = MaxTime;\r
+                                else TimeLeft += MaxTime;\r
+                            }\r
+\r
+                            GameHistory[GamePtr++] = PACK_MOVE;\r
+                            CopyBoard(HistPtr=HistPtr+1&1023);\r
+                           if(Resign && Score <= -Threshold) { \r
+                               printf("resign\n"); Computer=EMPTY;\r
+                            } else if(PrintResult(Side))\r
+                                Computer = EMPTY;\r
+                        } else {\r
+                            if(!PrintResult(Side))\r
+                                printf("resign { refuses own move }\n");\r
+                            Computer = EMPTY;\r
+                        }\r
+                        continue;\r
+               }\r
+               if (!fgets(line, 256, stdin))\r
+                       return;\r
+               if (line[0] == '\n')\r
+                       continue;\r
+               sscanf(line, "%s", command);\r
+               if (!strcmp(command, "xboard"))\r
+                       continue;\r
+                if (!strcmp(command, "protover")) {\r
+                        printf("feature myname=\"" NAME " " VERSION "\"\n");\r
+                        printf("feature memory=1\n");\r
+                        printf("feature setboard=0 ping=1 done=0\n");\r
+                        printf("feature variants=\"");\r
+                        PrintVariants();\r
+                        printf("\"\n");\r
+                       PrintOptions();\r
+                        continue;\r
+                }\r
+                if (!strcmp(command, "ping")) { int nr=0;\r
+                        sscanf(line, "ping %d", &nr);\r
+                        printf("pong %d\n", nr);\r
+                       continue;\r
+                }\r
+                if (!strcmp(command, "p")) {\r
+                        pboard();\r
+                       continue;\r
+                }\r
+                if (!strcmp(command, "memory")) {\r
+                        int mem, mask;\r
+                       sscanf(line+6, "%d", &mem); mem = (mem*1024*1024)/12; // max nr of hash entries\r
+                       mask = 0x7FFFFFFF; while(mask > mem) mask >>= 1;\r
+                       if(mask != U) {\r
+                           free(A); U = mask;\r
+                           A = (struct _ *) calloc(U+1, sizeof(struct _));\r
+                       }\r
+                       continue;\r
+                }\r
+               if (!strcmp(command, "new")) {\r
+                        /* start new game */\r
+                        LoadGame("normal");\r
+                        InitGame();\r
+                        GamePtr   = Setup = 0;\r
+                        GameNr++;\r
+                        HistPtr   = 0;\r
+                        Computer  = BLACK;\r
+                        TimeLeft  = MaxTime;\r
+                        MovesLeft = MaxMoves;\r
+                        for(nr=0; nr<1024; nr++)\r
+                            for(m=0; m<STATE; m++)\r
+                                HistoryBoards[nr][m] = 0;\r
+                       continue;\r
+               }\r
+               if (!strcmp(command, "quit"))\r
+                        /* exit engine */\r
+                       return;\r
+               if (!strcmp(command, "force")) {\r
+                        /* computer plays neither */\r
+                        Computer = EMPTY;\r
+                       continue;\r
+               }\r
+               if (!strcmp(command, "white")) {\r
+                        /* set white to move in current position */\r
+                        Side     = WHITE;\r
+                        Computer = BLACK;\r
+                       continue;\r
+               }\r
+               if (!strcmp(command, "black")) {\r
+                        /* set blck to move in current position */\r
+                        Side     = BLACK;\r
+                        Computer = WHITE;\r
+                       continue;\r
+               }\r
+               if (!strcmp(command, "st")) {\r
+                        /* move-on-the-bell mode     */\r
+                        /* indicated by MaxMoves = 1 */\r
+                        sscanf(line, "st %d", &MaxTime);\r
+                        MovesLeft = MaxMoves = 1;\r
+                        TimeLeft  = MaxTime *= 1000;\r
+                        TimeInc   = 0;\r
+                       continue;\r
+               }\r
+               if (!strcmp(command, "sd")) {\r
+                        /* set depth limit (remains in force */\r
+                        /* until next 'sd n' command)        */\r
+                        sscanf(line, "sd %d", &MaxDepth);\r
+                        MaxDepth += 2; /* QS depth */\r
+                       continue;\r
+               }\r
+                if (!strcmp(command, "level")) {\r
+                        /* normal or blitz time control */\r
+                        sec = 0;\r
+                        if(sscanf(line, "level %d %d %d",\r
+                                 &MaxMoves, &MaxTime, &TimeInc)!=3 &&\r
+                           sscanf(line, "level %d %d:%d %d",\r
+                                 &MaxMoves, &MaxTime, &sec, &TimeInc)!=4)\r
+                             continue;\r
+                        MovesLeft = MaxMoves;\r
+                        TimeLeft  = MaxTime = 60000*MaxTime + 1000*sec;\r
+                        TimeInc  *= 1000;\r
+                        continue;\r
+                }\r
+               if (!strcmp(command, "time")) {\r
+                        /* set time left on clock */\r
+                        sscanf(line, "time %d", &TimeLeft);\r
+                        TimeLeft  *= 10; /* centi-sec to ms */\r
+                       continue;\r
+               }\r
+               if (!strcmp(command, "otim")) {\r
+                        /* opponent's time (not kept, so ignore) */\r
+                       continue;\r
+               }\r
+               if (!strcmp(command, "easy")) {\r
+                       continue;\r
+               }\r
+               if (!strcmp(command, "hard")) {\r
+                       continue;\r
+               }\r
+               if (!strcmp(command, "accepted")) {\r
+                       continue;\r
+               }\r
+               if (!strcmp(command, "rejected")) {\r
+                       continue;\r
+               }\r
+               if (!strcmp(command, "random")) {\r
+                       continue;\r
+               }\r
+               if (!strcmp(command, "option")) {\r
+                       int i; static char filename[80];\r
+                       if(sscanf(line+7, "Resign=%d", &Resign) == 1) continue;\r
+                       if(sscanf(line+7, "Resign Threshold=%d", &Threshold) == 1) continue;\r
+                       if(sscanf(line+7, "Ini File=%s", filename) == 1) {\r
+                               inifile = filename; continue;\r
+                       }\r
+                       if(sscanf(line+7, "Clear Hash") == 1) for(i=0; i<U; i++) A->K = 0;\r
+                       continue;\r
+               }\r
+               if (!strcmp(command, "go")) {\r
+                        /* set computer to play current side to move */\r
+                        Computer = Side;\r
+                        MovesLeft = -(GamePtr+(Side==WHITE)>>1);\r
+                        while(MaxMoves>0 && MovesLeft<=0)\r
+                            MovesLeft += MaxMoves;\r
+                       continue;\r
+               }\r
+               if (!strcmp(command, "hint")) {\r
+                        Ticks = GetTickCount(); tlim = 1000;\r
+                        D(Side,-I,I,Q,O,LL|4*S,6);\r
+                        if (K==0 && L==0)\r
+                               continue;\r
+                        printf("Hint: ");\r
+                        printf("%c%c%c%c",'a'+(K&7),'8'-(K>>4),\r
+                                          'a'+(L&7),'8'-(L>>4));\r
+                        printf("\n");\r
+                       continue;\r
+               }\r
+                if (!strcmp(command, "undo")   && (nr=1) ||\r
+                    !strcmp(command, "remove") && (nr=2)   ) {\r
+                        /* 'take back' moves by replaying game */\r
+                        /* from history until desired ply      */\r
+                        if (GamePtr - nr < 0)\r
+                               continue;\r
+                        GamePtr -= nr;\r
+                        HistPtr -= nr;   /* erase history boards */\r
+                        while(nr-- > 0)  \r
+                            for(m=0; m<STATE; m++)\r
+                                HistoryBoards[HistPtr+nr+1&1023][m] = 0;\r
+                        InitGame();\r
+                       if(Setup) {\r
+                           for(i=0; i<128; i++) b[i] = setupPosition[i];\r
+                           Side = setupPosition[128]; Q = SetupQ;\r
+                           pl[WHITE] = setupPosition[129];\r
+                           pl[BLACK] = setupPosition[130];\r
+                       }\r
+                       for(i=0; i<=U; i++) A[i].D = A[i].K = 0; // clear hash table\r
+                        for(nr=0; nr<GamePtr; nr++) {\r
+                            UNPACK_MOVE(GameHistory[nr]);\r
+                            D(Side,-I,I,Q,O,LL|S,3);\r
+                            Side ^= BLACK^WHITE;\r
+                        }\r
+                       continue;\r
+               }\r
+               if (!strcmp(command, "post")) {\r
+                        Post = 1;\r
+                       continue;\r
+               }\r
+               if (!strcmp(command, "nopost")) {\r
+                        Post = 0;\r
+                       continue;\r
+               }\r
+               if (!strcmp(command, "variant")) {\r
+                        sscanf(line, "variant %s", command);\r
+                        LoadGame(command);\r
+                        InitGame(); Setup = 0;\r
+                       continue;\r
+               }\r
+                if (!strcmp(command, "edit")) {\r
+                        int color = WHITE, p;\r
+\r
+                        while(fgets(line, 256, stdin)) {\r
+                                m = line[0];\r
+                                if(m=='.') break;\r
+                                if(m=='#') {\r
+                                        for(i=0; i<128; i++) b[i]=0;\r
+                                        Q=0; R=0; O=S;\r
+                                        pl[WHITE]=pl[BLACK]=0;\r
+                                        continue;\r
+                                }\r
+                                if(m=='c') {\r
+                                        color = WHITE+BLACK - color;\r
+                                        Q = -Q;\r
+                                        continue;\r
+                                }\r
+                                if( m >= 'A' && m <= 'Z' && piecetype[m&31]\r
+                                    && line[1] >= 'a' && line[1] <= 'a'+BW-1\r
+                                    && line[2] >= '1' && line[2] <= '0'+BH) {\r
+                                        m = line[1]-16*line[2]+799;\r
+                                        switch(p = piecetype[line[0]&31])\r
+                                        {\r
+                                        case 1:\r
+                                        case 2:\r
+                                            if(color==WHITE)\r
+                                                 b[m]=(m&0x70)==0x60?1:33,\r
+                                                 Q+=w[1];\r
+                                            else b[m]=(m&0x70)==0x10?18:50,\r
+                                                 Q+=w[2];\r
+                                            break;\r
+                                        case 3: // can castle, normally King\r
+                                            b[m]=3+color+32;\r
+                                            if(m==BW>>1        && color==BLACK ||\r
+                                               m==0x70+(BW>>1) && color==WHITE)\r
+                                                b[m] -= 32;\r
+                                            break;\r
+                                        case 6: // can castle, normally Rook\r
+                                            b[m]=6+color+32;\r
+                                            if((m==0x00 || m==BW-1   ) && color==BLACK ||\r
+                                               (m==0x70 || m==0x6F+BW) && color==WHITE)\r
+                                                b[m] -= 32;\r
+                                            Q+=w[6]; R+=w[6]/FAC;\r
+                                            break;\r
+                                        default:\r
+                                            b[m]=p+color;\r
+                                            Q+=w[p]; R+=w[p]/FAC;\r
+                                                   case 0: // undefined piece, ignore\r
+                                            break;\r
+                                        }\r
+                                        pl[BLACK+WHITE-color]++;\r
+                                        continue;\r
+                                }\r
+                        }\r
+                        if(Side != color) Q = -Q;\r
+                       GamePtr = HistPtr = 0; Setup = 1; SetupQ = Q; // start anew\r
+                       for(i=0; i<128; i++) setupPosition[i] = b[i]; // remember position\r
+                       setupPosition[128] = Side;\r
+                       setupPosition[129] = pl[WHITE];\r
+                       setupPosition[130] = pl[BLACK];\r
+                       continue;\r
+               }\r
+                /* command not recognized, assume input move */\r
+                m = line[0]<'a' | line[0]>='a'+BW | line[1]<'1' | line[1]>='1'+BH |\r
+                    line[2]<'a' | line[2]>='a'+BW | line[3]<'1' | line[3]>='1'+BH;\r
+                if(line[4] == '\n') line[4] = piecename[7];\r
+                PromPiece = 7 - piecetype[line[4]&31];\r
+                   if(PromPiece == 7) PromPiece = 0;\r
+                {char *c=line; K=c[0]-16*c[1]+799;L=c[2]-16*c[3]+799; }\r
+                if (m)\r
+                        /* doesn't have move syntax */\r
+                       printf("Error (unknown command): %s\n", command);\r
+                else if(D(Side,-I,I,Q,O,LL|S,3)!=I) {\r
+                        /* did have move syntax, but illegal move */\r
+                        printf("Illegal move:%s\n", line);\r
+                } else {  /* legal move, perform it */\r
+                        GameHistory[GamePtr++] = PACK_MOVE;\r
+                        Side ^= BLACK^WHITE;\r
+                        CopyBoard(HistPtr=HistPtr+1&1023);\r
+                        if(PrintResult(Side)) Computer = EMPTY;\r
+               }\r
+       }\r
+}\r
diff --git a/fmax.6.pod b/fmax.6.pod
new file mode 100644 (file)
index 0000000..5319169
--- /dev/null
@@ -0,0 +1,119 @@
+=head1 NAME
+
+fairymax - xboard-compatible chess and chess-variant engine 'Fairy-Max'
+
+
+=head1 SYNOPSIS
+
+B<fairymax> [hashSize] [iniFile]
+
+B<shamax> [hashSize] [iniFile]
+
+B<maxqi> [hashSize] [iniFile]
+
+
+=head1 DESCRIPTION
+
+B<fairymax> is a program that plays chess and chess variants. 
+It uses the xboard/winboard chess-engine protocol to communicate.
+Apart from 'regular' chess (also known as the Mad-Queen variant),
+it can play Capablanca chess, gothic chess, knightmate, cylinder chess, 
+berolina chess, superchess and courier chess.
+Fairy-Max can be easily configured by the user to play other variants as well,
+by modifying the ini file.
+This ini file describes the rules of movement
+of the participating pieces and the initial board setup.
+
+Fairy-Max can also play shatranj, 
+but in this case is not aware of the shatranj rule that a bare king loses.
+So it might play sub-optimally in the late end-game.
+A version of Fairy-Max adapted to implement the baring rule is
+available under the name B<shamax>.
+
+Similarly, a version of Fairy-Max adapted to play Xiang Qi (Chinese Chess)
+is included in the fmax package as well.
+
+B<fairymax> is a derivative of the world's (once) smallest chess program 
+(source-code wise), micro-Max.
+The latter measures less that 2000 characters, (about 100 code lines),
+and has a computer rating of around 2050 on the CCRL rating list.
+Although this is about 1000 rating points behind the world champion,
+micro-Max still makes a quite tough opponent even for club players,
+although it is not unbeatable.
+
+The main difference between micro-Max and Fairy-Max is that the latter loads
+its move-generator tables, which specify how the various pieces move,
+from an external file, so it can be easily adapted to incorporate un-orthodox pieces.
+For ease of use of the artificial-intelligence, Fairy-Max is equipped with
+I/O routines that allow it to run with the xboard graphical user interface.
+
+See xboard(6) for instructions about how to use B<fairymax> through xboard. To
+start up quickly, you just need the command: B<xboard -fcp fairymax>.
+However, XBoard might not support symbols for every unorthodox piece in board sizes
+different from B<bulky>, B<middling> and B<petite>.
+It might thius be adviasable to specify a board size as well, e.g.
+B<xboard -fcp shamax -boardSize middling -variant shatranj> 
+to get correct display of the elephant and general pieces in shatranj.
+Note that to be able to play the chess variants,
+you will need xboard 4.3.14 or later.
+
+The fmax.ini file from which Fairy-Max by default takes the piece and game definitions
+is a self-documenting text file,
+which contains instructions for how to define new pieces and chess variants.
+In addition it contains an extensive list of pre-defined pieces,
+incuding many not occurring in any of the pre-defined variants,
+which the user can draw on to define his own variants.
+
+Amongst the move types supported by Fairy-Max are normal leaper and slider moves,
+(e.g. knight and rook),
+divergent moves (i.e. capture and non-capture moves can be different)
+hoppers (which jump over other pieces, such as the Chinese cannon or the grasshopper),
+lame leapers (the move of which can be blocked on squares they cannot move to,
+such as the Chinese horse and elephant),
+and any combination thereof,
+in every possible direction.
+The board width is configurable upto a width of 14 squares,
+and cylindrical boards (where left and right edge connect) are supported as well.
+
+=head1 OPTIONS
+
+=over 8
+
+=item B<hashSize>
+
+If the first argument to fairymax is numeric,
+it is taken as an indicator for the amount of memory Fairy-Max is allowed to use
+for its internal hash table.
+The default value for this argument, 22, would result in a memory usage of 48MB.
+Each next-higher number doubles the memory usage, each next-lower halves it.
+Running with less than 6MB (i.e. argument 19) is not recommended.
+When fairymax is running under xboard 4.3.15 the hash-table size can be set 
+through the xboard menus,
+making this argument superfluous.
+
+=item B<iniFile>
+
+A second or non-numeric first argument is taken as a filename.
+Fairy-max will use the mentioned file in stead of its default fmax.ini file
+to define the movement of pieces and initial setup of the variants.
+This makes it easier to define your own variants.
+
+=back
+
+
+=head1 SEE ALSO
+
+xboard(6)
+
+http://www.chessvariants.org/index/msdisplay.php?itemid=MSfairy-max
+
+http://home.hccnet.nl/h.g.muller/max-src2.html
+
+http://www.open-aurec.com/wbforum/viewtopic.php?t=49439
+
+
+=head1 AUTHOR
+
+B<Fairy-Max> was written by H.G.Muller <h.g.muller@hccnet.nl>.
+
+This manual page was generated with pod2man(1).
diff --git a/maxqi.c b/maxqi.c
new file mode 100644 (file)
index 0000000..9b15595
--- /dev/null
+++ b/maxqi.c
@@ -0,0 +1,791 @@
+/***************************************************************************/\r
+/*                                 MaxQi,                                  */\r
+/* Version of the sub-2KB (source) micro-Max Chess program, fused to a     */\r
+/* generic WinBoard interface, loading its move-generator tables from file */\r
+/* Adapted to play Xiang Qi, which required rather specialized changes     */\r
+/***************************************************************************/\r
+/* micro-Max version 4.8 (~1950 characters) features:                      */\r
+/* - recursive negamax search                                              */\r
+/* - all-capture quiescence search with MVV/LVA priority                   */\r
+/* - (internal) iterative deepening                                        */\r
+/* - best-move-first 'sorting'                                             */\r
+/* - a hash table storing score and best move                              */\r
+/* - futility pruning                                                      */\r
+/* - king safety through magnetic frozen king                              */\r
+/* - null-move pruning                                                     */\r
+/* - Late-move reductions                                                  */\r
+/* - full FIDE rules (expt minor promotion) and move-legality checking     */\r
+/* - keep hash + rep-draw detect                                           */\r
+/* - end-game Pawn-push bonus, new piece values, gradual promotion         */\r
+/***************************************************************************/\r
+/* This version reads the piece description from a file fmax.ini           */\r
+/* The format supports many fairy pieces, including hoppers.               */\r
+/* f) now supports 15 piece types, by requisitioning WHITE bit             */\r
+/* g) supports larger board width.                                         */\r
+/* h) castling bug ('in-check by non-captures') corrected                  */\r
+/* i) rep-draw bug ('side-to-move') corrected                              */\r
+/* k) allow user underpromotions, recognize & ignore 'variant' command     */\r
+/* l) edit bug corrected (i & j file clear)                                */\r
+/* m) piece values no longer quantized, game-stage counting bug corrected  */\r
+/* n) edit-menu K-side castling bug corrected.                             */\r
+/* o) retrieve the requested variant from the .ini file                    */\r
+/* p) clear hash table on variant switch                                   */\r
+/* q) reduced piece-material count for better Pawn push                    */\r
+/* r) hash-table bug corrected (X still ORed with flags)                   */\r
+/* s) Bug that prevented initialization center points corrected            */\r
+/* t) castling bug after edit fixed                                        */\r
+/* u) converted to protocol 2; ping implemented                            */\r
+/* v) white e.p. rights hash bug fixed;                                    */\r
+/* w) piece indicators programable, multi-path support                     */\r
+/* x) e.p. changed to support Berolina Pawns                               */\r
+/* y) capture vlue of 6-7th-rank Pawn reduced in Shatranj                  */\r
+/* z) bug in promotion input corrected                                     */\r
+/* A) stalemate-detection bug in printResult fixed                         */\r
+/* B) Invalidate hash on game-level promotion (might be under-promotion!)  */\r
+/* C) King move evaluation based on negative piece value in stead of nr    */\r
+/* D) WB memory command added, undo fixed                                  */\r
+/* E) 15th piece read in                                                   */\r
+/* F) accepts ini fileargument                                             */\r
+/* Xiang Qi adaptations:                                                   */\r
+/*    orient board sideways for easy implementation of King-facing rule    */\r
+/*    allow board to have 9 rows (= files)                                 */\r
+/*    add array for specifying board zones                                 */\r
+/*    add zone limiter for each piece                                      */\r
+/*    change promotion code to act when crossing river                     */\r
+/*    remove stalemate code                                                */
+/* G) o[] and oo[] made int, to work on big-endian machines                */\r
+/***************************************************************************/\r
+\r
+     /*****************************************************************/\r
+     /*                      LICENCE NOTIFICATION                     */\r
+     /* Fairy-Max 4.8 is free software, and you have my permission do */\r
+     /* with it whatever you want, whether it is commercial or not.   */\r
+     /* Note, however, that Fairy-Max can easily be configured through*/\r
+     /* its fmax.ini file to play Chess variants that are legally pro-*/\r
+     /* tected by patents, and that to do so would also require per-  */\r
+     /* mission of the holders of such patents. No guarantees are     */\r
+     /* given that Fairy-Max does anything in particular, or that it  */\r
+     /* would not wreck the hardware it runs on, and running it is    */\r
+     /* entirely for your own risk.  H.G,Muller, author of Fairy-Max  */\r
+     /*****************************************************************/\r
+\r
+\r
+#define MULTIPATH\r
+\r
+/* fused to generic Winboard driver */\r
+\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+#include <signal.h>\r
+#include <time.h>\r
+\r
+#ifndef WIN32\r
+\r
+#include <sys/time.h>\r
+int GetTickCount() // with thanks to Tord\r
+{      struct timeval t;\r
+       gettimeofday(&t, NULL);\r
+       return t.tv_sec*1000 + t.tv_usec/1000;\r
+}\r
+#ifndef QINI_FILE 
+#define QINI_FILE "qmax.ini"
+#endif
+\r
+#else\r
+\r
+#include <windows.h>\r
+#define QINI_FILE "qmax.ini"\r
+\r
+#endif\r
+\r
+int StartKey;\r
+\r
+#define EMPTY -1\r
+#define WHITE 0\r
+#define BLACK 16\r
+\r
+#define STATE 128\r
+\r
+#define FAC 128\r
+\r
+/* make unique integer from engine move representation */\r
+#define PACK_MOVE 256*K + L;\r
+\r
+/* convert intger argument back to engine move representation */\r
+#define UNPACK_MOVE(A) K = (A)>>8 & 255; L = (A) & 255;\r
+\r
+/* Global variables visible to engine. Normally they */\r
+/* would be replaced by the names under which these  */\r
+/* are known to your engine, so that they can be     */\r
+/* manipulated directly by the interface.            */\r
+\r
+int Side;\r
+int Move;\r
+int PromPiece;\r
+int Result;\r
+int TimeLeft;\r
+int MovesLeft;\r
+int MaxDepth;\r
+int Post;\r
+int Fifty;\r
+int UnderProm;\r
+int GameNr;\r
+char piecename[32], piecetype[32], defaultchar[]=".PPKNBRQEWFMACHG";\r
+char *inifile = QINI_FILE;\r
+\r
+int Ticks, tlim, Setup, SetupQ;\r
+\r
+int GameHistory[1024];\r
+char HistoryBoards[1024][STATE], setupPosition[129];\r
+int GamePtr, HistPtr;\r
+\r
+#define W while\r
+#define K(A,B) *(int*)(T+A+((B&31)<<8))\r
+#define J(A) K(y+A,b[y])-K(x+A,u)-K(y+A,t)\r
+\r
+int U=(1<<23)-1;\r
+struct _ {int K,V;char X,Y,D,F;} *A;           /* hash table, 16M+8 entries*/\r
+\r
+int M=136,S=128,I=8e3,Q,O,K,N,j,R,J,Z,LL,L,    /* M=0x88                   */\r
+BW,BH,sh,\r
+w[16]={0,2,2,-1,7,8,12,23,7,5},                /* relative piece values    */\r
+o[256],\r
+oo[32],                                        /* initial piece setup      */\r
+of[256],\r
+od[16];                                        /* 1st dir. in o[] per piece*/\r
+\r
+signed char\r
+b[513],                                        /* board: 16x8+dummy, + PST */\r
+T[8200],                                       /* hash translation table   */\r
+centr[32],\r
+n[]=".P*KEEQQAHCR????x+pkeeqqahcr????";        /* piece symbols on printout*/\r
+\r
+char zn[] = {                                  /* zones of xiangqi board   */\r
+1,1,1,1,1,2,2,2,2,2,    0,0,0,0,0,0,\r
+1,1,1,1,1,2,2,2,2,2,    0,0,0,0,0,0,\r
+1,1,1,1,1,2,2,2,2,2,    0,0,0,0,0,0,\r
+0,0,0,1,1,2,2,0,0,0,    0,0,0,0,0,0,\r
+0,0,0,1,1,2,2,0,0,0,    0,0,0,0,0,0,\r
+0,0,0,1,1,2,2,0,0,0,    0,0,0,0,0,0,\r
+1,1,1,1,1,2,2,2,2,2,    0,0,0,0,0,0,\r
+1,1,1,1,1,2,2,2,2,2,    0,0,0,0,0,0,\r
+1,1,1,1,1,2,2,2,2,2,    0,0,0,0,0,0\r
+};\r
+\r
+pboard()\r
+{int i;\r
+ i=-1;W(++i<144)printf(" %c",(i&15)==BW&&(i+=15-BW)?10:n[b[i]&31]);\r
+}\r
+\r
+D(k,q,l,e,z,n)          /* recursive minimax search, k=moving side, n=depth*/\r
+int k,q,l,e,z,n;        /* (q,l)=window, e=current eval. score, E=e.p. sqr.*/\r
+{                       /* e=score, z=prev.dest; J,Z=hashkeys; return score*/\r
+ int j,r,m,v,d,h,i,P,V,f=J,g=Z,C,s,flag,F;\r
+ unsigned char t,p,u,x,y,X,Y,B,lu;\r
+ struct _*a=A+(J+k&U-1);                       /* lookup pos. in hash table*/\r
+ q-=q<e;l-=l<=e;                               /* adj. window: delay bonus */\r
+ d=a->D;m=a->V;F=a->F;                         /* resume at stored depth   */\r
+ X=a->X;Y=a->Y;                                /* start at best-move hint  */\r
+if(z&S&&a->K==Z)printf("# root hit %d %d %x\n",a->D,a->V,a->F);\r
+ if(a->K-Z|z&S  |                              /* miss: other pos. or empty*/\r
+  !(m<=q|F&8&&m>=l|F&S))                       /*   or window incompatible */\r
+  d=X=0,Y=-1;                                  /* start iter. from scratch */\r
+ W(d++<n||d<3||              /*** min depth = 2   iterative deepening loop */\r
+   z&S&&K==I&&(GetTickCount()-Ticks<tlim&d<=MaxDepth|| /* root: deepen upto time   */\r
+   (K=X,L=Y,d=3)))                             /* time's up: go do best    */\r
+ {x=B=X;lu=1;                                  /* start scan at prev. best */\r
+  h=Y-255;                                       /* if move, request 1st try */\r
+  P=d>2&&l+I?D(16-k,-l,1-l,-e,2*S,d-3):I;      /* search null move         */\r
+  m=-P<l|R<5?d-2?-I:e:-P;   /*** prune if > beta  unconsidered:static eval */\r
+  N++;                                         /* node count (for timing)  */\r
+  do{u=b[x];                                   /* scan board looking for   */\r
+   if(u)m=lu|u&15^3?m:(d=98,I),lu=u&15^3;        /* Kings facing each other  */\r
+   if(u&&(u&16)==k)                            /*  own piece (inefficient!)*/\r
+   {r=p=u&15;                                  /* p = piece type (set r>0) */\r
+    j=od[p];                                   /* first step vector f.piece*/\r
+    W(r=o[++j])                                /* loop over directions o[] */\r
+    {A:                                        /* resume normal after best */\r
+     flag=h?3:of[j];                           /* move modes (for fairies) */\r
+     y=x;                                      /* (x,y)=move               */\r
+     do{                                       /* y traverses ray, or:     */\r
+      y=h?Y:y+r;                               /* sneak in prev. best move */\r
+      if(y>=16*BH|(y&15)>=BW)break;            /* board edge hit           */\r
+      t=b[y];                                  /* captured piece           */\r
+      if(flag&1+!t)                            /* mode (capt/nonc) allowed?*/\r
+      {if(t&&(t&16)==k||flag>>10&zn[y])break;  /* capture own or bad zone  */\r
+       i=w[t&15];                              /* value of capt. piece t   */\r
+       if(i<0)m=I,d=98;                        /* K capture                */\r
+       if(m>=l&d>1)goto C;                     /* abort on fail high       */\r
+       v=d-1?e:i-p;                            /*** MVV/LVA scoring if d=1**/\r
+       if(d-!t>1)                              /*** all captures if d=2  ***/\r
+       {v=centr[p]?b[x+257]-b[y+257]:0;        /* center positional pts.   */\r
+        b[x]=0;b[y]=u;                         /* do move                  */\r
+        v-=w[p]>0|R<10?0:20;                   /*** freeze K in mid-game ***/\r
+        if(p<3)                                /* pawns:                   */\r
+        {v+=2;                                 /* end-game Pawn-push bonus */\r
+         if(zn[x]-zn[y])b[y]+=5,               /* upgrade Pawn and         */\r
+          i+=w[p+5]-w[p];                      /*          promotion bonus */\r
+        }\r
+        if(z&S && GamePtr<6) v+=(rand()>>10&31)-16; // randomize in root\r
+        J+=J(0);Z+=J(4);\r
+        v+=e+i;V=m>q?m:q;                      /*** new eval & alpha    ****/\r
+        C=d-1-(d>5&p>2&!t&!h);                 /* nw depth, reduce non-cpt.*/\r
+        C=R<10|P-I|d<3||t&&p-3?C:d;            /* extend 1 ply if in-check */\r
+        do\r
+         s=C>2|v>V?-D(16-k,-l,-V,-v,/*** futility, recursive eval. of reply */\r
+                                     0,C):v;\r
+        W(s>q&++C<d); v=s;                     /* no fail:re-srch unreduced*/\r
+        if(z&S&&K-I)                           /* move pending: check legal*/\r
+        {if(v+I&&x==K&y==L)                    /*   if move found          */\r
+         {Q=-e-i;\r
+          a->D=99;a->V=500;                    /* lock game in hash as loss*/\r
+          R-=i/FAC;                            /*** total captd material ***/\r
+          Fifty = t|p<3?0:Fifty+1;\r
+                     return l;}                /*   & not in check, signal */\r
+         v=m;                                  /* (prevent fail-lows on    */\r
+        }                                      /*   K-capt. replies)       */\r
+        J=f;Z=g;\r
+        b[y]=t;b[x]=u;                         /* undo move                */\r
+       }                                       /*          if non-castling */\r
+       if(v>m)                                 /* new best, update max,best*/\r
+        m=v,X=x,Y=y;                           /* no marking!              */\r
+       if(h){h=0;goto A;}                      /* redo after doing old best*/\r
+      }\r
+      s=t;\r
+      t+=flag&4;                               /* fake capt. for nonsliding*/\r
+      if(s&&flag&8)t=0,flag^=flag>>4&15;       /* hoppers go to next phase */\r
+      if(!(flag&S))                            /* zig-zag piece?           */\r
+       r^=flag>>12,flag^=flag>>4&15;           /* alternate vector & mode  */\r
+     }W(!t);                                   /* if not capt. continue ray*/\r
+   }}\r
+   if((++x&15)>=BW)x=x+16&240,lu=1;            /* next sqr. of board, wrap */\r
+   if(x>=16*BH)x=0;\r
+  }W(x-B);           \r
+C:if(a->D<99)                                  /* protect game history     */\r
+   a->K=Z,a->V=m,a->D=d,a->X=X,                /* always store in hash tab */\r
+   a->F=8*(m>q)|S*(m<l),a->Y=Y;                /* move, type (bound/exact),*/\r
+if(z&S&&Post){\r
+  printf("%2d ",d-2);\r
+  printf("%6d ",m);\r
+  printf("%8d %10d %c%c%c%c\n",(GetTickCount()-Ticks)/10,N,\r
+     'i'-(X>>4&15),'9'-(X&15),'i'-(Y>>4&15),'9'-(Y&15)),fflush(stdout);}\r
+ }                                             /*    encoded in X S,8 bits */\r
+if(z&4*S)K=X,L=Y&~S;\r
+ return m+=m<e;                                /* delayed-loss bonus       */\r
+}\r
+\r
+\r
+/* Generic main() for Winboard-compatible engine     */\r
+/* (Inspired by TSCP)                                */\r
+/* Author: H.G. Muller                               */\r
+\r
+/* The engine is invoked through the following       */\r
+/* subroutines, that can draw on the global vaiables */\r
+/* that are maintained by the interface:             */\r
+/* Side         side to move                         */\r
+/* Move         move input to or output from engine  */\r
+/* PromPiece    requested piece on promotion move    */\r
+/* TimeLeft     ms left to next time control         */\r
+/* MovesLeft    nr of moves to play within TimeLeft  */\r
+/* MaxDepth     search-depth limit in ply            */\r
+/* Post         boolean to invite engine babble      */\r
+\r
+/* InitEngine() progran start-up initialization      */\r
+/* InitGame()   initialization to start new game     */\r
+/*              (sets Side, but not time control)    */\r
+/* Think()      think up move from current position  */\r
+/*              (leaves move in Move, can be invalid */\r
+/*               if position is check- or stalemate) */\r
+/* DoMove()     perform the move in Move             */\r
+/*              (togglese Side)                      */\r
+/* ReadMove()   convert input move to engine format  */\r
+/* PrintMove()  print Move on standard output        */\r
+/* Legal()      check Move for legality              */\r
+/* ClearBoard() make board empty                     */\r
+/* PutPiece()   put a piece on the board             */\r
+\r
+/* define this to the codes used in your engine,     */\r
+/* if the engine hasn't defined it already.          */\r
+\r
+int PrintResult(int s)\r
+{\r
+        int i, j, k, cnt=0;\r
+\r
+        /* search last 50 states with this stm for third repeat */\r
+        for(j=2; j<=100 && j <= HistPtr; j+=2)\r
+        {\r
+            for(k=0; k<STATE; k++)\r
+                if(HistoryBoards[HistPtr][k] !=\r
+                   HistoryBoards[HistPtr-j&1023][k] )\r
+                   {\r
+                     goto differs;}\r
+            /* is the same, count it */\r
+            if(++cnt > 1) /* third repeat */\r
+            {\r
+                printf("1/2-1/2 {Draw by repetition}\n");\r
+                return 1;\r
+            }\r
+          differs: ;\r
+        }\r
+        K=I;\r
+        cnt = D(s,-I,I,Q,4*S,3);\r
+        if(cnt==0 && K==0 && L==0) {\r
+                printf("1/2-1/2 {Stalemate}\n");\r
+                return 2;\r
+        }\r
+        if(cnt==-I+1) {\r
+                if (s == WHITE)\r
+                        printf("0-1 {Black mates}\n");\r
+                else\r
+                        printf("1-0 {White mates}\n");\r
+                return 3;\r
+        }\r
+        if(Fifty >=100) {\r
+                printf("1/2-1/2 {Draw by fifty move rule}\n");\r
+                return 4;\r
+        }\r
+        return 0;\r
+}\r
+\r
+\r
+InitEngine()\r
+{\r
+ int i, j;\r
+\r
+ N=8100;W(N-->256)T[N]=rand()>>9;\r
+ srand(GetTickCount());\r
+}\r
+\r
+InitGame()\r
+{\r
+ int i,j;\r
+\r
+ for(i=0;i<16*BH;i++)b[i]=0;           /* clear board   */\r
+ b[23]=b[119]=10;b[BW+8]=b[BW+104]=26; /* place Cannons */\r
+ K=BH;W(K--)\r
+ {b[16*K]=oo[K+16]+16;b[16*K+BW-1]=oo[K];if(!(K&1))b[16*K+BW-7]=18,b[16*K+6]=1; /* initial board setup*/\r
+  L=BW;W(L--)b[L+16*K+257]=(K-(BW-1)/2.)*(K-(BW-1)/2.)+(L-(BH-1)/2.)*(L-(BH-1)/2.); /* center-pts table   */\r
+ }                                                   /*(in unused half b[])*/\r
+ Side = WHITE; Q=0; O=S;\r
+ Fifty = 0; R = 0;\r
+ for(i=0; i<BW; i++) if(i!=3) R += (w[oo[i]]/FAC) + (w[oo[i+16]]/FAC);\r
+ UnderProm = -1;\r
+}\r
+\r
+void CopyBoard(int s)\r
+{\r
+        int i, j, k, cnt=0;\r
+\r
+        /* copy game representation of engine to HistoryBoard */\r
+        /* don't forget castling rights and e.p. state!       */\r
+        for(i=0; i<BH; i++)\r
+        for(j=0; j<BW; j++)                 /* board squares  */\r
+            HistoryBoards[s][BW*i+j] = b[16*i+j]|64*(16*i+j==O);\r
+}\r
+                                         \r
+void PrintVariants()\r
+{\r
+        int i, j, count=0; char c, buf[80];\r
+        FILE *f;\r
+\r
+        f = fopen(inifile, "r");\r
+        if(f==NULL) return;\r
+\r
+        /* search for game names in definition file */\r
+        do {\r
+           while(fscanf(f, "Game: %s", buf) != 1 && c != EOF) \r
+               while((c = fgetc(f)) != EOF && c != '\n');\r
+           if(c == EOF) break;\r
+           if(count++) printf(",");\r
+           printf("%s", buf);\r
+        } while(c != EOF);\r
+\r
+        fclose(f);\r
+}\r
+                                         \r
+int LoadGame(char *name)\r
+{\r
+        int i, j, count=0; char c, buf[80];\r
+        static int currentVariant;\r
+        FILE *f;\r
+\r
+        f = fopen(inifile, "r");\r
+        if(f==NULL)\r
+        {   printf("telluser piece-desription file '%s'  not found\n", inifile);\r
+            exit(0);\r
+        }\r
+        if(fscanf(f, "version 4.8(%c)", &c)!=1 || c != 'w')\r
+        { printf("telluser incompatible qmax.ini file\n"); exit(0); }\r
+\r
+        if(name != NULL)\r
+        {  /* search for game name in definition file */\r
+           while(fscanf(f, "Game: %s", buf)!=1 || strcmp(name, buf) ) {\r
+               while((c = fgetc(f)) != EOF && c != '\n');\r
+               count++;\r
+               if(c == EOF) {\r
+                   printf("telluser variant %s not supported\n", name);\r
+                   fclose(f);\r
+                   return; /* keep old settings */\r
+               }\r
+           }\r
+           currentVariant = count;\r
+        }\r
+\r
+        /* We have found variant, or if none specified, are at beginning of file */\r
+        if(fscanf(f, "%dx%d", &BW, &BH)!=2 || BW>12 || BH>9)\r
+        { printf("telluser unsupported board size %dx%d\n",BW,BH); exit(0); }\r
+\r
+        for(i=0; i<BH; i++) fscanf(f, "%d", oo+i);\r
+        for(i=0; i<BH; i++) fscanf(f, "%d", oo+i+16);\r
+\r
+        for(i= 0; i<=U; i++)\r
+            A[i].K = A[i].D = A[i].X = A[i].Y = A[i].F = 0; /* clear hash */\r
+        for(i=0; i<32; i++) piecetype[i] = 0;\r
+\r
+        i=0; j=-1; c=0;\r
+        while(fscanf(f, "%d,%x", o+j, of+j)==2 ||\r
+                                      fscanf(f,"%c:%d",&c, w+i+1)==2)\r
+        {   if(c)\r
+            { od[++i]=j; centr[i] = c>='a';\r
+              piecetype[c&31]=i; piecename[i]=c&31;\r
+            }\r
+            j++; o[j]=0;\r
+            /* printf("tell c='%c' i=%d od[i]=%d j=%d (%3d,%8x)\n",c,i,od[i],j,o[j-1],of[j-1]); /**/\r
+            c=0; if(i>15 || j>255) break;\r
+        }\r
+\r
+        fclose(f);\r
+       sh = w[7] < 250 ? 3 : 0;\r
+}\r
+\r
+int main(int argc, char **argv)\r
+{\r
+        int Computer, MaxTime, MaxMoves, TimeInc, sec, i, j;\r
+        char line[256], command[256], c, cc;\r
+        int m, nr;\r
+        FILE *f;\r
+\r
+        if(argc>1 && sscanf(argv[1], "%d", &m)==1)\r
+        { U = (1<<m)-1; argc--; argv++; }\r
+        A = (struct _ *) calloc(U+1, sizeof(struct _));\r
+        if(argc>1) inifile = argv[1];\r
+\r
+       signal(SIGINT, SIG_IGN);\r
+        printf("tellics say     MaxQi 4.8 (G)\n");\r
+        printf("tellics say     by H.G. Muller\n");\r
+        InitEngine();\r
+        LoadGame(NULL);\r
+        InitGame();\r
+        Computer = EMPTY;\r
+        MaxTime  = 10000;  /* 10 sec */\r
+        MaxDepth = 30;     /* maximum depth of your search */\r
+\r
+        for (;;) {\r
+               fflush(stdout);\r
+                if (Side == Computer) {\r
+                        /* think up & do move, measure time used  */\r
+                        /* it is the responsibility of the engine */\r
+                        /* to control its search time based on    */\r
+                        /* MovesLeft, TimeLeft, MaxMoves, TimeInc */\r
+                        /* Next 'MovesLeft' moves have to be done */\r
+                        /* within TimeLeft+(MovesLeft-1)*TimeInc  */\r
+                        /* If MovesLeft<0 all remaining moves of  */\r
+                        /* the game have to be done in this time. */\r
+                        /* If MaxMoves=1 any leftover time is lost*/\r
+                        Ticks = GetTickCount();\r
+                        m = MovesLeft<=0 ? 40 : MovesLeft;\r
+                        tlim = (0.6-0.06*(BW-8))*(TimeLeft+(m-1)*TimeInc)/(m+7);\r
+                        if(tlim>TimeLeft/15) tlim = TimeLeft/15;\r
+                        PromPiece = 0; /* Always promote to Queen ourselves */\r
+                        N=0;K=I;\r
+                        if (D(Side,-I,I,Q,S,3)==I) {\r
+                            Side ^= BLACK^WHITE;\r
+                            if(UnderProm>=0 && UnderProm != L)\r
+                            {    printf("tellics I hate under-promotions!\n");\r
+                                 printf("resign { underpromotion } \n");\r
+                                 Computer = EMPTY;\r
+                                 continue;\r
+                            } else UnderProm = -1;\r
+                            printf("move ");\r
+                            printf("%c%c%c%c",'i'-(K>>4),'9'-(K&15),\r
+                                          'i'-(L>>4&15),'9'-(L&15));\r
+                            printf("\n");\r
+                            m = GetTickCount() - Ticks;\r
+\r
+                            /* time-control accounting */\r
+                            TimeLeft -= m;\r
+                            TimeLeft += TimeInc;\r
+                            if(--MovesLeft == 0) {\r
+                                MovesLeft = MaxMoves;\r
+                                if(MaxMoves == 1)\r
+                                     TimeLeft  = MaxTime;\r
+                                else TimeLeft += MaxTime;\r
+                            }\r
+\r
+                            GameHistory[GamePtr++] = PACK_MOVE;\r
+                            CopyBoard(HistPtr=HistPtr+1&1023);\r
+                            if(PrintResult(Side))\r
+                                Computer = EMPTY;\r
+                        } else {\r
+                            if(!PrintResult(Side))\r
+                                printf("resign { refuses own move }\n");\r
+                            Computer = EMPTY;\r
+                        }\r
+                        continue;\r
+               }\r
+               if (!fgets(line, 256, stdin))\r
+                       return;\r
+               if (line[0] == '\n')\r
+                       continue;\r
+               sscanf(line, "%s", command);\r
+               if (!strcmp(command, "xboard"))\r
+                       continue;\r
+                if (!strcmp(command, "protover")) {\r
+                        printf("feature myname=\"MaxQi 4.8G\"\n");\r
+                        printf("feature memory=1\n");\r
+                        printf("feature smp=1\n");\r
+                        printf("feature setboard=0 ping=1 done=0\n");\r
+                        printf("feature variants=\"");\r
+                        PrintVariants();\r
+                        printf("\" done=1\n");\r
+                        continue;\r
+                }\r
+                if (!strcmp(command, "ping")) { int nr=0;\r
+                        sscanf(line, "ping %d", &nr);\r
+                        printf("pong %d\n", nr);\r
+                       continue;\r
+                }\r
+                if (!strcmp(command, "p")) {\r
+                        pboard();\r
+                       continue;\r
+                }\r
+                if (!strcmp(command, "memory")) {\r
+                        int mem, mask;\r
+                       sscanf(line+6, "%d", &mem); mem = (mem*1024*1024)/12; // max nr of hash entries\r
+                       mask = 0x7FFFFFFF; while(mask > mem) mask >>= 1;\r
+                       if(mask != U) {\r
+                           free(A); U = mask;\r
+                           A = (struct _ *) calloc(U+1, sizeof(struct _));\r
+                       }\r
+                       continue;\r
+                }\r
+               if (!strcmp(command, "new")) {\r
+                        /* start new game */\r
+                        LoadGame("xiangqi");\r
+                        InitGame();\r
+                        GamePtr   = Setup = 0;\r
+                        GameNr++;\r
+                        HistPtr   = 0;\r
+                        Computer  = BLACK;\r
+                        TimeLeft  = MaxTime;\r
+                        MovesLeft = MaxMoves;\r
+                        for(nr=0; nr<1024; nr++)\r
+                            for(m=0; m<STATE; m++)\r
+                                HistoryBoards[nr][m] = 0;\r
+                       continue;\r
+               }\r
+               if (!strcmp(command, "quit"))\r
+                        /* exit engine */\r
+                       return;\r
+               if (!strcmp(command, "force")) {\r
+                        /* computer plays neither */\r
+                        Computer = EMPTY;\r
+                       continue;\r
+               }\r
+               if (!strcmp(command, "white")) {\r
+                        /* set white to move in current position */\r
+                        Side     = WHITE;\r
+                        Computer = BLACK;\r
+                       continue;\r
+               }\r
+               if (!strcmp(command, "black")) {\r
+                        /* set blck to move in current position */\r
+                        Side     = BLACK;\r
+                        Computer = WHITE;\r
+                       continue;\r
+               }\r
+               if (!strcmp(command, "st")) {\r
+                        /* move-on-the-bell mode     */\r
+                        /* indicated by MaxMoves = 1 */\r
+                        sscanf(line, "st %d", &MaxTime);\r
+                        MovesLeft = MaxMoves = 1;\r
+                        TimeLeft  = MaxTime *= 1000;\r
+                        TimeInc   = 0;\r
+                       continue;\r
+               }\r
+               if (!strcmp(command, "sd")) {\r
+                        /* set depth limit (remains in force */\r
+                        /* until next 'sd n' command)        */\r
+                        sscanf(line, "sd %d", &MaxDepth);\r
+                        MaxDepth += 2; /* QS depth */\r
+                       continue;\r
+               }\r
+                if (!strcmp(command, "level")) {\r
+                        /* normal or blitz time control */\r
+                        sec = 0;\r
+                        if(sscanf(line, "level %d %d %d",\r
+                                 &MaxMoves, &MaxTime, &TimeInc)!=3 &&\r
+                           sscanf(line, "level %d %d:%d %d",\r
+                                 &MaxMoves, &MaxTime, &sec, &TimeInc)!=4)\r
+                             continue;\r
+                        MovesLeft = MaxMoves;\r
+                        TimeLeft  = MaxTime = 60000*MaxTime + 1000*sec;\r
+                        TimeInc  *= 1000;\r
+                        continue;\r
+                }\r
+               if (!strcmp(command, "time")) {\r
+                        /* set time left on clock */\r
+                        sscanf(line, "time %d", &TimeLeft);\r
+                        TimeLeft  *= 10; /* centi-sec to ms */\r
+                       continue;\r
+               }\r
+               if (!strcmp(command, "otim")) {\r
+                        /* opponent's time (not kept, so ignore) */\r
+                       continue;\r
+               }\r
+               if (!strcmp(command, "easy")) {\r
+                       continue;\r
+               }\r
+               if (!strcmp(command, "hard")) {\r
+                       continue;\r
+               }\r
+               if (!strcmp(command, "accepted")) {\r
+                       continue;\r
+               }\r
+               if (!strcmp(command, "rejected")) {\r
+                       continue;\r
+               }\r
+               if (!strcmp(command, "random")) {\r
+                       continue;\r
+               }\r
+               if (!strcmp(command, "go")) {\r
+                        /* set computer to play current side to move */\r
+                        Computer = Side;\r
+                        MovesLeft = -(GamePtr+(Side==WHITE)>>1);\r
+                        while(MaxMoves>0 && MovesLeft<=0)\r
+                            MovesLeft += MaxMoves;\r
+                       continue;\r
+               }\r
+               if (!strcmp(command, "hint")) {\r
+                        Ticks = GetTickCount(); tlim = 1000;\r
+                        D(Side,-I,I,Q,4*S,6);\r
+                        if (K==0 && L==0)\r
+                               continue;\r
+                        printf("Hint: ");\r
+                        printf("%c%c%c%c",'a'+(K&7),'8'-(K>>4),\r
+                                          'a'+(L&7),'8'-(L>>4));\r
+                        printf("\n");\r
+                       continue;\r
+               }\r
+                if (!strcmp(command, "undo")   && (nr=1) ||\r
+                    !strcmp(command, "remove") && (nr=2)   ) {\r
+                        /* 'take back' moves by replaying game */\r
+                        /* from history until desired ply      */\r
+                        if (GamePtr - nr < 0)\r
+                               continue;\r
+                        GamePtr -= nr;\r
+                        HistPtr -= nr;   /* erase history boards */\r
+                        while(nr-- > 0)  \r
+                            for(m=0; m<STATE; m++)\r
+                                HistoryBoards[HistPtr+nr+1&1023][m] = 0;\r
+                        InitGame();\r
+                       if(Setup) {\r
+                           for(i=0; i<128; i++) b[i] = setupPosition[i];\r
+                           Side = setupPosition[128]; Q = SetupQ;\r
+                       }\r
+                       for(i=0; i<=U; i++) A[i].D = A[i].K = 0; // clear hash table\r
+                        for(nr=0; nr<GamePtr; nr++) {\r
+                            UNPACK_MOVE(GameHistory[nr]);\r
+                            D(Side,-I,I,Q,S,3);\r
+                            Side ^= BLACK^WHITE;\r
+                        }\r
+                       continue;\r
+               }\r
+               if (!strcmp(command, "post")) {\r
+                        Post = 1;\r
+                       continue;\r
+               }\r
+               if (!strcmp(command, "nopost")) {\r
+                        Post = 0;\r
+                       continue;\r
+               }\r
+               if (!strcmp(command, "variant")) {\r
+                        sscanf(line, "variant %s", command);\r
+                        LoadGame(command);\r
+                        InitGame(); Setup = 0;\r
+                       continue;\r
+               }\r
+                if (!strcmp(command, "edit")) {\r
+                        int color = WHITE, p;\r
+\r
+                        while(fgets(line, 256, stdin)) {\r
+                                m = line[0];\r
+                                if(m=='.') break;\r
+                                if(m=='#') {\r
+                                        for(i=0; i<128; i++) b[i]=0;\r
+                                        Q=0; R=0; O=S;\r
+                                        continue;\r
+                                }\r
+                                if(m=='c') {\r
+                                        color = WHITE+BLACK - color;\r
+                                        Q = -Q;\r
+                                        continue;\r
+                                }\r
+                                if( m >= 'A' && m <= 'Z'\r
+                                    && line[1] >= 'a' && line[1] <= 'a'+BH-1\r
+                                    && line[2] >= '0' && line[2] <= '0'+BW-1) {\r
+                                        m = 16*('i'-line[1])+'9'-line[2];\r
+                                        p = 4; /* Elephant code */\r
+                                        switch(line[0])\r
+                                        {\r
+                                        case 'K':\r
+                                            b[m]=3+color;\r
+                                            break;\r
+                                        case 'R': p++;\r
+                                        case 'C': p++;\r
+                                        case 'H': p++;\r
+                                        case 'A': p+=4;\r
+                                            b[m]=p+color;\r
+                                            Q+=w[p]; R+=w[p]/FAC;\r
+                                            break;\r
+                                        case 'P':\r
+                                            if((color==WHITE) == ((m&15)<5))\r
+                                                p = 6; else p = 1;\r
+                                        case 'E': p+=(color==BLACK);\r
+                                            b[m]=p+color;\r
+                                            Q+=w[p]; R+=w[p]/FAC;\r
+                                            break;\r
+                                        }\r
+                                        continue;\r
+                                }\r
+                        }\r
+                        if(Side != color) Q = -Q;\r
+                       GamePtr = HistPtr = 0; Setup = 1; SetupQ = Q; // start anew\r
+                       for(i=0; i<128; i++) setupPosition[i] = b[i]; // remember position\r
+                       setupPosition[128] = Side;\r
+                       continue;\r
+               }\r
+                /* command not recognized, assume input move */\r
+                m = line[0]<'a' | line[0]>='a'+BH | line[1]<'0' | line[1]>='0'+BW |\r
+                    line[2]<'a' | line[2]>='a'+BH | line[3]<'0' | line[3]>='0'+BW |\r
+                    line[4] != '\n';\r
+                {char *c=line; K=16*('i'-c[0])+'9'-c[1];\r
+                               L=16*('i'-c[2])+'9'-c[3]; }\r
+                if (m)\r
+                        /* doesn't have move syntax */\r
+                       printf("Error (unknown command): %s\n", command);\r
+                else if(D(Side,-I,I,Q,S,3)!=I) {\r
+                        /* did have move syntax, but illegal move */\r
+                        printf("Illegal move:%s\n", line);\r
+                } else {  /* legal move, perform it */\r
+                        GameHistory[GamePtr++] = PACK_MOVE;\r
+                        Side ^= BLACK^WHITE;\r
+                        CopyBoard(HistPtr=HistPtr+1&1023);\r
+                        if(PrintResult(Side)) Computer = EMPTY;\r
+               }\r
+       }\r
+}\r
+\r
+\r
+\r