--- /dev/null
+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
+
--- /dev/null
+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
+
--- /dev/null
+/***************************************************************************/
+/* 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
--- /dev/null
+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>.
+
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+.\" 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).
--- /dev/null
+/***************************************************************************/\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
--- /dev/null
+=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).
--- /dev/null
+/***************************************************************************/\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