Check-in modifications made by HGM so far
authorH.G. Muller <h.g.muller@hccnet.nl>
Mon, 18 Jan 2010 12:20:48 +0000 (13:20 +0100)
committerH.G. Muller <h.g.muller@hccnet.nl>
Mon, 18 Jan 2010 12:20:48 +0000 (13:20 +0100)
This is the version of the variant ICS that first started running
permanently on my ADSL connection.

23 files changed:
lasker-2.2.3/data/boards/wild/CVS/Entries [deleted file]
lasker-2.2.3/data/boards/wild/CVS/Repository [deleted file]
lasker-2.2.3/data/boards/wild/CVS/Root [deleted file]
lasker-2.2.3/src/Makefile.in
lasker-2.2.3/src/algcheck.c [changed mode: 0644->0755]
lasker-2.2.3/src/board.c
lasker-2.2.3/src/board.h
lasker-2.2.3/src/command.c
lasker-2.2.3/src/config.h
lasker-2.2.3/src/eco.c [changed mode: 0644->0755]
lasker-2.2.3/src/gamedb.c
lasker-2.2.3/src/gamedb.h
lasker-2.2.3/src/gamedb_old.c
lasker-2.2.3/src/gameproc.c
lasker-2.2.3/src/help.c
lasker-2.2.3/src/matchproc.c
lasker-2.2.3/src/movecheck.c [changed mode: 0644->0755]
lasker-2.2.3/src/movecheck.h [changed mode: 0644->0755]
lasker-2.2.3/src/obsproc.c
lasker-2.2.3/src/setup.c
lasker-2.2.3/src/talkproc.c
lasker-2.2.3/src/utils.c
lasker-2.2.3/src/variable.c

diff --git a/lasker-2.2.3/data/boards/wild/CVS/Entries b/lasker-2.2.3/data/boards/wild/CVS/Entries
deleted file mode 100644 (file)
index 1784810..0000000
+++ /dev/null
@@ -1 +0,0 @@
-D
diff --git a/lasker-2.2.3/data/boards/wild/CVS/Repository b/lasker-2.2.3/data/boards/wild/CVS/Repository
deleted file mode 100644 (file)
index 5cc55ef..0000000
+++ /dev/null
@@ -1 +0,0 @@
-lasker/data/boards/wild
diff --git a/lasker-2.2.3/data/boards/wild/CVS/Root b/lasker-2.2.3/data/boards/wild/CVS/Root
deleted file mode 100644 (file)
index c42ba94..0000000
+++ /dev/null
@@ -1 +0,0 @@
-/home/cvs
index 7e465f8..24cb2df 100644 (file)
@@ -126,6 +126,21 @@ install: $(ALL)
        install -d -m0755 ${CHESSDDIR}/data/messages
        install -d -m0755 ${CHESSDDIR}/data/stats
        install -d -m0755 ${CHESSDDIR}/data/boards/wild
+       install -d -m0755 ${CHESSDDIR}/data/boards/capablanca
+       install -d -m0755 ${CHESSDDIR}/data/boards/knightmate
+       install -d -m0755 ${CHESSDDIR}/data/boards/gothic
+       install -d -m0755 ${CHESSDDIR}/data/boards/super
+       install -d -m0755 ${CHESSDDIR}/data/boards/crazyhouse
+       install -d -m0755 ${CHESSDDIR}/data/boards/fischerandom
+       install -d -m0755 ${CHESSDDIR}/data/boards/fr
+       install -d -m0755 ${CHESSDDIR}/data/boards/zh
+       install -d -m0755 ${CHESSDDIR}/data/boards/shatranj
+       install -d -m0755 ${CHESSDDIR}/data/boards/xiangqi
+       install -d -m0755 ${CHESSDDIR}/data/boards/shogi
+       install -d -m0755 ${CHESSDDIR}/data/boards/caparandom
+       install -d -m0755 ${CHESSDDIR}/data/boards/courier
+       install -d -m0755 ${CHESSDDIR}/data/boards/fairy
+       install -d -m0755 ${CHESSDDIR}/data/boards/great
        install -d -m0755 ${CHESSDDIR}/games/history
        install -d -m0755 ${CHESSDDIR}/games/journal
        install -d -m0755 ${CHESSDDIR}/games/adjourned
@@ -135,6 +150,20 @@ install: $(ALL)
        cp -u ${srcdir}/../data/help/[a-z]* ${CHESSDDIR}/data/help
        cp -u ${srcdir}/../data/usage/[a-z]* ${CHESSDDIR}/data/usage
        cp -u ${srcdir}/../data/messages/[a-z]* ${CHESSDDIR}/data/messages
+       cp -u ${srcdir}/../data/boards/capablanca/* ${CHESSDDIR}/data/boards/capablanca
+       cp -u ${srcdir}/../data/boards/gothic/* ${CHESSDDIR}/data/boards/gothic
+       cp -u ${srcdir}/../data/boards/knightmate/* ${CHESSDDIR}/data/boards/knightmate
+       cp -u ${srcdir}/../data/boards/fischerandom/* ${CHESSDDIR}/data/boards/fischerandom
+       cp -u ${srcdir}/../data/boards/shatranj/* ${CHESSDDIR}/data/boards/shatranj
+       cp -u ${srcdir}/../data/boards/crazyhouse/* ${CHESSDDIR}/data/boards/crazyhouse
+       cp -u ${srcdir}/../data/boards/super/* ${CHESSDDIR}/data/boards/super
+       cp -u ${srcdir}/../data/boards/wild/* ${CHESSDDIR}/data/boards/wild
+       cp -u ${srcdir}/../data/boards/xiangqi/* ${CHESSDDIR}/data/boards/xiangqi
+       cp -u ${srcdir}/../data/boards/shogi/* ${CHESSDDIR}/data/boards/shogi
+       cp -u ${srcdir}/../data/boards/courier/* ${CHESSDDIR}/data/boards/courier
+       cp -u ${srcdir}/../data/boards/fairy/* ${CHESSDDIR}/data/boards/fairy
+       cp -u ${srcdir}/../data/boards/great/* ${CHESSDDIR}/data/boards/great
+       cp -u ${srcdir}/../data/boards/caparandom/* ${CHESSDDIR}/data/boards/caparandom
        perl -e 'mkdir("${CHESSDDIR}/players/$$_",0755) for ("a".."z")'
        perl -e 'mkdir("${CHESSDDIR}/games/history/$$_",0755) for ("0".."99")'
        perl -e 'mkdir("${CHESSDDIR}/games/journal/$$_",0755) for ("a".."z")'
old mode 100644 (file)
new mode 100755 (executable)
index 32bdba1..d043445
@@ -96,7 +96,7 @@ static int get_move_info(const char *str, int *piece, int *ff, int *fr, int *tf,
     for (j = len - 1; j >= 0; j--) {
       switch (alg_list[i][j]) {
       case 'f':
-       if ((tmp[j] < 'a') || (tmp[j] > 'h'))
+       if ((tmp[j] < 'a') || (tmp[j] > 'l')) // [HGM] upto l-file
          goto nomatch;
        if (ltf == ALG_UNKNOWN)
          ltf = tmp[j] - 'a';
@@ -104,12 +104,12 @@ static int get_move_info(const char *str, int *piece, int *ff, int *fr, int *tf,
          lff = tmp[j] - 'a';
        break;
       case 'r':
-       if ((tmp[j] < '1') || (tmp[j] > '8'))
+       if ((tmp[j] < '0') || (tmp[j] > '9')) // [HGM] also match 0- and 9-rank
          goto nomatch;
-       if (ltr == ALG_UNKNOWN)
-         ltr = tmp[j] - '1';
-       else
-         lfr = tmp[j] - '1';
+       if (ltr == ALG_UNKNOWN)\r
+         ltr = tmp[j] - '0'; // [HGM] allow 0-rank for Xiangqi, correct later\r
+       else\r
+         lfr = tmp[j] - '0';
        break;
       case 'p':
        if (isupper(tmp[j]))
@@ -118,8 +118,32 @@ static int get_move_info(const char *str, int *piece, int *ff, int *fr, int *tf,
          c = tmp[j];
        if (c == 'k')
          lpiece = KING;
+       else if (c == 'e')   // [HGM] note that som piece indicators are ambiguous,
+         lpiece = ELEPHANT; //       and their true meaning depends on the variant,
+       else if (c == 'v')   //       which we do not know at this point.
+         lpiece = CENTAUR;
+       else if (c == 's')
+         lpiece = SILVER;
+       else if (c == 'g')
+         lpiece = GOLD;
+       else if (c == 'l')
+         lpiece = LANCE;
+       else if (c == 'f')
+         lpiece = FERZ;
+       else if (c == 'h')
+         lpiece = HORSE;
+       else if (c == 'w')
+         lpiece = WAZIR;
+       else if (c == 'o')
+         lpiece = SQUIRREL;
        else if (c == 'q')
          lpiece = QUEEN;
+       else if (c == 'c')
+         lpiece = MARSHALL;
+       else if (c == 'a')
+         lpiece = CARDINAL;
+       else if (c == 'm')
+         lpiece = MAN;
        else if (c == 'r')
          lpiece = ROOK;
        else if (c == 'b')
@@ -190,7 +214,7 @@ int alg_is_move(const char *mstr)
 static void add_promotion(struct game_state_t *gs, const char *mstr, struct move_t * mt)
 {
        char *s;
-       int piece;
+       int piece, i;
        s = strchr(mstr, '=');
        if (s == NULL) {
                return;
@@ -199,14 +223,29 @@ static void add_promotion(struct game_state_t *gs, const char *mstr, struct move
        if (piecetype(gs->board[mt->fromFile][mt->fromRank]) != PAWN) {
                return;
        }
-       if (mt->toRank != 7 && mt->toRank != 0) {
+       if (mt->toRank != gs->ranks-1 && mt->toRank != 0) {
                return;
        }
 
        switch (tolower(s[1])) {
+       case 'f':
+               piece = FERZ2;
+               break;
        case 'q':
                piece = QUEEN;
                break;
+       case 'c':\r
+               if(!gs->capablancaPieces) return; // [HGM] should make variant-dependent piece mask\r
+               piece = MARSHALL;\r
+               break;\r
+       case 'a':\r
+               if(!gs->capablancaPieces) return;\r
+               piece = CARDINAL;\r
+               break;\r
+       case 'm':\r
+               if(!gs->royalKnight) return; // [HGM] only in knightmate\r
+               piece = MAN;\r
+               break;\r
        case 'r':
                piece = ROOK;
                break;
@@ -214,12 +253,35 @@ static void add_promotion(struct game_state_t *gs, const char *mstr, struct move
                piece = BISHOP;
                break;
        case 'n':
+               if(gs->royalKnight) return; // [HGM] not in knightmate\r
                piece = KNIGHT;
                break;
+       // Superchess promotons: filtered out later by promoType
+       case 'g':
+               piece = MASTODON;
+               break;
+       case 'o':
+               piece = SQUIRREL;
+               break;
+       case 'w':
+               piece = WOODY;
+               break;
+       case 'v':
+               piece = CENTAUR;
+               break;
+       case 'e':\r
+               piece = EMPRESS;
+               break;
+       case 's':
+               piece = PRINCESS;
+               break;
        default:
                return;
        }
 
+       i = colorval(gs->board[mt->fromFile][mt->fromRank]) == WHITE ? 0 : 1;
+       if(piece >= WOODY && (gs->promoType != 2 || gs->holding[i][piece-1] == 0)) return;
+
        mt->piecePromotionTo = piece | colorval(gs->board[mt->fromFile][mt->fromRank]);
 }
 
@@ -233,6 +295,56 @@ int alg_parse_move(char *mstr, struct game_state_t * gs, struct move_t * mt)
     d_printf( "CHESSD: Shouldn't try to algebraicly parse non-algabraic move string.\n");
     return MOVE_ILLEGAL;
   }
+  \r
+  // [HGM] check if move does not stray off board\r
+  if(gs->ranks < 10) { \r
+    if(tr == 0 || fr == 0) return MOVE_ILLEGAL; // used nonexistent 0-rank\r
+    if(tr != ALG_UNKNOWN) tr--; if(fr != ALG_UNKNOWN) fr--; // shift to lowest rank = 1\r
+  }\r
+  if(tr >= gs->ranks || fr >= gs->ranks || tf >= gs->files || ff >= gs->files)\r
+    return MOVE_ILLEGAL;\r
+
+  // [HGM] resolve ambiguity in piece, type based on variant
+  switch(piece) {
+    case ELEPHANT:
+      if(strstr(gs->variant, "super"))   piece = EMPRESS; else
+      if(strstr(gs->variant, "great"))   piece = MODERNELEPHANT; else
+      if(strstr(gs->variant, "courier")) piece = ALFIL2;
+      break;
+    case CARDINAL:
+      if(strstr(gs->variant, "super")) piece = AMAZON; else
+      if(strstr(gs->variant, "xiangqi")) piece = MANDARIN;
+      break;
+    case MARSHALL:
+      if(strstr(gs->variant, "xiangqi")) piece = CANNON;
+      break;
+    case SILVER:
+      if(strstr(gs->variant, "super")) piece = PRINCESS;
+      if(strstr(gs->variant, "great")) piece = MAN2;
+      break;
+    case BISHOP:
+      if(strstr(gs->variant, "shatranj")) piece = ALFIL;
+      break;
+    case QUEEN:
+      if(strstr(gs->variant, "shatranj")) piece = FERZ;
+      break;
+    case WAZIR:
+      if(strstr(gs->variant, "super")) piece = WOODY;
+      break;
+    case KNIGHT:
+      if(strstr(gs->variant, "shogi")) piece = HONORABLEHORSE;
+      break;
+    case MAN:
+      if(strstr(gs->variant, "great")) piece = MINISTER;
+      break;
+    case HORSE:
+      if(strstr(gs->variant, "great")) piece = PRIESTESS;
+      break;
+    case GOLD:
+      if(strstr(gs->variant, "great")) piece = MASTODON;
+      break;
+  }
+\r
   /* Resolve ambiguities in to-ness */
   if (tf == ALG_UNKNOWN) {
          d_printf("Ambiguous %s(%d)\n", __FUNCTION__, __LINE__);
@@ -250,7 +362,7 @@ int alg_parse_move(char *mstr, struct game_state_t * gs, struct move_t * mt)
     }
     /* Need to find pawn on ff that can take to tf and fill in ranks */
     for (InitPieceLoop(gs->board, &f, &r, gs->onMove);
-        NextPieceLoop(gs->board, &f, &r, gs->onMove);) {
+        NextPieceLoop(gs->board, &f, &r, gs->onMove, gs->files, gs->ranks);) {
       if ((ff != ALG_UNKNOWN) && (ff != f))
        continue;
       if (piecetype(gs->board[f][r]) != piece)
@@ -286,25 +398,27 @@ int alg_parse_move(char *mstr, struct game_state_t * gs, struct move_t * mt)
     ff = ALG_UNKNOWN;
     fr = ALG_UNKNOWN;
     for (InitPieceLoop(gs->board, &f, &r, gs->onMove);
-        NextPieceLoop(gs->board, &f, &r, gs->onMove);) {
-           if ((piecetype(gs->board[f][r]) != PAWN) && (piecetype(gs->board[f][r]) != BISHOP)) {
+        NextPieceLoop(gs->board, &f, &r, gs->onMove, gs->files, gs->ranks);) {
+           if ((piecetype(gs->board[f][r]) != PAWN) && (piecetype(gs->board[f][r]) != piece)) {
+                   // note that the interpretation Bxc4 is matched last, and has set piece to BISHOP
                    continue;
            }
+
            if (legal_andcheck_move(gs, f, r, tf, tr)) {
-                   if ((piecetype(gs->board[f][r]) == PAWN) && (f != 1)) {
+                   if ((piecetype(gs->board[f][r]) == PAWN) && (f != tolower(mstr[0]) - 'a')) {
                            continue;
                    }
 
                    /* if its a lowercase 'b' then prefer the pawn move if there is one */
                    if ((ff != ALG_UNKNOWN) && (fr != ALG_UNKNOWN) &&
-                       piecetype(gs->board[f][r]) == PAWN && mstr[0] == 'b') {
+                       piecetype(gs->board[f][r]) == PAWN && mstr[0] >= 'a') {
                            ff = f;
                            fr = r;
                            continue;
                    }
 
                    if ((ff != ALG_UNKNOWN) && (fr != ALG_UNKNOWN) &&
-                       piecetype(gs->board[ff][fr]) == PAWN && mstr[0] == 'b') {
+                       piecetype(gs->board[ff][fr]) == PAWN && mstr[0] >= 'a') {
                            continue;
                    }
 
@@ -322,7 +436,7 @@ int alg_parse_move(char *mstr, struct game_state_t * gs, struct move_t * mt)
     if ((ff == ALG_UNKNOWN) || (fr == ALG_UNKNOWN)) {
       /* Need to find a piece that can go to tf, tr */
       for (InitPieceLoop(gs->board, &f, &r, gs->onMove);
-          NextPieceLoop(gs->board, &f, &r, gs->onMove);) {
+          NextPieceLoop(gs->board, &f, &r, gs->onMove, gs->files, gs->ranks);) {
        if ((ff != ALG_UNKNOWN) && (ff != f))
          continue;
        if ((fr != ALG_UNKNOWN) && (fr != r))
@@ -381,20 +495,21 @@ char *alg_unparse(struct game_state_t * gs, struct move_t * mt)
     piece = piecetype(gs->board[mt->fromFile][mt->fromRank]);
   }
 
-  if ((piece == KING) && ((mt->fromFile == 4) && (mt->toFile == 6))) {
-    strcpy(mStr, "O-O");
-    goto check;
-  }
-  if ((piece == KING) && ((mt->fromFile == 4) && (mt->toFile == 2))) {
-    strcpy(mStr, "O-O-O");
-    goto check;
-  }
+  if ((mt->fromFile == ALG_CASTLE) && (mt->toFile > mt->toRank)) { // [HGM] castle: K ends right of R\r
+    strcpy(mStr, "O-O");\r
+    goto check;\r
+  }\r
+  if ((mt->fromFile == ALG_CASTLE) && (mt->toFile < mt->toRank)) { // [HGM] castle: K ends left of R\r
+    strcpy(mStr, "O-O-O");\r
+    goto check;\r
+  }\r
   strcpy(mStr, "");
   switch (piece) {
   case PAWN:
     if (mt->fromFile == ALG_DROP) {
       strcpy(mStr,"P");
-    } else if (mt->fromFile != mt->toFile) {
+    } else if (mt->fromFile != mt->toFile 
+           || gs->board[mt->toFile][mt->toRank] != NOPIECE) { // [HGM] XQ: forward captures as "axa6"
       sprintf(tmp, "%c", mt->fromFile + 'a');
       strcpy(mStr, tmp);
     }
@@ -408,9 +523,68 @@ char *alg_unparse(struct game_state_t * gs, struct move_t * mt)
   case ROOK:
     strcpy(mStr, "R");
     break;
+  case ALFIL2:
+  case AMAZON:
+  case CARDINAL:\r
+    strcpy(mStr, "A");\r
+    break;\r
+  case CANNON:
+  case MARSHALL:\r
+    strcpy(mStr, "C");\r
+    break;\r
+  case MAN:\r
+    strcpy(mStr, "M");\r
+    break;\r
+  case FERZ:
   case QUEEN:
     strcpy(mStr, "Q");
     break;
+  case EMPRESS:
+  case ELEPHANT:
+    strcpy(mStr, "E");
+    break;
+  case ALFIL:
+    strcpy(mStr, "B");
+    break;
+  case FERZ2:
+    strcpy(mStr, "F");
+    break;
+  case WOODY:
+  case WAZIR:
+    strcpy(mStr, "W");
+    break;
+  case SQUIRREL:
+    strcpy(mStr, "O");
+    break;
+  case CENTAUR:
+    strcpy(mStr, "V");
+    break;
+  case HORSE:
+    strcpy(mStr, "H");
+    break;
+  case HONORABLEHORSE:
+    strcpy(mStr, "N");
+    break;
+  case DRAGONKING:
+    strcpy(mStr, "J");
+    break;
+  case DRAGONHORSE:
+    strcpy(mStr, "I");
+    break;
+  case LANCE:
+    strcpy(mStr, "L");
+    break;
+  case PRINCESS:
+  case SILVER:
+    strcpy(mStr, "S");
+    break;
+  case MASTODON:
+  case GOLD:
+    strcpy(mStr, "G");
+    break;
+  case MANDARIN:
+    strcpy(mStr, "A");
+    break;
   case KING:
     strcpy(mStr, "K");
     break;
@@ -425,8 +599,8 @@ char *alg_unparse(struct game_state_t * gs, struct move_t * mt)
   /* Checks for ambiguity in short notation ( Ncb3, R8e8 or so) */
   if (piece != PAWN) {
     ambig = r_ambig = f_ambig = 0;
-    for (r = 0; r < 8; r++)
-      for (f = 0; f < 8; f++) {
+    for (r = 0; r < gs->ranks; r++)\r
+      for (f = 0; f < gs->files; f++) {\r
        if ((gs->board[f][r] != NOPIECE) && iscolor(gs->board[f][r], gs->onMove)
            && (piecetype(gs->board[f][r]) == piece) &&
            ((f != mt->fromFile) || (r != mt->fromRank))) {
@@ -460,48 +634,78 @@ char *alg_unparse(struct game_state_t * gs, struct move_t * mt)
          }
        }
       }
-    if (ambig > 0) {
-      /* Ambiguity in short notation, need to add file,rank or _both_ in
-         notation */
-      if (f_ambig == 0) {
-       sprintf(tmp, "%c", mt->fromFile + 'a');
-       strcat(mStr, tmp);
-      } else if (r_ambig == 0) {
-       sprintf(tmp, "%d", mt->fromRank + 1);
-       strcat(mStr, tmp);
-      } else {
-       sprintf(tmp, "%c%d", mt->fromFile + 'a', mt->fromRank + 1);
-       strcat(mStr, tmp);
-      }
-    }
-  }
-  if ((gs->board[mt->toFile][mt->toRank] != NOPIECE) ||
-      ((piece == PAWN) && (mt->fromFile != mt->toFile))) {
-    strcat(mStr, "x");
-  }
-  }
-  sprintf(tmp, "%c%d", mt->toFile + 'a', mt->toRank + 1);
-  strcat(mStr, tmp);
-
-  if ((piece == PAWN) && (mt->piecePromotionTo != NOPIECE)) {
-    strcat(mStr, "=");         /* = before promoting piece */
-    switch (piecetype(mt->piecePromotionTo)) {
-    case KNIGHT:
-      strcat(mStr, "N");
-      break;
-    case BISHOP:
-      strcat(mStr, "B");
-      break;
-    case ROOK:
-      strcat(mStr, "R");
-      break;
-    case QUEEN:
-      strcat(mStr, "Q");
-      break;
-    default:
-      break;
-    }
-  }
+    if (ambig > 0) {\r
+      /* Ambiguity in short notation, need to add file,rank or _both_ in\r
+         notation */\r
+      if (f_ambig == 0) {\r
+       sprintf(tmp, "%c", mt->fromFile + 'a');\r
+       strcat(mStr, tmp);\r
+      } else if (r_ambig == 0) {\r
+       sprintf(tmp, "%d", mt->fromRank + 1 - (gs->ranks > 9));\r
+       strcat(mStr, tmp);\r
+      } else {\r
+       sprintf(tmp, "%c%d", mt->fromFile + 'a', mt->fromRank + 1 - (gs->ranks > 9));\r
+       strcat(mStr, tmp);\r
+      }\r
+    }\r
+  }\r
+  if ((gs->board[mt->toFile][mt->toRank] != NOPIECE) ||\r
+      ((piece == PAWN) && (mt->fromFile != mt->toFile))) {\r
+    strcat(mStr, "x");\r
+  }\r
+  }\r
+  sprintf(tmp, "%c%d", mt->toFile + 'a', mt->toRank + 1 - (gs->ranks > 9));\r
+  strcat(mStr, tmp);\r
+\r
+  if ((piece == PAWN) && (mt->piecePromotionTo != NOPIECE)) {\r
+    strcat(mStr, "=");         /* = before promoting piece */\r
+    switch (piecetype(mt->piecePromotionTo)) {\r
+    case KNIGHT:\r
+      strcat(mStr, "N");\r
+      break;\r
+    case BISHOP:\r
+      strcat(mStr, "B");\r
+      break;\r
+    case ROOK:\r
+      strcat(mStr, "R");\r
+      break;\r
+    case CARDINAL:\r
+      strcat(mStr, "A");\r
+      break;\r
+    case MARSHALL:\r
+      strcat(mStr, "C");\r
+      break;\r
+    case MAN:\r
+      strcat(mStr, "M");\r
+      break;\r
+    case QUEEN:\r
+      strcat(mStr, "Q");\r
+      break;\r
+    case FERZ2:\r
+      strcat(mStr, "F");\r
+      break;\r
+    case WOODY:\r
+      strcat(mStr, "W");\r
+      break;\r
+    case EMPRESS:\r
+      strcat(mStr, "E");\r
+      break;\r
+    case CENTAUR:\r
+      strcat(mStr, "V");\r
+      break;\r
+    case PRINCESS:\r
+      strcat(mStr, "S");\r
+      break;\r
+    case SQUIRREL:\r
+      strcat(mStr, "O");\r
+      break;\r
+    case MASTODON:\r
+      strcat(mStr, "G");\r
+      break;\r
+    default:\r
+      break;\r
+    }\r
+  }\r
 check:;
   fakeMove = *gs;
   execute_move(&fakeMove, mt, 0);
index 8fdbb0e..5c974f1 100644 (file)
 #include "includes.h"
 
 
-const char *wpstring[] = {" ", "P", "N", "B", "R", "Q", "K"};
-static const char *bpstring[] = {" ", "p", "n", "b", "r", "q", "k"};
+const char *wpstring[] = {" ", "P", "N", "B", "R", "A", "C", "M", "Q", "E", "B", "Q", "W", "H", "N", "J", "I", "L", 
+                         "C", "S", "G", "H", "A", "F", "E", "H", "M", "S", "E", "W", "O", "G", "V", "S", "E", "A", "K"};
+const char *bpstring[] = {" ", "p", "n", "b", "r", "a", "c", "m", "q", "e", "b", "q", "w", "h", "n", "j", "i", "l", 
+                         "c", "s", "g", "h", "a", "f", "e", "h", "m", "s", "e", "w", "o", "g", "v", "s", "e", "a", "k"};
 
-static int pieceValues[7] = {0, 1, 3, 3, 5, 9, 0};
+int pieceValues[KING+1] = {0, 1, 3, 3, 5, 8, 9, 3, 9, 1, 1, 2, 2, 2, 1, 6, 5, 2, 3, 3, 3, 1, 5, 2, 1, 7, 7, 3, 3, 3, 7, 7, 7, 8, 9, 12, 0};
 
 static const int mach_type = (1<<7) | (1<<8) | (1<<9) | (1<<10) | (1<<11);
 #define IsMachineStyle(n) (((1<<(n)) & mach_type) != 0)
 
-static char bstring[MAX_BOARD_STRING_LEGTH];
+static char bstring[MAX_BOARD_STRING_LENGTH];
 
 static int board_read_file(char *category, char *gname, struct game_state_t *gs);
-static void wild_update(int style);
+static void wild_update(board_t b, int style);
 
 static int style1(struct game_state_t *b, struct move_t *ml);
 static int style2(struct game_state_t *b, struct move_t *ml);
@@ -71,14 +73,16 @@ static void reset_board_vars(struct game_state_t *gs)
 {
  int f,r;
 
+  if(gs->files <= 0) gs->files = 8; // [HGM] for pristine board, set default size
+  if(gs->ranks <= 0) gs->ranks = 8;
   for (f = 0; f < 2; f++) {
-    for (r = 0; r < 8; r++)
+    for (r = 0; r < BW; r++)
       gs->ep_possible[f][r] = 0;
-    for (r = PAWN; r <= QUEEN; r++)
+    for (r = PAWN; r <= KING-1; r++)
       gs->holding[f][r-PAWN] = 0;
   }
-  gs->wkmoved = gs->wqrmoved = gs->wkrmoved = 0;
-  gs->bkmoved = gs->bqrmoved = gs->bkrmoved = 0;
+  gs->wkmoved = gs->wqrmoved = gs->wkrmoved = -1; // [HGM] castle: no rights
+  gs->bkmoved = gs->bqrmoved = gs->bkrmoved = -1;
   gs->onMove = WHITE;
   gs->moveNum = 1;
   gs->lastIrreversable = -1;
@@ -89,8 +93,8 @@ void board_clear(struct game_state_t *gs)
 {
  int f,r;
 
- for (f = 0; f < 8; f++)
-    for (r = 0; r < 8; r++)
+ for (f = 0; f < BW; f++)
+    for (r = 0; r < BH; r++)
       gs->board[f][r] = NOPIECE;
  reset_board_vars(gs);
 }
@@ -99,48 +103,141 @@ void board_standard(struct game_state_t *gs)
 {
  int f,r;
 
- for (f = 0; f < 8; f++)
-    for (r = 2; r < 6; r++)
-      gs->board[f][r] = NOPIECE;
- for (f = 0; f < 8; f++)
-   gs->board[f][1] = W_PAWN;
- for (f = 0; f < 8; f++)
-   gs->board[f][6] = B_PAWN;
- gs->board[0][0] = W_ROOK;
- gs->board[1][0] = W_KNIGHT;
- gs->board[2][0] = W_BISHOP; 
- gs->board[3][0] = W_QUEEN;
- gs->board[4][0] = W_KING;
- gs->board[5][0] = W_BISHOP;
- gs->board[6][0] = W_KNIGHT;
- gs->board[7][0] = W_ROOK;
- gs->board[0][7] = B_ROOK;
- gs->board[1][7] = B_KNIGHT;
- gs->board[2][7] = B_BISHOP;
- gs->board[3][7] = B_QUEEN;
- gs->board[4][7] = B_KING;
- gs->board[5][7] = B_BISHOP;
- gs->board[6][7] = B_KNIGHT;
- gs->board[7][7] = B_ROOK;
+ for (f = 0; f < BW; f++)\r
+    for (r = 0; r < BH; r++)\r
+      gs->board[f][r] = NOPIECE;\r
+ for (f = 0; f < gs->files; f++)\r
+   gs->board[f][gs->ranks-7] = W_PAWN;\r
+ for (f = 0; f < gs->files; f++)\r
+   gs->board[f][6] = B_PAWN;\r
+ gs->board[0][0] = W_ROOK;\r
+ gs->board[1][0] = W_KNIGHT;\r
+ gs->board[2][0] = W_BISHOP; \r
+ gs->board[3][0] = W_QUEEN;\r
+ gs->board[gs->files/2][0] = W_KING;\r
+ gs->board[gs->files-3][0] = W_BISHOP;\r
+ gs->board[gs->files-2][0] = W_KNIGHT;\r
+ gs->board[gs->files-1][0] = W_ROOK;\r
+ gs->board[0][gs->ranks-1] = B_ROOK;\r
+ gs->board[1][gs->ranks-1] = B_KNIGHT;\r
+ gs->board[2][gs->ranks-1] = B_BISHOP;\r
+ gs->board[3][gs->ranks-1] = B_QUEEN;\r
+ gs->board[gs->files/2][gs->ranks-1] = B_KING;\r
+ gs->board[gs->files-3][gs->ranks-1] = B_BISHOP;\r
+ gs->board[gs->files-2][gs->ranks-1] = B_KNIGHT;\r
+ gs->board[gs->files-1][gs->ranks-1] = B_ROOK;\r
+#if 1
+ if(gs->files == 10) {\r
+  gs->board[6][0] = W_CARDINAL;\r
+  gs->board[4][0] = W_MARSHALL;\r
+  gs->board[6][gs->ranks-1] = B_CARDINAL;\r
+  gs->board[4][gs->ranks-1] = B_MARSHALL;\r
+ }\r
+ if(gs->royalKnight) {\r
+   gs->board[1][0] = W_MAN;\r
+   gs->board[gs->files-2][0] = W_MAN;\r
+   gs->board[1][gs->ranks-1] = B_MAN;\r
+   gs->board[gs->files-2][gs->ranks-1] = B_MAN;\r
+ }\r
+#endif
+
  reset_board_vars(gs);
+ // [HGM] castle: standard setup has rights for corner Rooks and central King
+ gs->wkmoved = gs->files/2;
+ gs->bkmoved = gs->files/2;
+ gs->wkrmoved = gs->files-1;
+ gs->bkrmoved = gs->files-1;
+ gs->wqrmoved = 0;
+ gs->bqrmoved = 0;
 }
 
 int board_init(int g,struct game_state_t *b, char *category, char *board)
 {
   int retval = 0;
-  int wval;
-
-  if (!category || !board || !category[0] || !board[0]) 
-                               /* accounts for bughouse too */
-    board_standard(b);
+  int wval, i, j;
+
+  b->files = b->ranks = 8;\r
+  b->pawnDblStep = (!category || strcmp(category, "shatranj")); \r
+  b->royalKnight = (category && !strcmp(category, "knightmate"));\r
+  b->capablancaPieces = 0;
+  b->holdings = 0;
+  b->drops = 0;
+  b->castlingStyle = 1;
+  b->palace = 0;
+  b->setup = 0;
+  b->bareKingLoses = 0;
+  b->stalemate = 1;
+  b->promoType = 1;
+  b->variant[0] = 0; // [HGM] variant: default is normal, if variant name is missing\r
+  if (!category || !board || !category[0] || !board[0]) \r
+                               /* accounts for bughouse too */\r
+    board_standard(b);\r
   else {
-    if (!strcmp(category, "wild")) {
-      if (sscanf(board, "%d", &wval) == 1 && wval >= 1 && wval <= 4)
-        wild_update(wval);
+    if(category && category[0]) strcpy(b->variant, category); // [HGM] variant: remember category name\r
+    if (!strcmp(category, "wild") && sscanf(board, "%d", &wval) == 1) {
+       if(wval >= 1 && wval <= 4)\r
+            wild_update(b->board, wval);
+       sprintf(b->variant, "wild/%d", wval);\r
+    }
+
+    if (board && !strcmp(board, "0"))
+       b->setup = 0; // [HGM] variant: any board in the default file "0" is supposed to be implied by the variant\r
+
+    if (!strcmp(category, "knightmate")) {\r
+      board_standard(b);\r
+    } else if (!strcmp(category, "super")) {\r
+      board_standard(b);
+      b->holdings = 1;
+      b->promoType = 2;
+      for(i=CENTAUR; i<=AMAZON; i++) {
+       int placed = 0;
+       do { int p, newp;
+         j = random() % 8;
+         if((p = piecetype(b->board[j][0])) >= CENTAUR) continue; // includes King
+         b->holding[1][p-PAWN] = ++b->holding[0][p-PAWN]; // piece to holding
+         if(board && !strcmp(board, "1")) newp = i - CENTAUR + WOODY; else newp = i;
+         if(board && !strcmp(board, "2")) newp = WOODY + random()%7;
+         b->board[j][0] = newp | WHITE; // place replacements
+         b->board[j][7] = newp | BLACK;
+         placed = 1;
+       } while(!placed);
       }
-    retval = board_read_file(category, board, b); 
+      b->setup = 1;\r
+    } else if (!strcmp(category, "fischerandom")) {\r
+      wild_update(b->board, 22);
+      b->castlingStyle = 2;
+      b->setup = 1; // [HGM] FRC: even the default is a setup position, for which an initial board has to be printed\r
+    } else if (!strcmp(category, "caparandom")) {
+      b->files = 10;\r
+      wild_update(b->board, 46);
+      b->castlingStyle = 2;
+      b->setup = 1; \r
+    } else retval = board_read_file(category, board, b); \r
+  }
+  if(b->setup && game_globals.garray[g].FENstartPos[0])  // [HGM] use pre-existing start position, if one available
+    FEN_to_board(game_globals.garray[g].FENstartPos, b); //       (could be wild board, or shuffle variant)
+  if(b->castlingStyle == 1) {
+    b->wkmoved = b->files/2;
+    b->bkmoved = b->files/2;
+    b->wkrmoved = b->files-1;
+    b->bkrmoved = b->files-1;
+    b->wqrmoved = 0;
+    b->bqrmoved = 0;
+  } else if(b->castlingStyle == 2) {
+    for(i=j=0; i < b->files; i++) {
+      int p = b->board[i][0];
+      if(p == W_ROOK || p == W_KING) {
+       switch(j++) {
+         case 0: b->wqrmoved = b->bqrmoved = i; break;
+         case 1: b->wkmoved  = b->bkmoved  = i; break;
+         case 2: b->wkrmoved = b->bkrmoved = i; break;
+       }
+      }
+    }
   }
+\r
   MakeFENpos(g, game_globals.garray[g].FENstartPos);
+
   return retval;
 }
 
@@ -150,8 +247,8 @@ void board_calc_strength(struct game_state_t *b, int *ws, int *bs)
   int *p;
 
   *ws = *bs = 0;
-  for (f = 0; f < 8; f++) {
-    for (r = 0; r < 8; r++) {
+  for (f = 0; f < b->ranks; f++) {
+    for (r = 0; r < b->files; r++) {
       if (colorval(b->board[r][f]) == WHITE)
        p = ws;
       else
@@ -159,7 +256,7 @@ void board_calc_strength(struct game_state_t *b, int *ws, int *bs)
       *p += pieceValues[piecetype(b->board[r][f])];
     }
   }
-  for (r = PAWN; r <= QUEEN; r++) {
+  for (r = PAWN; r < KING; r++) {
     *ws += b->holding[0][r-1] * pieceValues[r];
     *bs += b->holding[1][r-1] * pieceValues[r];
   }
@@ -167,11 +264,11 @@ void board_calc_strength(struct game_state_t *b, int *ws, int *bs)
 
 static char *holding_str(int *holding)
 {
-       static char tmp[30];
+       static char tmp[80];
        int p,i,j;
 
        i = 0;
-       for (p = PAWN; p <= QUEEN; p++) {
+       for (p = PAWN; p < KING; p++) {
                for (j = 0; j < holding[p-1]; j++) {
                        tmp[i++] = wpstring[p][0];
                }
@@ -183,7 +280,7 @@ static char *holding_str(int *holding)
 static char *append_holding_machine(char *buf, int g, int c, int p)
 {
   struct game_state_t *gs = &game_globals.garray[g].game_state;
-  char tmp[50];
+  char tmp[160];
 
   sprintf(tmp, "<b1> game %d white [%s] black [", g+1, holding_str(gs->holding[0]));
   strcat(tmp, holding_str(gs->holding[1]));
@@ -213,7 +310,7 @@ void update_holding(int g, int pieceCaptured)
   int c = colorval(pieceCaptured);
   struct game_state_t *gs = &game_globals.garray[g].game_state;
   int pp, pl;
-  char tmp1[80], tmp2[80];
+  char tmp1[160], tmp2[160];
 
   if (c == WHITE) {
     c = 0;
@@ -251,7 +348,8 @@ char *board_to_string(char *wn, char *bn,
                      int orientation, int relation,
                      int p)
 {
-  int bh = (b->gameNum >= 0 && game_globals.garray[b->gameNum].link >= 0);
+  int bh = (b->gameNum >= 0 && game_globals.garray[b->gameNum].link >= 0
+             || b->holdings ); // [HGM] zh: make sure holdings are printed
   orient = orientation;
   myTurn = relation;
 
@@ -262,6 +360,7 @@ char *board_to_string(char *wn, char *bn,
      move happened, not current time */
   if (game_globals.garray[b->gameNum].status == GAME_EXAMINE) {
          unsigned nhm = game_globals.garray[b->gameNum].numHalfMoves;
+
          if (nhm > 0) {
                  wTime = ml[nhm - 1].wTime;
                  bTime = ml[nhm - 1].bTime;
@@ -288,8 +387,10 @@ char *board_to_string(char *wn, char *bn,
     bstring[0] = '\0';
   if (bh && !IsMachineStyle(style))
     append_holding_display(bstring, b, orientation==BLACK);
+
   if (styleFuncs[style] (b, ml))
     return NULL;
+
   if (bh) {
     if (IsMachineStyle(style))
       append_holding_machine(bstring, b->gameNum, 0, 0);
@@ -302,490 +403,582 @@ char *board_to_string(char *wn, char *bn,
 char *move_and_time(struct move_t *m)
 {
        static char tmp[20];
+#if 0
+       if(m->depth>0)
+            sprintf(tmp, "%-7s (%s%.2f/%d)", m->algString, /* tenth_str(m->tookTime, 0), */
+                                       m->score>0 ? "+" : "", m->score, m->depth);
+       else 
+#endif
        sprintf(tmp, "%-7s (%s)", m->algString, tenth_str(m->tookTime, 0));
        return tmp;
 }
 
 /* The following take the game state and whole move list */
 
+void Enlarge(char *a, int ss, int w)
+{
+  int l, i;
+  char *p, *q;
+  if(strlen(a) < ss) return;
+  for(i=8; i<w; i++) {
+    l = strlen(a);
+    p = a + l; q = p + ss;
+    while(q != a+l-ss) *q-- = *p--;
+  }
+}
+
 static int genstyle(struct game_state_t *b, struct move_t *ml, const char *wp[], const char *bp[],
                    const char *wsqr, const char *bsqr,
                    const char *top, const char *mid, const char *start, const char *end, 
                    const char *label,const char *blabel)
 {
-  int f, r, count;
-  char tmp[80];
-  int first, last, inc;
-  int ws, bs;
-
-  board_calc_strength(b, &ws, &bs);
-  if (orient == WHITE) {
-    first = 7;
-    last = 0;
-    inc = -1;
-  } else {
-    first = 0;
-    last = 7;
-    inc = 1;
+  int f, r, count, i;\r
+  char tmp[80], mylabel[80], *p, *q, myTop[80], myMid[80];\r
+  int firstR, lastR, firstF, lastF, inc;\r
+  int ws, bs, sqrSize = strlen(wp[0]);\r
+\r
+  board_calc_strength(b, &ws, &bs);\r
+  if (orient == WHITE) {\r
+    firstR = b->ranks-1;\r
+    firstF = b->files-1;\r
+    lastR = lastF = 0;\r
+    inc = -1;\r
+  } else {\r
+    firstR = firstF = 0;\r
+    lastR = b->ranks-1;\r
+    lastF = b->files-1;\r
+    inc = 1;\r
   }
-  strcat(bstring, top);
-  for (f = first, count = 7; f != last + inc; f += inc, count--) {
-    sprintf(tmp, "     %d  %s", f + 1, start);
-    strcat(bstring, tmp);
-    for (r = last; r != first - inc; r = r - inc) {
-      if (square_color(r, f) == WHITE)
-       strcat(bstring, wsqr);
-      else
-       strcat(bstring, bsqr);
-      if (piecetype(b->board[r][f]) == NOPIECE) {
-       if (square_color(r, f) == WHITE)
-         strcat(bstring, bp[0]);
-       else
-         strcat(bstring, wp[0]);
+  strcpy(myTop, top);
+  strcpy(myMid, mid);
+  Enlarge(myTop, sqrSize, b->files);\r
+  Enlarge(myMid, sqrSize, b->files);\r
+  strcat(bstring, myTop);\r
+  for (f = firstR, count = b->ranks-1; f != lastR + inc; f += inc, count--) {\r
+    sprintf(tmp, "     %d  %s", f + (b->ranks < 10), start);\r
+    strcat(bstring, tmp);\r
+    for (r = lastF; r != firstF - inc; r = r - inc) {\r
+      if (square_color(r, f) == WHITE)\r
+       strcat(bstring, wsqr);\r
+      else\r
+       strcat(bstring, bsqr);\r
+      if (piecetype(b->board[r][f]) == NOPIECE) {\r
+       if (square_color(r, f) == WHITE)\r
+         strcat(bstring, bp[0]);\r
+       else\r
+         strcat(bstring, wp[0]);\r
       } else {
-       if (colorval(b->board[r][f]) == WHITE)
-         strcat(bstring, wp[piecetype(b->board[r][f])]);
-       else
-         strcat(bstring, bp[piecetype(b->board[r][f])]);
-      }
-    }
-    sprintf(tmp, "%s", end);
-    strcat(bstring, tmp);
-    switch (count) {
-    case 7:
-      sprintf(tmp, "     Move # : %d (%s)", b->moveNum, CString(b->onMove));
-      strcat(bstring, tmp);
-      break;
-    case 6:
-/*    if ((b->moveNum > 1) || (b->onMove == BLACK)) {  */
-/* The change from the above line to the one below is a kludge by hersco. */
-      if (game_globals.garray[b->gameNum].numHalfMoves > 0) {
-/* loon: think this fixes the crashing ascii board on takeback bug */
-       sprintf(tmp, "     %s Moves : '%s'", CString(CToggle(b->onMove)),
-               move_and_time(&ml[game_globals.garray[b->gameNum].numHalfMoves - 1]));
-       strcat(bstring, tmp);
-      }
-      break;
-    case 5:
-      break;
-    case 4:
-      sprintf(tmp, "     Black Clock : %s", tenth_str(((bTime > 0) ? bTime : 0), 1));
-      strcat(bstring, tmp);
-      break;
-    case 3:
-      sprintf(tmp, "     White Clock : %s", tenth_str(((wTime > 0) ? wTime : 0), 1));
-      strcat(bstring, tmp);
-      break;
-    case 2:
-      sprintf(tmp, "     Black Strength : %d", bs);
-      strcat(bstring, tmp);
-      break;
-    case 1:
-      sprintf(tmp, "     White Strength : %d", ws);
-      strcat(bstring, tmp);
-      break;
-    case 0:
-      break;
-    }
-    strcat(bstring, "\n");
-    if (count != 0)
-      strcat(bstring, mid);
-    else
-      strcat(bstring, top);
-  }
-  if (orient == WHITE)
-    strcat(bstring, label);
-  else
-    strcat(bstring, blabel);
-  return 0;
-}
-
-/* Experimental ANSI board for colour representation */
-static int style13(struct game_state_t *b, struct move_t *ml)
-{
-  static const char *wp[] = {"   ", "\033[37m\033[1m P ", "\033[37m\033[1m N ", "\033[37m\033[1m B ", "\033[37m\033[1m R ", "\033[37m\033[1m Q ", "\033[37m\033[1m K "};
-  static const char *bp[] = {"   ", "\033[21m\033[37m P ", "\033[21m\033[37m N ", "\033[21m\033[37m B ", "\033[21m\033[37m R ", "\033[21m\033[37m Q ", "\033[21m\033[37m K "};
-  static const char *wsqr = "\033[40m";
-  static const char *bsqr = "\033[45m";
-  static const char *top = "\t+------------------------+\n";
-  static const char *mid = "";
-  static const char *start = "|";
-  static const char *end = "\033[0m|";
-  static const char *label = "\t  a  b  c  d  e  f  g  h\n";
-  static const char *blabel = "\t  h  g  f  e  d  c  b  a\n";
-
-  return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel);
-}
-
-/* Standard ICS */
-static int style1(struct game_state_t *b, struct move_t *ml)
-{
-  static const char *wp[] = {"   |", " P |", " N |", " B |", " R |", " Q |", " K |"};
-  static const char *bp[] = {"   |", " *P|", " *N|", " *B|", " *R|", " *Q|", " *K|"};
-  static char *wsqr = "";
-  static char *bsqr = "";
-  static char *top = "\t---------------------------------\n";
-  static char *mid = "\t|---+---+---+---+---+---+---+---|\n";
-  static char *start = "|";
-  static char *end = "";
-  static char *label = "\t  a   b   c   d   e   f   g   h\n";
-  static char *blabel = "\t  h   g   f   e   d   c   b   a\n";
-
-  return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel);
-}
-
-/* USA-Today Sports Center-style board */
-static int style2(struct game_state_t *b, struct move_t *ml)
-{
-  static const char *wp[] = {"+  ", "P  ", "N  ", "B  ", "R  ", "Q  ", "K  "};
-  static const char *bp[] = {"-  ", "p' ", "n' ", "b' ", "r' ", "q' ", "k' "};
-  static char *wsqr = "";
-  static char *bsqr = "";
-  static char *top = "";
-  static char *mid = "";
-  static char *start = "";
-  static char *end = "";
-  static char *label = "\ta  b  c  d  e  f  g  h\n";
-  static char *blabel = "\th  g  f  e  d  c  b  a\n";
-
-  return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel);
-}
-
-/* Experimental vt-100 ANSI board for dark backgrounds */
-static int style3(struct game_state_t *b, struct move_t *ml)
-{
-  static const char *wp[] = {"   ", " P ", " N ", " B ", " R ", " Q ", " K "};
-  static const char *bp[] = {"   ", " *P", " *N", " *B", " *R", " *Q", " *K"};
-  static char *wsqr = "\033[0m";
-  static char *bsqr = "\033[7m";
-  static char *top = "\t+------------------------+\n";
-  static char *mid = "";
-  static char *start = "|";
-  static char *end = "\033[0m|";
-  static char *label = "\t  a  b  c  d  e  f  g  h\n";
-  static char *blabel = "\t  h  g  f  e  d  c  b  a\n";
-
-  return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel);
-}
-
-/* Experimental vt-100 ANSI board for light backgrounds */
-static int style4(struct game_state_t *b, struct move_t *ml)
-{
-  static const char *wp[] = {"   ", " P ", " N ", " B ", " R ", " Q ", " K "};
-  static const char *bp[] = {"   ", " *P", " *N", " *B", " *R", " *Q", " *K"};
-  static char *wsqr = "\033[7m";
-  static char *bsqr = "\033[0m";
-  static char *top = "\t+------------------------+\n";
-  static char *mid = "";
-  static char *start = "|";
-  static char *end = "\033[0m|";
-  static char *label = "\t  a  b  c  d  e  f  g  h\n";
-  static char *blabel = "\t  h  g  f  e  d  c  b  a\n";
-
-  return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel);
-}
-
-/* Style suggested by ajpierce@med.unc.edu */
-static int style5(struct game_state_t *b, struct move_t *ml)
-{
-  static const char *wp[] = {"    ", "  o ", " :N:", " <B>", " |R|", " {Q}", " =K="};
-  static const char *bp[] = {"    ", "  p ", " :n:", " <b>", " |r|", " {q}", " =k="};
-  static char *wsqr = "";
-  static char *bsqr = "";
-  static char *top = "        .   .   .   .   .   .   .   .   .\n";
-  static char *mid = "        .   .   .   .   .   .   .   .   .\n";
-  static char *start = "";
-  static char *end = "";
-  static char *label = "\t  a   b   c   d   e   f   g   h\n";
-  static char *blabel = "\t  h   g   f   e   d   c   b   a\n";
-
-  return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel);
-}
-
-/* Email Board suggested by Thomas Fought (tlf@rsch.oclc.org) */
-static int style6(struct game_state_t *b, struct move_t *ml)
-{
-  static const char *wp[] = {"    |", " wp |", " WN |", " WB |", " WR |", " WQ |", " WK |"};
-  static const char *bp[] = {"    |", " bp |", " BN |", " BB |", " BR |", " BQ |", " BK |"};
-  static char *wsqr = "";
-  static char *bsqr = "";
-  static char *top = "\t-----------------------------------------\n";
-  static char *mid = "\t-----------------------------------------\n";
-  static char *start = "|";
-  static char *end = "";
-  static char *label = "\t  A    B    C    D    E    F    G    H\n";
-  static char *blabel = "\t  H    G    F    E    D    C    B    A\n";
-
-  return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel);
-}
-
-/* Miniature board */
-static int style7(struct game_state_t *b, struct move_t *ml)
-{
-  static const char *wp[] = {"  ", " P", " N", " B", " R", " Q", " K"};
-  static const char *bp[] = {" -", " p", " n", " b", " r", " q", " k"};
-  static char *wsqr = "";
-  static char *bsqr = "";
-  static char *top = "\t:::::::::::::::::::::\n";
-  static char *mid = "";
-  static char *start = "..";
-  static char *end = " ..";
-  static char *label = "\t   a b c d e f g h\n";
-  static char *blabel = "\t   h g f e d c b a\n";
-
-  return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel);
-}
-
-/* ICS interface maker board-- raw data dump */
-static int style8(struct game_state_t *b, struct move_t *ml)
-{
-  char tmp[80];
-  int f, r;
-  int ws, bs;
-
-  board_calc_strength(b, &ws, &bs);
-  sprintf(tmp, "#@#%03d%-16s%s%-16s%s", b->gameNum + 1,
-         game_globals.garray[b->gameNum].white_name,
-         (orient == WHITE) ? "*" : ":",
-         game_globals.garray[b->gameNum].black_name,
-         (orient == WHITE) ? ":" : "*");
-  strcat(bstring, tmp);
-  for (r = 0; r < 8; r++) {
-    for (f = 0; f < 8; f++) {
-      if (b->board[f][r] == NOPIECE) {
-       strcat(bstring, " ");
-      } else {
-       if (colorval(b->board[f][r]) == WHITE)
-         strcat(bstring, wpstring[piecetype(b->board[f][r])]);
-       else
-         strcat(bstring, bpstring[piecetype(b->board[f][r])]);
-      }
-    }
-  }
-  sprintf(tmp, "%03d%s%02d%02d%05d%05d%-7s(%s)@#@\n",
-         game_globals.garray[b->gameNum].numHalfMoves / 2 + 1,
-         (b->onMove == WHITE) ? "W" : "B",
-         ws,
-         bs,
-         (wTime + 5) / 10,
-         (bTime + 5) / 10,
-         game_globals.garray[b->gameNum].numHalfMoves ?
-         ml[game_globals.garray[b->gameNum].numHalfMoves - 1].algString :
-         "none",
-         game_globals.garray[b->gameNum].numHalfMoves ?
-         tenth_str(ml[game_globals.garray[b->gameNum].numHalfMoves - 1].tookTime, 0) :
-         "0:00");
-  strcat(bstring, tmp);
-  return 0;
-}
-
-/* last 2 moves only (previous non-verbose mode) */
-static int style9(struct game_state_t *b, struct move_t *ml)
-{
-  int i, count;
-  char tmp[80];
-  int startmove;
-
-  sprintf(tmp, "\nMove     %-23s%s\n",
-         game_globals.garray[b->gameNum].white_name,
-         game_globals.garray[b->gameNum].black_name);
-  strcat(bstring, tmp);
-  sprintf(tmp, "----     --------------         --------------\n");
-  strcat(bstring, tmp);
-  startmove = ((game_globals.garray[b->gameNum].numHalfMoves - 3) / 2) * 2;
-  if (startmove < 0)
-    startmove = 0;
-  for (i = startmove, count = 0;
-       i < game_globals.garray[b->gameNum].numHalfMoves && count < 4;
-       i++, count++) {
-    if (!(i & 0x01)) {
-      sprintf(tmp, "  %2d     ", i / 2 + 1);
-      strcat(bstring, tmp);
-    }
-    sprintf(tmp, "%-23s", move_and_time(&ml[i]));
-    strcat(bstring, tmp);
-    if (i & 0x01)
-      strcat(bstring, "\n");
-  }
-  if (i & 0x01)
-    strcat(bstring, "\n");
-  return 0;
-}
-
-/* Sleator's 'new and improved' raw dump format... */
-static int style10(struct game_state_t *b, struct move_t *ml)
-{
-  int f, r;
-  char tmp[80];
-  int ws, bs;
-
-  board_calc_strength(b, &ws, &bs);
-  sprintf(tmp, "<10>\n");
-  strcat(bstring, tmp);
-  for (r = 7; r >= 0; r--) {
-    strcat(bstring, "|");
-    for (f = 0; f < 8; f++) {
-      if (b->board[f][r] == NOPIECE) {
-       strcat(bstring, " ");
-      } else {
-       if (colorval(b->board[f][r]) == WHITE)
-         strcat(bstring, wpstring[piecetype(b->board[f][r])]);
-       else
-         strcat(bstring, bpstring[piecetype(b->board[f][r])]);
-      }
+       int piece = piecetype(b->board[r][f]);
+//     if(piece > QUEEN) piece = ELEPHANT + (piece == KING); // All fairies become elephants in ascii styles\r
+       if (colorval(b->board[r][f]) == WHITE)\r
+         strcat(bstring, wp[piece]);\r
+       else\r
+         strcat(bstring, bp[piece]);\r
+      }\r
+    }\r
+    sprintf(tmp, "%s", end);\r
+    strcat(bstring, tmp);\r
+    switch (count) {\r
+    case 7:\r
+      sprintf(tmp, "     Move # : %d (%s)", b->moveNum, CString(b->onMove));\r
+      strcat(bstring, tmp);\r
+      break;\r
+    case 6:\r
+/*    if ((b->moveNum > 1) || (b->onMove == BLACK)) {  */\r
+/* The change from the above line to the one below is a kludge by hersco. */\r
+      if (game_globals.garray[b->gameNum].numHalfMoves > 0) {\r
+/* loon: think this fixes the crashing ascii board on takeback bug */\r
+       sprintf(tmp, "     %s Moves : '%s'", CString(CToggle(b->onMove)),\r
+               move_and_time(&ml[game_globals.garray[b->gameNum].numHalfMoves - 1]));\r
+       strcat(bstring, tmp);\r
+      }\r
+      break;\r
+    case 5:\r
+      break;\r
+    case 4:\r
+      sprintf(tmp, "     Black Clock : %s", tenth_str(((bTime > 0) ? bTime : 0), 1));\r
+      strcat(bstring, tmp);\r
+      break;\r
+    case 3:\r
+      sprintf(tmp, "     White Clock : %s", tenth_str(((wTime > 0) ? wTime : 0), 1));\r
+      strcat(bstring, tmp);\r
+      break;\r
+    case 2:\r
+      sprintf(tmp, "     Black Strength : %d", bs);\r
+      strcat(bstring, tmp);\r
+      break;\r
+    case 1:\r
+      sprintf(tmp, "     White Strength : %d", ws);\r
+      strcat(bstring, tmp);\r
+      break;\r
+    case 0:\r
+      break;\r
+    }\r
+    strcat(bstring, "\n");\r
+    if (count != 0)\r
+      strcat(bstring, myMid);\r
+    else\r
+      strcat(bstring, myTop);\r
+  }\r
+  q = mylabel; i = 0;
+  if (orient == WHITE) {\r
+    p = label;
+    while(*p) {
+       switch(*p) {
+         case ' ':
+         case '\t':
+         case '\n':
+               *q++ = *p++; break;
+         default:
+               if(++i > b->files) { *q++ = '\n'; *q++ = 0; }
+               *q++ = *p++;
+       }
     }
-    strcat(bstring, "|\n");
-  }
-  strcat(bstring, (b->onMove == WHITE) ? "W " : "B ");
-  if (game_globals.garray[b->gameNum].numHalfMoves) {
-    sprintf(tmp, "%d ",
-           ml[game_globals.garray[b->gameNum].numHalfMoves - 1].doublePawn);
   } else {
-    sprintf(tmp, "-1 ");
-  }
-  strcat(bstring, tmp);
-  sprintf(tmp, "%d %d %d %d %d\n",
-         !(b->wkmoved || b->wkrmoved),
-         !(b->wkmoved || b->wqrmoved),
-         !(b->bkmoved || b->bkrmoved),
-         !(b->bkmoved || b->bqrmoved),
-       (game_globals.garray[b->gameNum].numHalfMoves - ((b->lastIrreversable == -1) ? 0 :
-                                          b->lastIrreversable)));
-  strcat(bstring, tmp);
-  sprintf(tmp, "%d %s %s %d %d %d %d %d %d %d %d %s (%s) %s %d\n",
-         b->gameNum,
-         game_globals.garray[b->gameNum].white_name,
-         game_globals.garray[b->gameNum].black_name,
-         myTurn,
-         game_globals.garray[b->gameNum].wInitTime / 600,
-         game_globals.garray[b->gameNum].wIncrement / 10,
-         ws,
-         bs,
-         (wTime + 5) / 10,
-         (bTime + 5) / 10,
-         game_globals.garray[b->gameNum].numHalfMoves / 2 + 1,
-         game_globals.garray[b->gameNum].numHalfMoves ?
-         ml[game_globals.garray[b->gameNum].numHalfMoves - 1].moveString :
-         "none",
-         game_globals.garray[b->gameNum].numHalfMoves ?
-         tenth_str(ml[game_globals.garray[b->gameNum].numHalfMoves - 1].tookTime, 0) :
-         "0:00",
-         game_globals.garray[b->gameNum].numHalfMoves ?
-         ml[game_globals.garray[b->gameNum].numHalfMoves - 1].algString :
-         "none",
-         (orient == WHITE) ? 0 : 1);
-  strcat(bstring, tmp);
-  sprintf(tmp, ">10<\n");
-  strcat(bstring, tmp);
-  return 0;
-}
-
-/* Same as 8, but with verbose moves ("P/e3-e4", instead of "e4") */
-static int style11(struct game_state_t *b, struct move_t *ml)
-{
-  char tmp[80];
-  int f, r;
-  int ws, bs;
-
-  board_calc_strength(b, &ws, &bs);
-  sprintf(tmp, "#@#%03d%-16s%s%-16s%s", b->gameNum,
-         game_globals.garray[b->gameNum].white_name,
-         (orient == WHITE) ? "*" : ":",
-         game_globals.garray[b->gameNum].black_name,
-         (orient == WHITE) ? ":" : "*");
-  strcat(bstring, tmp);
-  for (r = 0; r < 8; r++) {
-    for (f = 0; f < 8; f++) {
-      if (b->board[f][r] == NOPIECE) {
-       strcat(bstring, " ");
-      } else {
-       if (colorval(b->board[f][r]) == WHITE)
-         strcat(bstring, wpstring[piecetype(b->board[f][r])]);
-       else
-         strcat(bstring, bpstring[piecetype(b->board[f][r])]);
-      }
-    }
-  }
-    sprintf(tmp, "%03d%s%02d%02d%05d%05d%-7s(%s)@#@\n",
-           game_globals.garray[b->gameNum].numHalfMoves / 2 + 1,
-           (b->onMove == WHITE) ? "W" : "B",
-           ws,
-           bs,
-           (wTime + 5) / 10,
-           (bTime + 5) / 10,
-           game_globals.garray[b->gameNum].numHalfMoves ?
-           ml[game_globals.garray[b->gameNum].numHalfMoves - 1].moveString :
-           "none",
-           game_globals.garray[b->gameNum].numHalfMoves ?
-           tenth_str(ml[game_globals.garray[b->gameNum].numHalfMoves - 1].tookTime, 0) :
-           "0:00");
-  strcat(bstring, tmp);
-  return 0;
+    p = blabel;
+    while(*p) {
+       switch(*p) {
+         case ' ':
+         case '\t':
+         case '\n':
+               *q++ = *p++; break;
+         default:
+               *q++ = *p++ + b->files - 12;
+               if(++i >= b->files) { *q++ = '\n'; *q++ = 0; }
+       }
+    }\r
+  }\r
+  *q++ = 0;
+  strcat(bstring, mylabel);\r
+  return 0;\r
 }
 
-/* Similar to style 10.  See the "style12" help file for information */
-static int style12(struct game_state_t *b, struct move_t *ml)
-{
-  int f, r;
-  char tmp[80];
-  int ws, bs;
-
-  board_calc_strength(b, &ws, &bs);
-  sprintf(bstring, "<12> ");
-  for (r = 7; r >= 0; r--) {
-    for (f = 0; f < 8; f++) {
-      if (b->board[f][r] == NOPIECE) {
-       strcat(bstring, "-");
-      } else {
-       if (colorval(b->board[f][r]) == WHITE)
-         strcat(bstring, wpstring[piecetype(b->board[f][r])]);
-       else
-         strcat(bstring, bpstring[piecetype(b->board[f][r])]);
-      }
-    }
-    strcat(bstring, " ");
-  }
-  strcat(bstring, (b->onMove == WHITE) ? "W " : "B ");
-  if (game_globals.garray[b->gameNum].numHalfMoves) {
-    sprintf(tmp, "%d ",
-           ml[game_globals.garray[b->gameNum].numHalfMoves - 1].doublePawn);
-  } else {
-    sprintf(tmp, "-1 ");
+/* Experimental ANSI board for colour representation */\r
+static int style13(struct game_state_t *b, struct move_t *ml)\r
+{\r
+  static const char *wp[] = {"   ", "\033[37m\033[1m P ", "\033[37m\033[1m N ", "\033[37m\033[1m B ", "\033[37m\033[1m R ", "\033[37m\033[1m A ", "\033[37m\033[1m C ", "\033[37m\033[1m M ", "\033[37m\033[1m Q ", "\033[37m\033[1m E ", "\033[37m\033[1m K "};\r
+  static const char *bp[] = {"   ", "\033[21m\033[37m P ", "\033[21m\033[37m N ", "\033[21m\033[37m B ", "\033[21m\033[37m R ", "\033[21m\033[37m A ", "\033[21m\033[37m C ", "\033[21m\033[37m M ", "\033[21m\033[37m Q ", "\033[21m\033[37m E ", "\033[21m\033[37m K "};\r
+  static const char *wsqr = "\033[40m";\r
+  static const char *bsqr = "\033[45m";\r
+  static const char *top = "\t+------------------------+\n";\r
+  static const char *mid = "";\r
+  static const char *start = "|";\r
+  static const char *end = "\033[0m|";\r
+  static const char *label = "\t  a  b  c  d  e  f  g  h  i  j  k  l\n";\r
+  static const char *blabel = "\t  l  k  j  i  h  g  f  e  d  c  b  a\n";\r
+return 0;\r
+  return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel);\r
+}\r
+\r
+/* Standard ICS */\r
+static int style1(struct game_state_t *b, struct move_t *ml)\r
+{\r
+  static const char *wp[] = {"   |", " P |", " N |", " B |", " R |", " A |", " C |", " M |", " Q |", " E |", " B |", " Q |", 
+                            " W |", " H |", " N |", " J |", " I |", " L |", " C |", " S |", " G |", " H |", " A |", " F |",
+                            " E |", " H |", " M |", " S |", " E |", " W |", " O |", " G |", " V |", " S |", " E |", " A |", " K |"};
+  static const char *bp[] = {"   |", " *P|", " *N|", " *B|", " *R|", " *A|", " *C|", " *M|", " *Q|", " *E|", " *B|", " *Q|", 
+                            " *W|", " *H|", " *N|", " *J|", " *I|", " *L|", " *C|", " *S|", " *G|", " *H|", " *A|", " *F|",
+                            " *E|", " *H|", " *M|", " *S|", " *E|", " *W|", " *O|", " *G|", " *V|", " *S|", " *E|", " *A|", " *K|"};
+  static char *wsqr = "";\r
+  static char *bsqr = "";\r
+  static char *top = "\t---------------------------------\n";\r
+  static char *mid = "\t|---+---+---+---+---+---+---+---|\n";\r
+  static char *start = "|";\r
+  static char *end = "";\r
+  static char *label = "\t  a   b   c   d   e   f   g   h   i   j   k   l\n";\r
+  static char *blabel = "\t  l   k   j   i   h   g   f   e   d   c   b   a\n";\r
+\r
+  return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel);\r
+}\r
+\r
+/* USA-Today Sports Center-style board */\r
+static int style2(struct game_state_t *b, struct move_t *ml)\r
+{\r
+  static const char *wp[] = {"-  ", "P  ", "N  ", "B  ", "R  ", "A  ", "C  ", "M  ", "Q  ", "E  ", "B  ", "Q  ",
+                            "W  ", "H  ", "N  ", "J  ", "I  ", "L  ", "C  ", "S  ", "G  ", "H  ", "A  ", "F  ",
+                            "E  ", "H  ", "M  ", "S  ", "E  ", "W  ", "O  ", "G  ", "V  ", "S  ", "E  ", "A  ", "K  "};
+  static const char *bp[] = {"+  ", "p' ", "n' ", "b' ", "r' ", "a' ", "c' ", "m' ", "q' ", "e' ", "b' ", "q' ",
+                            "w' ", "h' ", "n' ", "j' ", "i' ", "l' ", "c' ", "s' ", "g' ", "h' ", "a' ", "f' ",
+                            "e' ", "h' ", "m' ", "s' ", "e' ", "w' ", "o' ", "g' ", "v' ", "s' ", "e' ", "a' ", "k' "};
+  static char *wsqr = "";\r
+  static char *bsqr = "";\r
+  static char *top = "";\r
+  static char *mid = "";\r
+  static char *start = "";\r
+  static char *end = "";\r
+  static char *label = "\ta  b  c  d  e  f  g  h  i  j  k  l\n";\r
+  static char *blabel = "\tl  k  j  i  h  g  f  e  d  c  b  a\n";\r
+\r
+  return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel);\r
+}\r
+\r
+/* Experimental vt-100 ANSI board for dark backgrounds */\r
+static int style3(struct game_state_t *b, struct move_t *ml)\r
+{\r
+  static const char *wp[] = {"   ", " P ", " N ", " B ", " R ", " A ", " C ", " M ", " Q ", " E ", " B ", " Q ", 
+                            " W ", " H ", " N ", " J ", " I ", " L ", " C ", " S ", " G ", " H ", " A ", " F ",
+                            " E ", " H ", " M ", " S ", " E ", " W ", " O ", " G ", " V ", " S ", " E ", " A ", " K "};
+  static const char *bp[] = {"   ", " *P", " *N", " *B", " *R", " *A", " *C", " *M", " *Q", " *E", " *B", " *Q", 
+                            " *W", " *H", " *N", " *J", " *I", " *L", " *C", " *S", " *G", " *H", " *A", " *F",
+                            " *E", " *H", " *M", " *S", " *E", " *W", " *O", " *G", " *V", " *S", " *E", " *A", " *K"};
+  static char *wsqr = "\033[0m";\r
+  static char *bsqr = "\033[7m";\r
+  static char *top = "\t+------------------------+\n";\r
+  static char *mid = "";\r
+  static char *start = "|";\r
+  static char *end = "\033[0m|";\r
+  static char *label = "\t  a  b  c  d  e  f  g  h  i  j  k  l\n";\r
+  static char *blabel = "\t  l  k  j  i  h  g  f  e  d  c  b  a\n";\r
+\r
+  return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel);\r
+}\r
+\r
+/* Experimental vt-100 ANSI board for light backgrounds */\r
+static int style4(struct game_state_t *b, struct move_t *ml)\r
+{\r
+  static const char *wp[] = {"   ", " P ", " N ", " B ", " R ", " A ", " C ", " M ", " Q ", " E ", " B ", " Q ", 
+                            " W ", " H ", " N ", " J ", " I ", " L ", " C ", " S ", " G ", " H ", " A ", " F ",
+                            " E ", " H ", " M ", " S ", " E ", " W ", " O ", " G ", " V ", " S ", " E ", " A ", " K "};
+  static const char *bp[] = {"   ", " *P", " *N", " *B", " *R", " *A", " *C", " *M", " *Q", " *E", " *B", " *Q", 
+                            " *W", " *H", " *N", " *J", " *I", " *L", " *C", " *S", " *G", " *H", " *A", " *F",
+                            " *E", " *H", " *M", " *S", " *E", " *W", " *O", " *G", " *V", " *S", " *E", " *A", " *K"};
+  static char *wsqr = "\033[7m";\r
+  static char *bsqr = "\033[0m";\r
+  static char *top = "\t+------------------------+\n";\r
+  static char *mid = "";\r
+  static char *start = "|";\r
+  static char *end = "\033[0m|";\r
+  static char *label = "\t  a  b  c  d  e  f  g  h  i  j  k  l\n";\r
+  static char *blabel = "\t  l  k  j  i  h  g  f  e  d  c  b  a\n";\r
+\r
+  return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel);\r
+}\r
+\r
+/* Style suggested by ajpierce@med.unc.edu */\r
+static int style5(struct game_state_t *b, struct move_t *ml)\r
+{\r
+  static const char *wp[] = {"    ", "  o ", " :N:", " <B>", " |R|", " (A)", " [C]", " :M:", " {Q}", " !E!",
+                            " <B>", " {Q}", " .W.", " :H:", " :N:", " <J>", " |I|", " |L|", 
+                            " |C|", " !S!", " :G:", " :H:", " {A}", " {F}", " !E!", " (H)", " [M]", " :S:",
+                            " !E!", " |W|", " *O*", " {G}", " :V:", " (S)", " [E]", " &A&", " =K="};
+  static const char *bp[] = {"    ", "  p ", " :n:", " <b>", " |r|", " (a)", " [c]", " :m:", " {q}", " !e!",
+                            " <b>", " {q}", " .w.", " :h:", " :n:", " <j>", " |i|", " |l|", 
+                            " |c|", " !s!", " :g:", " :h:", " {a}", " {f}", " !e!", " (h)", " [m]", " :s:",
+                            " !e!", " |w|", " *o*", " {g}", " :v:", " (s)", " [e]", " &a&", " =k="};
+  static char *wsqr = "";\r
+  static char *bsqr = "";\r
+  static char *top = "        .   .   .   .   .   .   .   .   .\n";\r
+  static char *mid = "        .   .   .   .   .   .   .   .   .\n";\r
+  static char *start = "";\r
+  static char *end = "";\r
+  static char *label = "\t  a   b   c   d   e   f   g   h   i   j   k   l\n";\r
+  static char *blabel = "\t  l   k   j   i   h   g   f   e   d   c   b   a\n";\r
+\r
+  return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel);\r
+}\r
+\r
+/* Email Board suggested by Thomas Fought (tlf@rsch.oclc.org) */\r
+static int style6(struct game_state_t *b, struct move_t *ml)\r
+{\r
+  static const char *wp[] = {"    |", " wp |", " WN |", " WB |", " WR |", " WA |", " WC |", " WM |", " WQ |", 
+                            " WE |", " WB |", " WQ |", " WW |", " WH |", " WN |", " WJ |", " WI |", " WL |", 
+                            " WC |", " WS |", " WG |", " WH |", " WA |", " WF |", " WE |", " WH |", " WM |", 
+                            " WS |", " WE |", " WW |", " WO |", " WG |", " WV |", " WS |", " WE |", " WA |", " WK |"};
+  static const char *bp[] = {"    |", " bp |", " BN |", " BB |", " BR |", " BA |", " BC |", " BM |", " BQ |", 
+                            " BE |", " BB |", " BQ |", " BW |", " BH |", " BN |", " BJ |", " BI |", " BL |", 
+                            " BC |", " BS |", " BG |", " BH |", " BA |", " BF |", " BE |", " BH |", " BM |", 
+                            " BS |", " BE |", " BW |", " BO |", " BG |", " BV |", " BS |", " BE |", " BA |", " BK |"};
+  static char *wsqr = "";\r
+  static char *bsqr = "";\r
+  static char *top = "\t-----------------------------------------\n";\r
+  static char *mid = "\t-----------------------------------------\n";\r
+  static char *start = "|";\r
+  static char *end = "";\r
+  static char *label = "\t  A    B    C    D    E    F    G    H    I    J    K    L\n";\r
+  static char *blabel = "\t  L    K    J    I    H    G    F    E    D    C    B    A\n";\r
+\r
+  return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel);\r
+}\r
+\r
+/* Miniature board */\r
+static int style7(struct game_state_t *b, struct move_t *ml)\r
+{\r
+  static const char *wp[] = {"  ", " P", " N", " B", " R", " A", " C", " M", " Q", " E", " B", " Q", " W", " H", " N", " J", " I", " L", 
+                            " C", " S", " G", " H", " A", " F", " E", " H", " M", " S", " E", " W", " O", " G", " V", " S", " E", " A", " K"};
+  static const char *bp[] = {" -", " p", " n", " b", " r", " a", " c", " m", " q", " e", " b", " q", " w", " h", " n", " j", " i", " l", 
+                            " c", " s", " g", " h", " a", " f", " e", " h", " m", " s", " e", " w", " o", " g", " v", " s", " e", " a", " k"};
+  static char *wsqr = "";\r
+  static char *bsqr = "";\r
+  static char *top = "\t:::::::::::::::::::::\n";\r
+  static char *mid = "";\r
+  static char *start = "..";\r
+  static char *end = " ..";\r
+  static char *label = "\t   a b c d e f g h i j k l\n";\r
+  static char *blabel = "\t   l k j i h g f e d c b a\n";\r
+\r
+  return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel);\r
+}\r
+
+/* ICS interface maker board-- raw data dump */\r
+static int style8(struct game_state_t *b, struct move_t *ml)\r
+{\r
+  char tmp[160];\r
+  int f, r;\r
+  int ws, bs;\r
+\r
+  board_calc_strength(b, &ws, &bs);\r
+  sprintf(tmp, "#@#%03d%-16s%s%-16s%s", b->gameNum + 1,\r
+         game_globals.garray[b->gameNum].white_name,\r
+         (orient == WHITE) ? "*" : ":",\r
+         game_globals.garray[b->gameNum].black_name,\r
+         (orient == WHITE) ? ":" : "*");\r
+  strcat(bstring, tmp);\r
+  for (r = 0; r < b->ranks; r++) {\r
+    for (f = 0; f < b->files; f++) {\r
+      if (b->board[f][r] == NOPIECE) {\r
+       strcat(bstring, " ");\r
+      } else {\r
+       if (colorval(b->board[f][r]) == WHITE)\r
+         strcat(bstring, wpstring[piecetype(b->board[f][r])]);\r
+       else\r
+         strcat(bstring, bpstring[piecetype(b->board[f][r])]);\r
+      }\r
+    }\r
+  }\r
+  sprintf(tmp, "%03d%s%02d%02d%05d%05d%-7s(%s)@#@\n",\r
+         game_globals.garray[b->gameNum].numHalfMoves / 2 + 1,\r
+         (b->onMove == WHITE) ? "W" : "B",\r
+         ws,\r
+         bs,\r
+         (wTime + 5) / 10,\r
+         (bTime + 5) / 10,\r
+         game_globals.garray[b->gameNum].numHalfMoves ?\r
+         ml[game_globals.garray[b->gameNum].numHalfMoves - 1].algString :\r
+         "none",\r
+         game_globals.garray[b->gameNum].numHalfMoves ?\r
+         tenth_str(ml[game_globals.garray[b->gameNum].numHalfMoves - 1].tookTime, 0) :\r
+         "0:00");\r
+  strcat(bstring, tmp);\r
+  return 0;\r
+}\r
+\r
+/* last 2 moves only (previous non-verbose mode) */\r
+static int style9(struct game_state_t *b, struct move_t *ml)\r
+{\r
+  int i, count;\r
+  char tmp[160];\r
+  int startmove;\r
+\r
+  sprintf(tmp, "\nMove     %-23s%s\n",\r
+         game_globals.garray[b->gameNum].white_name,\r
+         game_globals.garray[b->gameNum].black_name);\r
+  strcat(bstring, tmp);\r
+  sprintf(tmp, "----     --------------         --------------\n");\r
+  strcat(bstring, tmp);\r
+  startmove = ((game_globals.garray[b->gameNum].numHalfMoves - 3) / 2) * 2;\r
+  if (startmove < 0)\r
+    startmove = 0;\r
+  for (i = startmove, count = 0;\r
+       i < game_globals.garray[b->gameNum].numHalfMoves && count < 4;\r
+       i++, count++) {\r
+    if (!(i & 0x01)) {\r
+      sprintf(tmp, "  %2d     ", i / 2 + 1);\r
+      strcat(bstring, tmp);\r
+    }\r
+    sprintf(tmp, "%-23s", move_and_time(&ml[i]));\r
+    strcat(bstring, tmp);\r
+    if (i & 0x01)\r
+      strcat(bstring, "\n");\r
+  }\r
+  if (i & 0x01)\r
+    strcat(bstring, "\n");\r
+  return 0;\r
+}\r
+\r
+/* Sleator's 'new and improved' raw dump format... */\r
+static int style10(struct game_state_t *b, struct move_t *ml)\r
+{\r
+  int f, r;\r
+  char tmp[160];\r
+  int ws, bs;\r
+\r
+  board_calc_strength(b, &ws, &bs);\r
+  sprintf(tmp, "<10>\n");\r
+  strcat(bstring, tmp);\r
+  for (r = b->ranks-1; r >= 0; r--) {\r
+    strcat(bstring, "|");\r
+    for (f = 0; f < b->files; f++) {\r
+      if (b->board[f][r] == NOPIECE) {\r
+       strcat(bstring, " ");\r
+      } else {\r
+       if (colorval(b->board[f][r]) == WHITE)\r
+         strcat(bstring, wpstring[piecetype(b->board[f][r])]);\r
+       else\r
+         strcat(bstring, bpstring[piecetype(b->board[f][r])]);\r
+      }\r
+    }\r
+    strcat(bstring, "|\n");\r
+  }\r
+  strcat(bstring, (b->onMove == WHITE) ? "W " : "B ");\r
+  if (game_globals.garray[b->gameNum].numHalfMoves) {\r
+    sprintf(tmp, "%d ",\r
+           ml[game_globals.garray[b->gameNum].numHalfMoves - 1].doublePawn);\r
+  } else {\r
+    sprintf(tmp, "-1 ");\r
+  }\r
+  strcat(bstring, tmp);\r
+  sprintf(tmp, "%d %d %d %d %d\n",\r
+         (b->wkmoved >= 0 && b->wkrmoved >= 0), // [HGM] castle: inverted the logic, both must have rights\r
+         (b->wkmoved >= 0 && b->wqrmoved >= 0),\r
+         (b->bkmoved >= 0 && b->bkrmoved >= 0),\r
+         (b->bkmoved >= 0 && b->bqrmoved >= 0),\r
+       (game_globals.garray[b->gameNum].numHalfMoves - ((b->lastIrreversable == -1) ? 0 :\r
+                                          b->lastIrreversable)));\r
+  strcat(bstring, tmp);\r
+  sprintf(tmp, "%d %s %s %d %d %d %d %d %d %d %d %s (%s) %s %d\n",\r
+         b->gameNum,\r
+         game_globals.garray[b->gameNum].white_name,\r
+         game_globals.garray[b->gameNum].black_name,\r
+         myTurn,\r
+         game_globals.garray[b->gameNum].wInitTime / 600,\r
+         game_globals.garray[b->gameNum].wIncrement / 10,\r
+         ws,\r
+         bs,\r
+         (wTime + 5) / 10,\r
+         (bTime + 5) / 10,\r
+         game_globals.garray[b->gameNum].numHalfMoves / 2 + 1,\r
+         game_globals.garray[b->gameNum].numHalfMoves ?\r
+         ml[game_globals.garray[b->gameNum].numHalfMoves - 1].moveString :\r
+         "none",\r
+         game_globals.garray[b->gameNum].numHalfMoves ?\r
+         tenth_str(ml[game_globals.garray[b->gameNum].numHalfMoves - 1].tookTime, 0) :\r
+         "0:00",\r
+         game_globals.garray[b->gameNum].numHalfMoves ?\r
+         ml[game_globals.garray[b->gameNum].numHalfMoves - 1].algString :\r
+         "none",\r
+         (orient == WHITE) ? 0 : 1);\r
+  strcat(bstring, tmp);\r
+  sprintf(tmp, ">10<\n");\r
+  strcat(bstring, tmp);\r
+  return 0;\r
+}\r
+\r
+/* Same as 8, but with verbose moves ("P/e3-e4", instead of "e4") */\r
+static int style11(struct game_state_t *b, struct move_t *ml)\r
+{\r
+  char tmp[160];\r
+  int f, r;\r
+  int ws, bs;\r
+\r
+  board_calc_strength(b, &ws, &bs);\r
+  sprintf(tmp, "#@#%03d%-16s%s%-16s%s", b->gameNum,\r
+         game_globals.garray[b->gameNum].white_name,\r
+         (orient == WHITE) ? "*" : ":",\r
+         game_globals.garray[b->gameNum].black_name,\r
+         (orient == WHITE) ? ":" : "*");\r
+  strcat(bstring, tmp);\r
+  for (r = 0; r < b->ranks; r++) {\r
+    for (f = 0; f < b->files; f++) {\r
+      if (b->board[f][r] == NOPIECE) {\r
+       strcat(bstring, " ");\r
+      } else {\r
+       if (colorval(b->board[f][r]) == WHITE)\r
+         strcat(bstring, wpstring[piecetype(b->board[f][r])]);\r
+       else\r
+         strcat(bstring, bpstring[piecetype(b->board[f][r])]);\r
+      }\r
+    }\r
+  }\r
+    sprintf(tmp, "%03d%s%02d%02d%05d%05d%-7s(%s)@#@\n",\r
+           game_globals.garray[b->gameNum].numHalfMoves / 2 + 1,\r
+           (b->onMove == WHITE) ? "W" : "B",\r
+           ws,\r
+           bs,\r
+           (wTime + 5) / 10,\r
+           (bTime + 5) / 10,\r
+           game_globals.garray[b->gameNum].numHalfMoves ?\r
+           ml[game_globals.garray[b->gameNum].numHalfMoves - 1].moveString :\r
+           "none",\r
+           game_globals.garray[b->gameNum].numHalfMoves ?\r
+           tenth_str(ml[game_globals.garray[b->gameNum].numHalfMoves - 1].tookTime, 0) :\r
+           "0:00");\r
+  strcat(bstring, tmp);\r
+  return 0;\r
+}\r
+
+
+int kludgeFlag = 0; \r
+/* Similar to style 10.  See the "style12" help file for information */\r
+static int style12(struct game_state_t *b, struct move_t *ml)\r
+{\r
+  int f, r;\r
+  char tmp[160]; // [HGM] 80 caused problems with long login names\r
+  int ws, bs; 
+  int nhm = kludgeFlag ? 0 : game_globals.garray[b->gameNum].numHalfMoves; 
+  // [HGM] setup: the number of half moves appeared in this routine an enormous number of times,
+  // and had to be dug out of the game_globals, so that this routine could only be used to print
+  // a board from a game, and not just any board given by an isolated game_state_t. This was very
+  // inconvenient for printing initial boards in move lists of shuffle variants, so I added the
+  // global kludgeFlag to signal that we want to print an initial position, and force nhm = 0.\r
+\r
+  board_calc_strength(b, &ws, &bs);\r
+\r
+  sprintf(bstring, "<12> ");\r
+  for (r = b->ranks-1; r >= 0; r--) {\r
+    for (f = 0; f < b->files; f++) {
+      if (b->board[f][r] == NOPIECE) {\r
+       strcat(bstring, "-");\r
+      } else {\r
+       if (colorval(b->board[f][r]) == WHITE)\r
+         strcat(bstring, wpstring[piecetype(b->board[f][r])]);\r
+       else\r
+         strcat(bstring, bpstring[piecetype(b->board[f][r])]);\r
+      }\r
+    }\r
+    strcat(bstring, " ");\r
   }
+\r
+  strcat(bstring, (b->onMove == WHITE) ? "W " : "B ");\r
+  if (nhm) {\r
+    sprintf(tmp, "%d ",\r
+           ml[nhm - 1].doublePawn);\r
+  } else {\r
+    sprintf(tmp, "-1 ");\r
+  }\r
+  strcat(bstring, tmp);\r
+  sprintf(tmp, "%d %d %d %d %d ",\r
+         (b->wkmoved >= 0 && b->wkrmoved >= 0), // [HGM] castle: inverted the logic, both must have rights\r
+         (b->wkmoved >= 0 && b->wqrmoved >= 0),\r
+         (b->bkmoved >= 0 && b->bkrmoved >= 0),\r
+         (b->bkmoved >= 0 && b->bqrmoved >= 0),\r
+         (nhm - ((b->lastIrreversable == -1) ? 0 : b->lastIrreversable)));\r
   strcat(bstring, tmp);
-  sprintf(tmp, "%d %d %d %d %d ",
-         !(b->wkmoved || b->wkrmoved),
-         !(b->wkmoved || b->wqrmoved),
-         !(b->bkmoved || b->bkrmoved),
-         !(b->bkmoved || b->bqrmoved),
-         (game_globals.garray[b->gameNum].numHalfMoves - ((b->lastIrreversable == -1) ? 0 : b->lastIrreversable)));
-  strcat(bstring, tmp);
-  sprintf(tmp, "%d %s %s %d %d %d %d %d %d %d %d %s (%s) %s %d %d\n",
-         b->gameNum + 1,
-         game_globals.garray[b->gameNum].white_name,
-         game_globals.garray[b->gameNum].black_name,
-         myTurn,
-         game_globals.garray[b->gameNum].wInitTime / 600,
-         game_globals.garray[b->gameNum].wIncrement / 10,
-         ws,
-         bs,
-         (wTime / 10),
-         (bTime / 10),
-         game_globals.garray[b->gameNum].numHalfMoves / 2 + 1,
-         game_globals.garray[b->gameNum].numHalfMoves ?
-         ml[game_globals.garray[b->gameNum].numHalfMoves - 1].moveString :
-         "none",
-         game_globals.garray[b->gameNum].numHalfMoves ?
-         tenth_str(ml[game_globals.garray[b->gameNum].numHalfMoves - 1].tookTime, 0) :
-         "0:00",
-         game_globals.garray[b->gameNum].numHalfMoves ?
-         ml[game_globals.garray[b->gameNum].numHalfMoves - 1].algString :
-         "none", (orient == WHITE) ? 0 : 1,
-         b->moveNum > 1 ? 1 : 0); /* ticking */
-
-  strcat(bstring, tmp);
-  return 0;
-}
+  sprintf(tmp, "%d %s %s %d %d %d %d %d %d %d %d %s (%s) %s %d %d\n",\r
+         b->gameNum + 1,\r
+         game_globals.garray[b->gameNum].white_name,\r
+         game_globals.garray[b->gameNum].black_name,\r
+         myTurn,\r
+         game_globals.garray[b->gameNum].wInitTime / 600,\r
+         game_globals.garray[b->gameNum].wIncrement / 10,\r
+         ws,\r
+         bs,\r
+         (wTime / 10),\r
+         (bTime / 10),\r
+         nhm / 2 + 1,\r
+         nhm ?\r
+         ml[nhm - 1].moveString :\r
+         "none",\r
+         nhm ?\r
+         tenth_str(ml[nhm - 1].tookTime, 0) :\r
+         "0:00",\r
+         nhm ?\r
+         ml[nhm - 1].algString :\r
+         "none", (orient == WHITE) ? 0 : 1,\r
+         b->moveNum > 1 ? 1 : 0); /* ticking */\r
+
+  strcat(bstring, tmp);\r
+  return 0;\r
+}\r
 
 static int board_read_file(char *category, char *gname, struct game_state_t *gs)
 {
@@ -802,6 +995,7 @@ static int board_read_file(char *category, char *gname, struct game_state_t *gs)
     return 1;
 
   board_clear(gs);
+  gs->setup = 1;
   while (!feof(fp)) {
     c = fgetc(fp);
     if (onNewLine) {
@@ -813,6 +1007,55 @@ static int board_read_file(char *category, char *gname, struct game_state_t *gs)
        onColor = BLACK;
        if (gs->onMove < 0)
          gs->onMove = BLACK;
+      } else if (c == 'S') { int f=8, r=8;
+       // [HGM] rules: read rule modifiers
+       fscanf(fp, "%dx%d", &f, &r); gs->files=f; gs->ranks = r;
+       while (!feof(fp) && c != '\n') {
+         c = fgetc(fp);
+         switch(c) {
+           case 'r':
+               gs->royalKnight = 1;
+               break;
+           case 'c':
+               gs->capablancaPieces = 1;
+               break;
+           case 'd':
+               gs->drops = 1;
+               break;
+           case 'h':
+               gs->holdings = -1;     // color-flip holdings
+               break;
+           case 'p':
+               gs->palace = 3;
+               break;
+           case 'P':
+               gs->promoType = 2; // only promote to captured pieces
+               gs->holdings = 1;  // use holdings to hold own captured pieces
+               break;
+           case 'F':
+               gs->castlingStyle = 2; // FRC castling
+               break;
+           case 'w':
+               gs->castlingStyle = 1; // wild castling, from both center files
+               break;
+           case 'n':
+               gs->castlingStyle = 0; // no castling
+               break;
+           case 'f':
+               gs->castlingStyle = 3; // free castling
+               break;
+           case 'D':
+               gs->pawnDblStep = 0; // suppress pawn double step
+               break;
+           case 'b':
+               gs->bareKingLoses = 1; // apply baring rule
+               break;
+           case 's':
+               gs->stalemate = 0; // stalemate loses
+               break;
+         }
+       }       
+       continue;
       } else if (c == '#') {
        while (!feof(fp) && c != '\n')
          c = fgetc(fp);        /* Comment line */
@@ -837,36 +1080,128 @@ static int board_read_file(char *category, char *gname, struct game_state_t *gs)
       case 'B':
        onPiece = BISHOP;
        break;
+      case 'A':\r
+       onPiece = CARDINAL;\r
+       break;\r
+      case 'C':\r
+       onPiece = MARSHALL;\r
+       break;\r
+      case 'M':\r
+       onPiece = MAN;\r
+       break;\r
       case 'Q':
        onPiece = QUEEN;
        break;
-      case 'K':
-       onPiece = KING;
+      case 'T':
+       onPiece = ELEPHANT;
        break;
-      case 'a':
-      case 'b':
-      case 'c':
-      case 'd':
-      case 'e':
-      case 'f':
-      case 'g':
-      case 'h':
-       onFile = c - 'a';
-       onRank = -1;
+      case 'E':
+       onPiece = ALFIL;
+       break;
+      case 't':
+       onPiece = ALFIL2;
+       break;
+      case 'q':
+       onPiece = FERZ;
+       break;
+      case 'F':
+       onPiece = FERZ2;
+       break;
+      case 'W':
+       onPiece = WAZIR;
+       break;
+      case 'w':
+       onPiece = WOODY;
+       break;
+      case 'p':
+       onPiece = PRIESTESS;
+       break;
+      case 'r':
+       onPiece = MINISTER;
+       break;
+      case 'z':
+       onPiece = MAN2;
+       break;
+      case 'u':
+       onPiece = NIGHTRIDER;
+       break;
+      case 'o':
+       onPiece = MODERNELEPHANT;
+       break;
+      case 's':
+       onPiece = MASTODON;
+       break;
+      case 'Z':
+       onPiece = AMAZON;
+       break;
+      case 'V':
+       onPiece = CENTAUR;
+       break;
+      case 'H':
+       onPiece = HORSE;
+       break;
+      case 'n':
+       onPiece = HONORABLEHORSE;
+       break;
+      case 'J':
+       onPiece = DRAGONKING;
        break;
-      case '1':
-      case '2':
-      case '3':
-      case '4':
-      case '5':
-      case '6':
-      case '7':
-      case '8':
-       onRank = c - '1';
-       if (onFile >= 0 && onColor >= 0 && onPiece >= 0)
-         gs->board[onFile][onRank] = onPiece | onColor;
+      case 'I':
+       onPiece = DRAGONHORSE;
        break;
-      case '#':
+      case 'L':
+       onPiece = LANCE;
+       break;
+      case 'O':
+       onPiece = CANNON;
+       break;
+      case 'S':
+       onPiece = SILVER;
+       break;
+      case 'G':
+       onPiece = GOLD;
+       break;
+      case 'm':
+       onPiece = MANDARIN;
+       break;
+      case 'K':
+       onPiece = KING;
+       break;
+      case 'a':\r
+      case 'b':\r
+      case 'c':\r
+      case 'd':\r
+      case 'e':\r
+      case 'f':\r
+      case 'g':\r
+      case 'h':\r
+      case 'i':\r
+      case 'j':\r
+      case 'k':\r
+      case 'l':\r
+       onFile = c - 'a';\r
+        if(onFile >= gs->files) { onFile = -1; break; }\r
+       onRank = -1;\r
+       break;\r
+      case '@':
+       if (onColor >= 0 && onPiece >= 0) // allow placement in holdings\r
+         gs->holding[onColor == BLACK][onPiece-1]++;
+       break;\r
+      case '1':\r
+      case '2':\r
+      case '3':\r
+      case '4':\r
+      case '5':\r
+      case '6':\r
+      case '7':\r
+      case '8':\r
+      case '9':\r
+      case '0':\r
+       onRank = c - '1' + (gs->ranks > 9);\r
+        if(onRank < 0 || onRank >= gs->ranks) { onRank = -1; break; }\r
+       if (onFile >= 0 && onColor >= 0 && onPiece >= 0)\r
+         gs->board[onFile][onRank] = onPiece | onColor;\r
+       break;\r      case '#':
        while (!feof(fp) && c != '\n')
          c = fgetc(fp);        /* Comment line */
       case '\n':
@@ -890,8 +1225,8 @@ static int board_read_file(char *category, char *gname, struct game_state_t *gs)
 #define ANY_SQUARE -1
 #define SquareColor(f, r) ((f ^ r) & 1)
 
-static void place_piece(board_t b, int piece, int squareColor)
-{
+static void place_piece(board_t b, int piece, int squareColor, int width)
+{ //[HGM] board: make width a variable
   int r, f;
   int placed = 0;
 
@@ -902,9 +1237,9 @@ static void place_piece(board_t b, int piece, int squareColor)
 
   while (!placed) {
     if (squareColor == ANY_SQUARE) {
-      f = random() % 8;
+      f = random() % width;
     } else {
-      f = (random() % 4) * 2;
+      f = (random() % ((width+1)/2)) * 2; // to not overflow odd-width boards
       if (SquareColor(f, r) != squareColor)
        f++;
     }
@@ -915,12 +1250,11 @@ static void place_piece(board_t b, int piece, int squareColor)
   }
 }
 
-static void wild_update(int style)
+static void wild_update(board_t b, int style)
 {
-  int f, r, i;
-  board_t b;
+  int f, r, i, j;
 
-  for (f = 0; f < 8; f++)
+  for (f = 0; f < BW; f++) // [HGM] board: make sure also works with wider boards
     for (r = 0; r < 8; r++)
       b[f][r] = NOPIECE;
   for (f = 0; f < 8; f++) {
@@ -947,24 +1281,24 @@ static void wild_update(int style)
     b[0][7] = b[7][7] = B_ROOK;
     /* Must do bishops before knights to be sure opposite colored squares are
        available. */
-    place_piece(b, W_BISHOP, WHITE_SQUARE);
-    place_piece(b, W_BISHOP, BLACK_SQUARE);
-    place_piece(b, W_KNIGHT, ANY_SQUARE);
-    place_piece(b, W_KNIGHT, ANY_SQUARE);
-    place_piece(b, B_BISHOP, WHITE_SQUARE);
-    place_piece(b, B_BISHOP, BLACK_SQUARE);
-    place_piece(b, B_KNIGHT, ANY_SQUARE);
-    place_piece(b, B_KNIGHT, ANY_SQUARE);
+    place_piece(b, W_BISHOP, WHITE_SQUARE, 8);
+    place_piece(b, W_BISHOP, BLACK_SQUARE, 8);
+    place_piece(b, W_KNIGHT, ANY_SQUARE, 8);
+    place_piece(b, W_KNIGHT, ANY_SQUARE, 8);
+    place_piece(b, B_BISHOP, WHITE_SQUARE, 8);
+    place_piece(b, B_BISHOP, BLACK_SQUARE, 8);
+    place_piece(b, B_KNIGHT, ANY_SQUARE, 8);
+    place_piece(b, B_KNIGHT, ANY_SQUARE, 8);
     break;
   case 2:
-    place_piece(b, W_KING, ANY_SQUARE);
-    place_piece(b, W_QUEEN, ANY_SQUARE);
-    place_piece(b, W_ROOK, ANY_SQUARE);
-    place_piece(b, W_ROOK, ANY_SQUARE);
-    place_piece(b, W_BISHOP, ANY_SQUARE);
-    place_piece(b, W_BISHOP, ANY_SQUARE);
-    place_piece(b, W_KNIGHT, ANY_SQUARE);
-    place_piece(b, W_KNIGHT, ANY_SQUARE);
+    place_piece(b, W_KING, ANY_SQUARE, 8);
+    place_piece(b, W_QUEEN, ANY_SQUARE, 8);
+    place_piece(b, W_ROOK, ANY_SQUARE, 8);
+    place_piece(b, W_ROOK, ANY_SQUARE, 8);
+    place_piece(b, W_BISHOP, ANY_SQUARE, 8);
+    place_piece(b, W_BISHOP, ANY_SQUARE, 8);
+    place_piece(b, W_KNIGHT, ANY_SQUARE, 8);
+    place_piece(b, W_KNIGHT, ANY_SQUARE, 8);
     /* Black mirrors White */
     for (i = 0; i < 8; i++) {
       b[i][7] = b[i][0] | BLACK;
@@ -972,7 +1306,7 @@ static void wild_update(int style)
     break;
   case 3:
     /* Generate White king on random square plus random set of pieces */
-    place_piece(b, W_KING, ANY_SQUARE);
+    place_piece(b, W_KING, ANY_SQUARE, 8);
     for (i = 0; i < 8; i++) {
       if (b[i][0] != W_KING) {
        b[i][0] = (random() % 4) + 2;
@@ -985,7 +1319,7 @@ static void wild_update(int style)
     break;
   case 4:
     /* Generate White king on random square plus random set of pieces */
-    place_piece(b, W_KING, ANY_SQUARE);
+    place_piece(b, W_KING, ANY_SQUARE, 8);
     for (i = 0; i < 8; i++) {
       if (b[i][0] != W_KING) {
        b[i][0] = (random() % 4) + 2;
@@ -997,15 +1331,47 @@ static void wild_update(int style)
        to be sure there are enough squares left of the correct color. */
     for (i = 0; i < 8; i++) {
       if (b[i][0] == W_BISHOP) {
-       place_piece(b, B_BISHOP, !SquareColor(i, 0));
+       place_piece(b, B_BISHOP, !SquareColor(i, 0), 8);
       }
     }
     for (i = 0; i < 8; i++) {
       if (b[i][0] != W_BISHOP) {
-       place_piece(b, b[i][0] | BLACK, ANY_SQUARE);
+       place_piece(b, b[i][0] | BLACK, ANY_SQUARE, 8);
       }
     }
     break;
+  case 22:
+    /* Chess960 placement: King between R */
+    place_piece(b, W_BISHOP, WHITE_SQUARE, 8);
+    place_piece(b, W_BISHOP, BLACK_SQUARE, 8);
+    place_piece(b, W_QUEEN,  ANY_SQUARE, 8);
+    place_piece(b, W_KNIGHT, ANY_SQUARE, 8);
+    place_piece(b, W_KNIGHT, ANY_SQUARE, 8);
+    for (i = j = 0; i < 8; i++) {
+      if(b[i][0] == NOPIECE) b[i][0] = (j++ == 1 ? W_KING : W_ROOK);
+    }
+    /* Black mirrors White */
+    for (i = 0; i < 8; i++) {
+      b[i][7] = b[i][0] | BLACK;
+    }
+    break;
+  case 46:
+    /* Chess960 placement: King between R */
+    place_piece(b, W_BISHOP, WHITE_SQUARE, 10);
+    place_piece(b, W_BISHOP, BLACK_SQUARE, 10);
+    place_piece(b, W_QUEEN,  ANY_SQUARE, 10);
+    place_piece(b, W_MARSHALL, ANY_SQUARE, 10);
+    place_piece(b, W_CARDINAL, ANY_SQUARE, 10);
+    place_piece(b, W_KNIGHT, ANY_SQUARE, 10);
+    place_piece(b, W_KNIGHT, ANY_SQUARE, 10);
+    for (i = j = 0; i < 10; i++) {
+      if(b[i][0] == NOPIECE) j++ == 1 ? W_KING : W_ROOK;
+    }
+    /* Black mirrors White */
+    for (i = 0; i < 10; i++) {
+      b[i][7] = b[i][0] | BLACK;
+    }
+    break;
   default:
     return;
     break;
@@ -1048,9 +1414,10 @@ static void wild_update(int style)
 
 void wild_init(void)
 {
-       wild_update(1);
-       wild_update(2);
-       wild_update(3);
-       wild_update(4);
+       board_t b;
+       wild_update(b, 1);
+       wild_update(b, 2);
+       wild_update(b, 3);
+       wild_update(b, 4);
 }
 
index 051866b..a94a96e 100644 (file)
 
 /* These will go into an array */
 
-#define NOPIECE 0x00
-#define PAWN 0x01
-#define KNIGHT 0x02
-#define BISHOP 0x03
-#define ROOK 0x04
-#define QUEEN 0x05
-#define KING 0x06
-
-#define MAX_BOARD_STRING_LEGTH 1280    /* Abitrarily 80 * 16 */
+#define NOPIECE 0
+#define PAWN 1
+#define KNIGHT 2
+#define BISHOP 3
+#define ROOK 4
+#define CARDINAL 5
+#define MARSHALL 6
+#define MAN 7
+#define QUEEN 8
+#define ELEPHANT 9
+#define ALFIL 10
+#define FERZ 11
+#define WAZIR 12
+#define HORSE 13
+#define HONORABLEHORSE 14
+#define DRAGONKING 15
+#define DRAGONHORSE 16
+#define LANCE 17
+#define CANNON 18
+#define SILVER 19
+#define GOLD 20
+#define NIGHTRIDER 21
+#define MANDARIN 22
+#define FERZ2 23
+#define ALFIL2 24
+#define PRIESTESS 25
+#define MINISTER 26
+#define MAN2 27
+#define MODERNELEPHANT 28
+#define WOODY 29
+#define SQUIRREL 30
+#define MASTODON 31
+#define CENTAUR 32
+#define PRINCESS 33
+#define EMPRESS 34
+#define AMAZON 35
+#define KING 36
+
+#define MAX_BOARD_STRING_LENGTH 1280   /* Abitrarily 80 * 16 */
 #define MAX_STYLES 13
 
 #define W_PAWN (PAWN | WHITE)
 #define W_KNIGHT (KNIGHT | WHITE)
 #define W_BISHOP (BISHOP | WHITE)
 #define W_ROOK (ROOK | WHITE)
+#define W_CARDINAL (CARDINAL | WHITE)
+#define W_MARSHALL (MARSHALL | WHITE)
+#define W_MAN (MAN | WHITE)
 #define W_QUEEN (QUEEN | WHITE)
+#define W_ELEPHANT (ELEPHANT | WHITE)
+#define W_ALFIL (ALFIL | WHITE)
+#define W_FERZ (FERZ | WHITE)
+#define W_WAZIR (WAZIR | WHITE)
+#define W_ALFIL2 (ALFIL2 | WHITE)
+#define W_FERZ2 (FERZ2 | WHITE)
+#define W_AMAZON (AMAZON | WHITE)
+#define W_CENTAUR (CENTAUR | WHITE)
+#define W_HORSE (HORSE | WHITE)
+#define W_HONORABLEHORSE (HONORABLEHORSE | WHITE)
+#define W_DRAGONKING (DRAGONKING | WHITE)
+#define W_DRAGONHORSE (DRAGONHORSE | WHITE)
+#define W_LANCE (LANCE | WHITE)
+#define W_CANNON (CANNON | WHITE)
+#define W_SILVER (SILVER | WHITE)
+#define W_GOLD (GOLD | WHITE)
 #define W_KING (KING | WHITE)
+#define W_MANDARIN (MANDARIN | WHITE)
+#define W_EMPRESS (EMPRESS | WHITE)
+#define W_PRINCESS (PRINCESS | WHITE)
+#define W_WOODY (WOODY | WHITE)
+#define W_MINISTER (MINISTER | WHITE)
+#define W_PRIESTESS (PRIESTESS | WHITE)
+#define W_MASTODON (MASTODON | WHITE)
+#define W_MAN2 (MAN2 | WHITE)
+#define W_NIGHTRIDER (NIGHTRIDER | WHITE)
 
 #define B_PAWN (PAWN | BLACK)
 #define B_KNIGHT (KNIGHT | BLACK)
 #define B_BISHOP (BISHOP | BLACK)
 #define B_ROOK (ROOK | BLACK)
+#define B_CARDINAL (CARDINAL | BLACK)
+#define B_MARSHALL (MARSHALL | BLACK)
+#define B_MAN (MAN | BLACK)
 #define B_QUEEN (QUEEN | BLACK)
+#define B_ELEPHANT (ELEPHANT | BLACK)
+#define B_ALFIL (ALFIL | BLACK)
+#define B_FERZ (FERZ | BLACK)
+#define B_WAZIR (WAZIR | BLACK)
+#define B_ALFIL2 (ALFIL2 | BLACK)
+#define B_FERZ2 (FERZ2 | BLACK)
+#define B_AMAZON (AMAZON | BLACK)
+#define B_CENTAUR (CENTAUR | BLACK)
+#define B_HORSE (HORSE | BLACK)
+#define B_HONORABLEHORSE (HONORABLEHORSE | BLACK)
+#define B_DRAGONKING (DRAGONKING | BLACK)
+#define B_DRAGONHORSE (DRAGONHORSE | BLACK)
+#define B_LANCE (LANCE | BLACK)
+#define B_CANNON (CANNON | BLACK)
+#define B_SILVER (SILVER | BLACK)
+#define B_GOLD (GOLD | BLACK)
 #define B_KING (KING | BLACK)
+#define B_MANDARIN (MANDARIN | BLACK)
+#define B_EMPRESS (EMPRESS | BLACK)
+#define B_PRINCESS (PRINCESS | BLACK)
+#define B_WOODY (WOODY | BLACK)
+#define B_MINISTER (MINISTER | BLACK)
+#define B_PRIESTESS (PRIESTESS | BLACK)
+#define B_MASTODON (MASTODON | BLACK)
+#define B_MAN2 (MAN2 | BLACK)
+#define B_NIGHTRIDER (NIGHTRIDER | BLACK)
 
 #define isblack(p) ((p) & BLACK)
 #define iswhite(p) (!isblack(p))
 #define colorval(p) ((p) & 0x80)
 #define square_color(r,f) ((((r)+(f)) & 0x01) ? BLACK : WHITE)
 
-extern int pieceValues[7];
+extern int pieceValues[KING+1];
 
+#define BW 12
+#define BH 10
 /* Treated as [file][rank] */
-typedef int board_t[8][8];
+typedef int board_t[BW][BH];
 
 GENSTRUCT struct game_state_t {
-       int board[8][8];
+       int board[BW][BH];
        /* for bughouse */
-       int holding[2][5];
+       int holding[2][KING];
        /* For castling */
-       unsigned char wkmoved, wqrmoved, wkrmoved;
-       unsigned char bkmoved, bqrmoved, bkrmoved;
+       char wkmoved, wqrmoved, wkrmoved;
+       char bkmoved, bqrmoved, bkrmoved;
        /* for ep */
-       int ep_possible[2][8];
+       int ep_possible[2][BW];
        /* For draws */
        int lastIrreversable;
        int onMove;
        int moveNum;
        /* Game num not saved, must be restored when read */
        int gameNum;
+       char royalKnight;
+       char capablancaPieces;
+       char pawnDblStep;
+       char ranks;
+       char files;
+       char holdings;
+       char drops;
+       char castlingStyle;
+       char palace;
+       char setup;
+       char bareKingLoses;
+       char stalemate;
+       char promoType;
+       char variant[20];
 };
 
 #define ALG_DROP -2
+#define ALG_CASTLE -3
 
 /* bughouse: if a drop move, then fromFile is ALG_DROP and fromRank is piece */
 
@@ -103,6 +206,10 @@ GENSTRUCT struct move_t {
        /* these are used when examining a game */
        int wTime;
        int bTime;
+
+       /* [HGM] these are used for computer games */
+       float score;
+       int depth;
 };
 
 #define MoveToHalfMove( gs ) ((((gs)->moveNum - 1) * 2) + (((gs)->onMove == WHITE) ? 0 : 1))
@@ -110,6 +217,8 @@ GENSTRUCT struct move_t {
 extern const char *wpstring[];
 extern const char *bpstring[];
 
+extern int kludgeFlag; // [HGM] setup: forces move nr to zero in board printing
+
 /* the FEN for the default initial position */
 #define INITIAL_FEN "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w"
 
index f779206..7d440c5 100644 (file)
@@ -21,7 +21,7 @@
 #include "includes.h"
 #include "command_list.h"
 
-static const char *usage_dir[NUM_LANGS] = {USAGE_DIR, USAGE_SPANISH, 
+const char *usage_dir[NUM_LANGS] = {USAGE_DIR, USAGE_SPANISH, 
                                           USAGE_FRENCH, USAGE_DANISH};
 
 static int lastCommandFound = -1;
index f18571c..69509ee 100644 (file)
@@ -90,7 +90,7 @@
 #define DEFAULT_TIME 2
 #define DEFAULT_INCREMENT 12
 #define DEFAULT_MAX_SOUGHT 1000
-#define DEFAULT_IDLE_TIMEOUT 3600
+#define DEFAULT_IDLE_TIMEOUT 36000
 #define DEFAULT_LOGIN_TIMEOUT 300
 #define DEFAULT_GUEST_PREFIX_ONLY 0
 
old mode 100644 (file)
new mode 100755 (executable)
index bc3a115..5d13738
@@ -48,63 +48,66 @@ static int ECO_entries, NIC_entries, LONG_entries;
 
 void FEN_to_board(char* FENpos, struct game_state_t* gs)
 {
-  int f,r;
-  char next;
-  
-  for (r=7; r >=0; r--) {
-    f=0;
-    while (f<8) {
-      next = *(FENpos++);
-      if (isalpha(next))
-        gs->board[f++][r] = CharToPiece(next);
-      else if (next != '/') {
-        int t = (next - '0');
-        do
-          gs->board[f++][r] = NOPIECE;
-        while (--t);
-      }
-    }
-  }
-  if (*(FENpos + 1) == 'w') /* the char after the space */
-    gs->onMove = WHITE;
-  else
-    gs->onMove = BLACK;
+  int f,r;\r
+  char next;\r
+printf("FEN, var='%s'\n", gs->variant);\r
+  for (r=gs->ranks-1; r >=0; r--) {\r
+    f=0;\r
+    while (f<gs->files) {\r
+      next = *(FENpos++);\r
+      if (isalpha(next))\r
+        gs->board[f++][r] = CharToPiece(next, gs->variant);\r
+      else if (next != '/') {\r
+        int t = (next - '0');\r
+         if(*FENpos >= '0' && *FENpos <= '9') // [HGM] can be double-digit\r
+             t = 10*t + *(FENpos++) - '0';\r
+        do\r
+          gs->board[f++][r] = NOPIECE;\r
+        while (--t && f < gs->files);\r
+      }\r
+    }\r
+  }\r
+  if (*(FENpos + 1) == 'w') /* the char after the space */\r
+    gs->onMove = WHITE;\r
+  else\r
+    gs->onMove = BLACK;\r
 }
 
 /* converts a board to a FEN pos */
 
 static void board_to_FEN(char* FENpos, struct game_state_t* gs)
 {
-  int f,r,count;
-  char piece;  
-
-  for (r=7; r>=0; r--) {
-    count = 0;
-    for (f=0;  f<8; f++) {
-      if ((piece = PieceToChar(gs->board[f][r])) != ' ') {
-        if (count) { 
-          *(FENpos++) = count + '0';
-          count = 0;
-        }
-        *(FENpos++) = piece;
-      } else {
-        if (f == 7)
-          *(FENpos++) = count + '0' + 1;
-        else
-          count++;
-      }
-    }
-    *(FENpos++) = '/';
-  }
-
-  *(--FENpos) = ' ';
-
-  if (gs->onMove == WHITE)
-    *(++FENpos) = 'w';
-  else
-    *(++FENpos) = 'b';
-  *(++FENpos) = '\0';
+  int f,r,count;\r
+  char piece;  \r
+\r
+  for (r=gs->ranks-1; r>=0; r--) {\r
+    count = 0;\r
+    for (f=0;  f<gs->files; f++) {\r
+      if ((piece = PieceToChar(gs->board[f][r])) != ' ') {\r
+        if (count) { \r
+           if(count > 9) { count -= 10; *(FENpos++) = '1'; }\r
+          *(FENpos++) = count + '0';\r
+          count = 0;\r
+        }\r
+        *(FENpos++) = piece;\r
+      } else {\r
+        if (f == gs->files-1) {\r
+           if(count > 8) { count -= 10; *(FENpos++) = '1'; }\r
+          *(FENpos++) = count + '0' + 1;\r
+        } else\r
+          count++;\r
+      }\r
+    }\r
+    *(FENpos++) = '/';\r
+  }\r
+\r
+  *(--FENpos) = ' ';\r
+\r
+  if (gs->onMove == WHITE)\r
+    *(++FENpos) = 'w';\r
+  else\r
+    *(++FENpos) = 'b';\r
+  *(++FENpos) = '\0';\r
 }
 
 char *boardToFEN(int g)
index 76aed03..666b5ed 100644 (file)
@@ -30,7 +30,8 @@ static int game_zero(int g);
  
 const char *TypeStrings[NUM_GAMETYPES] = {"untimed", "blitz", "standard", 
                                          "nonstandard", "wild", "lightning", 
-                                         "bughouse"};
+                                         "bughouse", "gothic", "knightmate", 
+                                         "capablanca"};
 
 /* this method is awful! how about allocation as we need it and freeing
     afterwards! */
@@ -127,7 +128,7 @@ static char *game_time_str(int wt, int winc, int bt, int binc)
   return tstr;
 }
 
-const char *bstr[] = {"untimed", "blitz", "standard", "non-standard", "wild", "lightning", "Bughouse"};
+const char *bstr[] = {"untimed", "blitz", "standard", "non-standard", "wild", "lightning", "Bughouse", "Gothic", "Knightmate", "Capablanca"};
 
 const char *rstr[] = {"unrated", "rated"};
 
@@ -160,6 +161,12 @@ int game_isblitz(int wt, int winc, int bt, int binc,
   if(cat && cat[0]) {
     if (!strcmp(cat, "bughouse"))
       return TYPE_BUGHOUSE;
+    if (!strcmp(cat, "gothic"))
+      return TYPE_GOTHIC;
+    if (!strcmp(cat, "knightmate"))
+      return TYPE_KNIGHTMATE;
+    if (!strcmp(cat, "capablanca"))
+      return TYPE_CAPABLANCA;
     if (board && board[0]) {
       if (!strcmp(cat, "wild"))
         return TYPE_WILD;
@@ -247,7 +254,14 @@ void send_boards(int g)
 
        if ((game_globals.garray[g].status != GAME_SETUP) && 
            (check_kings(&game_globals.garray[g].game_state))) {
-               d_printf( "Game has invalid amount of kings.  Aborting...\n");
+               d_printf( "Game has invalid number of kings.  Aborting...\n");
+{ int f, r;
+d_printf("files = %d, ranks = %d\n", game_globals.garray[g].game_state.files, game_globals.garray[g].game_state.ranks);
+for(r=0; r<game_globals.garray[g].game_state.ranks; r++) {
+  for(f=0; f<game_globals.garray[g].game_state.files; f++)
+       d_printf("b[%d][%d]=%d\n",f,r,game_globals.garray[g].game_state.board[f][r]);
+}
+}
                game_finish(g);
                
                for (p = 0; p < player_globals.p_num; p++) {
@@ -344,6 +358,10 @@ char *EndString(int g, int personal)
     sprintf(endstr, "%s checkmated",
            game_globals.garray[g].winner == WHITE ? blackguy : whiteguy);
     break;
+  case END_BARE:
+    sprintf(endstr, "%s bared",
+           game_globals.garray[g].winner == WHITE ? blackguy : whiteguy);
+    break;
   case END_RESIGN:
     sprintf(endstr, "%s resigned",
            game_globals.garray[g].winner == WHITE ? blackguy : whiteguy);
@@ -423,6 +441,7 @@ const char *EndSym(int g)
        case END_RESIGN:
        case END_FLAG:
        case END_ADJWIN:
+       case END_BARE:
                return ((game_globals.garray[g].winner == WHITE) ? symbols[0] : symbols[1]);
                break;
        case END_AGREEDDRAW:
@@ -471,7 +490,8 @@ char *movesToString(int g, int pgn)
            "\n[Event \"%s %s %s game\"]\n"
            "[Site \"%s, %s\"]\n",
            config_get_tmp("SERVER_NAME"),
-           rstr[game_globals.garray[g].rated], bstr[game_globals.garray[g].type],
+           rstr[game_globals.garray[g].rated], /*bstr[game_globals.garray[g].type],*/ 
+           game_globals.garray[g].variant, // [HGM] allow more variation in game_types
            config_get_tmp("SERVER_NAME"),
            config_get_tmp("SERVER_LOCATION"));
     strftime(tmp, sizeof(tmp),
@@ -487,6 +507,19 @@ char *movesToString(int g, int pgn)
            "[BlackElo \"%d\"]\n",
            game_globals.garray[g].white_name, game_globals.garray[g].black_name, wr, br);
     strcat(gameString, tmp);
+    if(game_globals.garray[g].game_state.variant[0]) { // [HGM] variant: print variant tag
+        sprintf(tmp,
+           "[Variant \"%s\"]\n",
+           game_globals.garray[g].game_state.variant);
+        strcat(gameString, tmp);
+    }
+    if(game_globals.garray[g].game_state.setup) { // [HGM] setup: print the FEN
+        sprintf(tmp,
+           "[Setup \"1\"]\n"
+           "[FEN \"%s\"]\n",
+           game_globals.garray[g].FENstartPos);
+        strcat(gameString, tmp);
+    }
     sprintf(tmp,
            "[TimeControl \"%d+%d\"]\n"
            "[Mode \"ICS\"]\n"
@@ -511,6 +544,14 @@ char *movesToString(int g, int pgn)
        col = 0;
       }
       strcat(gameString, tmp);
+      if(moves[i].depth > 0) { // [HGM] computer game, add {score/depth} comment
+       if ((col += sprintf(tmp, "{%s%.2f/%d} ", moves[i].score > 0 ? "+" : "",
+                               moves[i].score, moves[i].depth)) > 70) {
+         strcat(gameString, "\n");
+         col = 0;
+       }
+       strcat(gameString, tmp);
+      }
     }
     strcat(gameString, "\n");
 
@@ -538,7 +579,8 @@ char *movesToString(int g, int pgn)
     } else {
       strcat(gameString, "\nUnrated ");
     }
-    strcat (gameString, TypeStrings[game_globals.garray[g].type]);
+//    strcat (gameString, TypeStrings[game_globals.garray[g].type]);
+    strcat (gameString, game_globals.garray[g].variant);
     strcat(gameString, " match, initial time: ");
     if ((game_globals.garray[g].bInitTime != game_globals.garray[g].wInitTime) || (game_globals.garray[g].wIncrement != game_globals.garray[g].bIncrement)) { /* different starting times */ 
       sprintf(tmp, "%d minutes, increment: %d seconds AND %d minutes, increment: %d seconds.\n\n", game_globals.garray[g].wInitTime / 600, game_globals.garray[g].wIncrement / 10, game_globals.garray[g].bInitTime / 600, game_globals.garray[g].bIncrement / 10);
@@ -546,6 +588,45 @@ char *movesToString(int g, int pgn)
       sprintf(tmp, "%d minutes, increment: %d seconds.\n\n", game_globals.garray[g].wInitTime / 600, game_globals.garray[g].wIncrement / 10);
     }
     strcat(gameString, tmp);
+    if(game_globals.garray[g].game_state.setup) { // [HGM] setup: print the initial position board
+       char *q; struct game_state_t initial_gs; struct move_t ml[600]; int r, f;
+
+       initial_gs.gameNum = g;
+       initial_gs.wkrmoved = 0; // [HGM] for some reason calling reset_board_vars() does not work here
+       initial_gs.wqrmoved = 0; //       so I just duplicated the code and pasted it here...
+       initial_gs.wkmoved = 0;
+       initial_gs.bkrmoved = 0;
+       initial_gs.bqrmoved = 0;
+       initial_gs.bkmoved = 0;
+       initial_gs.onMove = WHITE;
+       initial_gs.lastIrreversable = -1;
+       initial_gs.files = game_globals.garray[g].game_state.files;
+       initial_gs.ranks = game_globals.garray[g].game_state.ranks;
+       initial_gs.holdings = game_globals.garray[g].game_state.holdings;
+       strcpy(initial_gs.variant, game_globals.garray[g].game_state.variant);
+        for (f = 0; f < 2; f++) {
+          for (r = 0; r < initial_gs.files; r++)
+             initial_gs.ep_possible[f][r] = 0;
+          for (r = PAWN; r <= QUEEN; r++)
+            initial_gs.holding[f][r-PAWN] = 0;
+       }
+       FEN_to_board(game_globals.garray[g].FENstartPos ,&initial_gs);
+
+       kludgeFlag = 1; // [HGM] setup: this is not thread safe. Must it be???
+       q = board_to_string(
+                     game_globals.garray[g].white_name,
+                     game_globals.garray[g].black_name,
+                     game_globals.garray[g].wTime,
+                     game_globals.garray[g].bTime,
+                     &initial_gs,
+                     ml,
+                     11,
+                     WHITE, 0, 0);
+       kludgeFlag = 0;
+
+        strcat(gameString, q);
+        strcat(gameString, "\n");
+    }
     sprintf(tmp, "Move  %-19s%-19s\n", game_globals.garray[g].white_name, game_globals.garray[g].black_name);
     strcat(gameString, tmp);
     strcat(gameString, "----  ----------------   ----------------\n");
@@ -584,8 +665,65 @@ void game_disconnect(int g, int p)
   game_ended(g, (game_globals.garray[g].white == p) ? WHITE : BLACK, END_LOSTCONNECTION);
 }
 
-int CharToPiece(char c)
+int CharToPiece(char c, char *variant)
 {
+
+  if(variant) {
+    if(!strcmp(variant, "shogi")) {
+      switch(c) {
+       case 'N':
+         return W_HONORABLEHORSE;
+       case 'n':
+         return B_HONORABLEHORSE;
+       case 'L':
+         return W_LANCE;
+       case 'l':
+         return B_LANCE;
+       case 'S':
+         return W_SILVER;
+       case 's':
+         return B_SILVER;
+       case 'G':
+         return W_GOLD;
+       case 'g':
+         return B_GOLD;
+      }
+    } else if(!strcmp(variant, "xiangqi")) {
+      switch(c) {
+       case 'A':
+         return W_MANDARIN;
+       case 'a':
+         return B_MANDARIN;
+       case 'H':
+         return W_HORSE;
+       case 'h':
+         return B_HORSE;
+       case 'C':
+         return W_CANNON;
+       case 'c':
+         return B_CANNON;
+      }
+    } else if(!strcmp(variant, "super")) {
+      switch(c) {
+       case 'E':
+         return W_EMPRESS;
+       case 'e':
+         return B_EMPRESS;
+       case 'S':
+         return W_PRINCESS;
+       case 's':
+         return B_PRINCESS;
+       case 'Z':
+         return W_AMAZON;
+       case 'z':
+         return B_AMAZON;
+       case 'V':
+         return W_CENTAUR;
+       case 'v':
+         return B_CENTAUR;
+      }
+    }
+  }
   switch (c) {
   case 'P':
     return W_PAWN;
@@ -603,10 +741,26 @@ int CharToPiece(char c)
     return W_ROOK;
   case 'r':
     return B_ROOK;
+  case 'A':
+    return W_CARDINAL;
+  case 'a':
+    return B_CARDINAL;
+  case 'C':
+    return W_MARSHALL;
+  case 'c':
+    return B_MARSHALL;
+  case 'M':
+    return W_MAN;
+  case 'm':
+    return B_MAN;
   case 'Q':
     return W_QUEEN;
   case 'q':
     return B_QUEEN;
+  case 'E':
+    return W_ELEPHANT;
+  case 'e':
+    return B_ELEPHANT;
   case 'K':
     return W_KING;
   case 'k':
@@ -623,8 +777,10 @@ char PieceToChar(int piece)
   case B_PAWN:
     return 'p';
   case W_KNIGHT:
+  case W_HONORABLEHORSE:
     return 'N';
   case B_KNIGHT:
+  case B_HONORABLEHORSE:
     return 'n';
   case W_BISHOP:
     return 'B';
@@ -634,14 +790,92 @@ char PieceToChar(int piece)
     return 'R';
   case B_ROOK:
     return 'r';
+  case W_CARDINAL:
+  case W_MANDARIN:
+  case W_ALFIL2:
+    return 'A';
+  case B_CARDINAL:
+  case B_MANDARIN:
+  case B_ALFIL2:
+    return 'a';
+  case W_CANNON:
+  case W_MARSHALL:
+    return 'C';
+  case B_CANNON:
+  case B_MARSHALL:
+    return 'c';
+  case W_MAN:
+  case W_MINISTER:
+    return 'M';
+  case B_MAN:
+  case B_MINISTER:
+    return 'm';
   case W_QUEEN:
     return 'Q';
   case B_QUEEN:
     return 'q';
+  case W_ELEPHANT:
+  case W_EMPRESS:
+    return 'E';
+  case B_ELEPHANT:
+  case B_EMPRESS:
+    return 'e';
+  case W_ALFIL:
+    return 'B';
+  case B_ALFIL:
+    return 'b';
+  case W_FERZ:
+    return 'Q';
+  case B_FERZ:
+    return 'q';
+  case W_FERZ2:
+    return 'F';
+  case B_FERZ2:
+    return 'f';
+  case W_WAZIR:
+  case W_WOODY:
+    return 'W';
+  case B_WAZIR:
+  case B_WOODY:
+    return 'w';
+  case W_HORSE:
+  case W_PRIESTESS:
+  case W_NIGHTRIDER:
+    return 'H';
+  case B_HORSE:
+  case B_PRIESTESS:
+  case B_NIGHTRIDER:
+    return 'h';
+  case W_SILVER:
+  case W_PRINCESS:
+  case W_MAN2:
+    return 'S';
+  case B_SILVER:
+  case B_PRINCESS:
+  case B_MAN2:
+    return 's';
+  case W_GOLD:
+  case W_MASTODON:
+    return 'G';
+  case B_GOLD:
+  case B_MASTODON:
+    return 'g';
+  case W_AMAZON:
+    return 'Z';
+  case B_AMAZON:
+    return 'z';
+  case W_CENTAUR:
+    return 'V';
+  case B_CENTAUR:
+    return 'v';
   case W_KING:
     return 'K';
   case B_KING:
     return 'k';
+  case W_LANCE:
+    return 'L';
+  case B_LANCE:
+    return 'l';
   default:
     return ' ';
   }
@@ -779,7 +1013,10 @@ int game_read(int g, int wp, int bp)
   if (game_globals.garray[g].type == TYPE_BLITZ) {
     game_globals.garray[g].white_rating = player_globals.parray[wp].b_stats.rating;
     game_globals.garray[g].black_rating = player_globals.parray[bp].b_stats.rating;
-  } else if (game_globals.garray[g].type == TYPE_WILD) {
+  } else if (game_globals.garray[g].type == TYPE_WILD ||
+            game_globals.garray[g].type == TYPE_KNIGHTMATE ||
+            game_globals.garray[g].type == TYPE_CAPABLANCA ||
+            game_globals.garray[g].type == TYPE_GOTHIC) {
     game_globals.garray[g].white_rating = player_globals.parray[wp].w_stats.rating;
     game_globals.garray[g].black_rating = player_globals.parray[bp].w_stats.rating;
   } else if (game_globals.garray[g].type == TYPE_LIGHT) {
@@ -797,7 +1034,7 @@ int game_read(int g, int wp, int bp)
   if (!fp) {
     return -1;
   }
-  for (piece=PAWN; piece <= QUEEN; piece++) {
+  for (piece=PAWN; piece < KING; piece++) {
     game_globals.garray[g].game_state.holding[0][piece-PAWN]
       = game_globals.garray[g].game_state.holding[1][piece-PAWN] = 0;
   }
@@ -977,7 +1214,9 @@ static void write_g_out(int g, char *file, int maxlines, int isDraw,
     wr = player_globals.parray[wp].b_stats.rating;
     br = player_globals.parray[bp].b_stats.rating;
     type[1] = 'b';
-  } else if (game_globals.garray[g].type == TYPE_WILD) {
+  } else if (game_globals.garray[g].type == TYPE_WILD ||
+            game_globals.garray[g].type == TYPE_KNIGHTMATE ||
+            game_globals.garray[g].type == TYPE_GOTHIC) {
     wr = player_globals.parray[wp].w_stats.rating;
     br = player_globals.parray[bp].w_stats.rating;
     type[1] = 'w';
@@ -1458,8 +1697,8 @@ static int check_kings(struct game_state_t *gs)
        int f, r;
        
        
-       for (f = 0; f < 8; f++) {
-               for (r = 0; r < 8; r++) {
+       for (f = 0; f < gs->files; f++) {
+               for (r = 0; r < gs->ranks; r++) {
                        if (gs->board[f][r] == B_KING) blackking++;
                        if (gs->board[f][r] == W_KING) whiteking++;
                }
index 711700c..d0249b7 100644 (file)
@@ -36,9 +36,9 @@ GENSTRUCT enum gamestatus {GAME_EMPTY, GAME_NEW, GAME_ACTIVE, GAME_EXAMINE, GAME
 
 /* Do not change the order of these - DAV */
 GENSTRUCT enum gametype {TYPE_UNTIMED, TYPE_BLITZ, TYPE_STAND, TYPE_NONSTANDARD,
-               TYPE_WILD, TYPE_LIGHT, TYPE_BUGHOUSE};
+               TYPE_WILD, TYPE_LIGHT, TYPE_BUGHOUSE, TYPE_GOTHIC, TYPE_KNIGHTMATE, TYPE_CAPABLANCA};
 
-#define NUM_GAMETYPES 7 
+#define NUM_GAMETYPES 10 
 
 /* OK, DAV, I'll try it another way. -- hersco */
 enum ratetype {RATE_STAND, RATE_BLITZ, RATE_WILD, RATE_LIGHT, RATE_BUGHOUSE};
@@ -68,7 +68,8 @@ GENSTRUCT enum gameend {
        END_ADJDRAW,
        END_ADJWIN,
        END_ADJABORT,
-       END_COURTESYADJOURN
+       END_COURTESYADJOURN,
+       END_BARE                // [HGM] bare king
 };
 
 struct journal {
@@ -138,6 +139,7 @@ GENSTRUCT struct game {
        char black_name[MAX_LOGIN_NAME]; _NULLTERM   
        int white_rating;
        int black_rating;
+       char variant[80]; // [HGM] arbitrary variant name for sending to interface, derived from load-directory name
 };
 
 extern const char *TypeStrings[NUM_GAMETYPES];
index e9d9306..15b947e 100644 (file)
@@ -155,7 +155,7 @@ static int ReadGameState(FILE * fp, struct game_state_t *gs, int version)
     for (i = 0; i < 8; i++)
       for (j = 0; j < 8; j++) {
        pieceChar = getc(fp);
-       gs->board[i][j] = CharToPiece(pieceChar);
+       gs->board[i][j] = CharToPiece(pieceChar, NULL);
       }
   }
   if (fscanf(fp, "%d %d %d %d %d %d",
index 7e2cd5d..a0dba3f 100644 (file)
@@ -139,6 +139,11 @@ void game_ended(int g, int winner, int why)
     strcpy(EndSymbol, "Mat");
     rate_change = 1;
     break;
+  case END_BARE:
+    sprintf(tmp, "%s bared} %s", NameOfLoser, winSymbol);
+    strcpy(EndSymbol, "Bar");
+    rate_change = 1;
+    break;
   case END_RESIGN:
     sprintf(tmp, "%s resigns} %s", NameOfLoser, winSymbol);
     strcpy(EndSymbol, "Res");
@@ -335,7 +340,7 @@ void game_ended(int g, int winner, int why)
           pprintf (p,"\n%s",avail_black);
           avail_printed = 1;
         }
-        if (gl != -1) /* bughouse ? */ {
+        if (gl == -1) /* bughouse ? */ {
           if (((player_globals.parray[game_globals.garray[gl].white].b_stats.rating <= pp->availmax) && (player_globals.parray[game_globals.garray[gl].white].b_stats.rating >= pp->availmin)) || (!pp->availmax)) {
             pprintf (p,"\n%s",avail_bugwhite);
             avail_printed = 1;
@@ -547,6 +552,7 @@ void process_move(int p, char *command)
   }
   if ((len = strlen(command)) > 1) {
     if (command[len - 2] == '=') {
+printf("promo '%s'\n", command);
       switch (tolower(command[strlen(command) - 1])) {
       case 'n':
        pp->promote = KNIGHT;
@@ -557,9 +563,41 @@ void process_move(int p, char *command)
       case 'r':
        pp->promote = ROOK;
        break;
+      case 'a':
+       pp->promote = CARDINAL;
+       break;
+      case 'c':
+       pp->promote = MARSHALL;
+       break;
+      case 'm':
+       pp->promote = MAN;
+       break;
       case 'q':
        pp->promote = QUEEN;
        break;
+      // courier promotion
+      case 'f':
+       pp->promote = FERZ2;
+       break;
+      // Superchess promotions
+      case 'e':
+       pp->promote = EMPRESS;
+       break;
+      case 's':
+       pp->promote = PRINCESS;
+       break;
+      case 'v':
+       pp->promote = CENTAUR;
+       break;
+      case 'w':
+       pp->promote = WOODY;
+       break;
+      case 'o':
+       pp->promote = SQUIRREL;
+       break;
+      case 'g':
+       pp->promote = MASTODON;
+       break;
       default:
        pprintf(p, "Don't understand that move.\n");
        return;
@@ -567,6 +605,7 @@ void process_move(int p, char *command)
       }
     }
   }
+
   switch (parse_move(command, &gg->game_state, &move, pp->promote)) {
   case MOVE_ILLEGAL:
     pprintf(p, "Illegal move.\n");
@@ -633,13 +672,19 @@ void process_move(int p, char *command)
       gg->moveList = (struct move_t *) realloc(gg->moveList, sizeof(struct move_t) * gg->moveListSize);
     }
     result = execute_move(&gg->game_state, &move, 1);
-    if (result == MOVE_OK && gg->link >= 0 && move.pieceCaptured != NOPIECE) {
+    if (result == MOVE_OK && (gg->link >= 0 || gg->game_state.holdings) && move.pieceCaptured != NOPIECE) {
       /* transfer captured piece to partner */
       /* check if piece reverts to a pawn */
+      int victim = move.pieceCaptured, partner = gg->link;
+      // [HGM] zh: if not Bughouse, the game_state.holdings field decides what happens
+      if(gg->link < 0) { 
+       partner = g; // pieces stay with current board
+       if(gg->game_state.holdings == -1) victim ^= WHITE|BLACK; // flip color
+      } 
       if (was_promoted(&game_globals.garray[g], move.toFile, move.toRank))
-        update_holding(gg->link, colorval(move.pieceCaptured) | PAWN);
+        update_holding(partner, colorval(victim) | PAWN); // [HGM] todo: for Shogi we would have to demote differently!
       else
-        update_holding(gg->link, move.pieceCaptured);
+        update_holding(partner, victim);
     }
     now = tenth_secs();
     move.atTime = now;
@@ -733,6 +778,22 @@ void process_move(int p, char *command)
       game_ended(g, CToggle(gg->game_state.onMove), END_NOMATERIAL);
     }
   }
+  if (result == MOVE_BARE) {
+    if (gg->status == GAME_EXAMINE) {
+      int p1;
+
+      for (p1 = 0; p1 < player_globals.p_num; p1++) {
+       if (player_globals.parray[p1].status != PLAYER_PROMPT)
+         continue;
+       if (player_is_observe(p1, g) || player_globals.parray[p1].game == g) {
+         pprintf(p1, "%s bared.\n",
+                 (gg->game_state.onMove == BLACK) ? "White" : "Black");
+       }
+      }
+    } else {
+      game_ended(g, gg->game_state.onMove, END_BARE);
+    }
+  }
 }
 
 int com_resign(int p, param_list param)
@@ -1039,8 +1100,8 @@ static int player_has_mating_material(struct game_state_t *gs, int color)
   int piece;
   int minor_pieces = 0;
 
-  for (i = 0; i < 8; i++)
-    for (j = 0; j < 8; j++) {
+  for (i = 0; i < gs->files; i++)
+    for (j = 0; j < gs->ranks; j++) {
       piece = gs->board[i][j];
       switch (piecetype(piece)) {
       case BISHOP:
index 0a8988a..be1c93e 100644 (file)
@@ -21,7 +21,7 @@
 
 #include "includes.h"
 
-static const char *help_dir[NUM_LANGS] = {HELP_DIR, HELP_SPANISH, 
+const char *help_dir[NUM_LANGS] = {HELP_DIR, HELP_SPANISH, 
                                          HELP_FRENCH, HELP_DANISH};
 
 
index 35f1937..020be38 100644 (file)
@@ -23,7 +23,7 @@
 #include "includes.h"
 
 const char *colorstr[] = {"", "[black] ", "[white] "};
-static const char *adjustr[] = {"", " (adjourned)"};
+const char *adjustr[] = {"", " (adjourned)"};
 
 static void prepare_match(int g,int wt,int bt,int winc,int binc,int wp, int bp,int rated)
 {
@@ -156,7 +156,8 @@ static void output_match_messages(int wp,int bp,int g, char* mess)
           player_globals.parray[bp].name,
           game_globals.garray[g].black_rating,
           rstr[game_globals.garray[g].rated],
-          bstr[game_globals.garray[g].type],
+          //bstr[game_globals.garray[g].type],
+          game_globals.garray[g].variant,
           game_globals.garray[g].wInitTime, 
           game_globals.garray[g].wIncrement);
   pprintf(wp, "%s", outStr);
@@ -168,7 +169,8 @@ static void output_match_messages(int wp,int bp,int g, char* mess)
           player_globals.parray[bp].name,
          mess,
           rstr[game_globals.garray[g].rated],
-          bstr[game_globals.garray[g].type]);
+          //bstr[game_globals.garray[g].type]);
+         game_globals.garray[g].variant);
   pprintf(wp, "%s", outStr);
   pprintf(bp, "%s", outStr);
 
@@ -265,6 +267,7 @@ int create_new_match(int g, int white_player, int black_player,
     decline_withdraw_offers(white_player, -1, PEND_SIMUL,
                             DO_WITHDRAW | DO_DECLINE);
   }
+  game_globals.garray[g].FENstartPos[0] = 0; // [HGM] new shuffle
   if (board_init(g,&game_globals.garray[g].game_state, category, board)) {
     pprintf(white_player, "PROBLEM LOADING BOARD. Game Aborted.\n");
     pprintf(black_player, "PROBLEM LOADING BOARD. Game Aborted.\n");
@@ -279,6 +282,15 @@ int create_new_match(int g, int white_player, int black_player,
   else
     game_globals.garray[g].type = game_isblitz(wt, winc, bt, binc, category, board);
 
+  if(category && category[0]) { // [HGM] set variant string from directory for games loaded from file
+    if(!strcmp(category, "wild") && board)
+       sprintf(game_globals.garray[g].variant, "%s/%s", category, board);
+    else
+       strcpy(game_globals.garray[g].variant, category);
+  }
+  else
+    strcpy(game_globals.garray[g].variant, bstr[game_globals.garray[g].type]);
+
   prepare_match(g,wt,bt,winc,binc,white_player,black_player,rated);
 
   output_match_messages(white_player,black_player,g, "Creating");
@@ -490,10 +502,47 @@ static int parse_match_string(int p, int* wt,int* bt,int* winc,int* binc,
       } else {
         strcpy(category,parsebuf);
         if (!strncmp("bughouse",category, strlen(category))
-            && strlen(category) >= 3) {
+            && strlen(category) >= 3 || !strcmp("bh", category)) {
           strcpy(category, "bughouse");
           bughouse = 1;
         }
+       // [HGM] allow some shortcuts for variant names
+       if(!strcmp("bh", category)) {
+         strcpy(category, "bughouse");
+       } else
+       if(!strcmp("zh", category)) {
+         strcpy(category, "crazyhouse");
+       } else
+       if(!strcmp("fr", category)) {
+         strcpy(category, "fischerandom");
+       } else
+       if(!strcmp("sj", category)) {
+         strcpy(category, "shatranj");
+       } else
+       if(!strcmp("gc", category)) {
+         strcpy(category, "gothic");
+       } else
+       if(!strcmp("ca", category)) {
+         strcpy(category, "capablanca");
+       } else
+       if(!strcmp("cr", category)) {
+         strcpy(category, "caparandom");
+       } else
+       if(!strcmp("su", category)) {
+         strcpy(category, "super");
+       } else
+       if(!strcmp("sg", category)) {
+         strcpy(category, "shogi");
+       } else
+       if(!strcmp("km", category)) {
+         strcpy(category, "knightmate");
+       } else
+       if(!strcmp("gr", category)) {
+         strcpy(category, "great");
+       } else
+       if(!strcmp("xq", category)) {
+         strcpy(category, "xiangqi");
+       }
       }
     } else
       confused = 1;
@@ -503,6 +552,8 @@ static int parse_match_string(int p, int* wt,int* bt,int* winc,int* binc,
     pprintf(p, "Can't interpret %s in match command.\n", parsebuf);
     return 0;
   }
+  if(category && (!board || !board[0]))
+       strcpy(board, "0"); // [HGM] variants: always provide default board
   return 1;
 }
 
old mode 100644 (file)
new mode 100755 (executable)
index 81f2d37..953298c
 
 #include "includes.h"
 
+// [HGM] some explanation of the parser code:
+// The routine parse_move() calls is_move() to recognize some simple cases,
+// like OO-castle and long algebraic with or without dash. What does not fall
+// in this class is handed to alg_is_move(), whch is really a continuation
+// of is_move(), to recognize SAN.
+// Depending on the type of move syntax, parse_move can extract from- and to-square
+// immediately, or transate the OO-castling to internal from-to representation.
+// Only for SAN syntax the routine alg_pars_move() is called to extract the
+// given elements, (through get_move_info(), which is the same as alg_is_move(),
+// xcept that it does not discard the value of the elements), and disambiguate 
+// the move (i.e. determines the from-square) by looking for a piece of the given
+// type on the board for which the move is pseudo-legal (using legal_move() ).
+// Th
+
 /* Simply tests if the input string is a move or not. */
 /* If it matches patterns below */
 /* Add to this list as you improve the move parser */
@@ -99,14 +113,14 @@ int is_move(const char *mstr)
 }
 
 
-int NextPieceLoop(board_t b, int *f, int *r, int color)
+int NextPieceLoop(board_t b, int *f, int *r, int color, int w, int h)
 {
   for (;;) {
     (*r) = (*r) + 1;
-    if (*r > 7) {
+    if (*r >= h) {
       *r = 0;
       *f = *f + 1;
-      if (*f > 7)
+      if (*f >= w)
        break;
     }
     if ((b[*f][*r] != NOPIECE) && iscolor(b[*f][*r], color))
@@ -126,22 +140,22 @@ int InitPieceLoop(board_t b, int *f, int *r, int color)
 /* See legal_move() */
 static int legal_pawn_move( struct game_state_t *gs, int ff, int fr, int tf, int tr )
 {
-  if (ff == tf) {
-    if (gs->board[tf][tr] != NOPIECE) return 0;
-    if (gs->onMove == WHITE) {
-      if (tr - fr == 1) return 1;
-      if ((fr == 1) && (tr - fr == 2) && gs->board[ff][2]==NOPIECE) return 1;
-    } else {
-      if (fr - tr == 1) return 1;
-      if ((fr == 6) && (fr - tr == 2) && gs->board[ff][5]==NOPIECE) return 1;
-    }
-    return 0;
-  }
+  if (ff == tf) {\r
+    if (gs->board[tf][tr] != NOPIECE && !gs->palace) return 0; // [HGM] XQ pawns can capture straight ahead\r
+    if (gs->onMove == WHITE) {\r
+      if (tr - fr == 1) return 1;\r
+      if ((fr <= gs->pawnDblStep) && (tr - fr == 2) && gs->board[ff][fr+1]==NOPIECE) return 1;
+    } else {\r
+      if (fr - tr == 1) return 1;\r
+      if ((fr >= gs->ranks - 1 - gs->pawnDblStep) && (fr - tr == 2) && gs->board[ff][fr-1]==NOPIECE) return 1;\r
+    }\r
+    return 0;\r
+  }\r
   if (ff != tf) { /* Capture ? */
     if ((ff - tf != 1) && (tf - ff != 1)) return 0;
-    if ((fr - tr != 1) && (tr - fr != 1)) return 0;
     if (gs->onMove == WHITE) {
-      if (fr > tr) return 0;
+      if(gs->palace) return (fr >= gs->ranks/2 && fr == tr); // [HGM] XQ promoted pawns\r
+      if (tr != fr+1) return 0;
       if ((gs->board[tf][tr] != NOPIECE) && iscolor(gs->board[tf][tr],BLACK))
         return 1;
       if (gs->ep_possible[0][ff] == 1) {
@@ -150,7 +164,8 @@ static int legal_pawn_move( struct game_state_t *gs, int ff, int fr, int tf, int
         if ((tf==ff-1) && (gs->board[ff-1][fr] == B_PAWN)) return 1;
       }
     } else {
-      if (tr > fr) return 0;
+      if(gs->palace) return (fr < gs->ranks/2 && fr == tr); // [HGM] XQ promoted pawns\r
+      if (tr != fr-1) return 0;
       if ((gs->board[tf][tr] != NOPIECE) && iscolor(gs->board[tf][tr],WHITE))
         return 1;
       if (gs->ep_possible[1][ff] == 1) {
@@ -180,6 +195,36 @@ static int legal_knight_move(struct game_state_t * gs, int ff, int fr, int tf, i
   return 0;
 }
 
+static int legal_horse_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)
+{
+  int dx, dy;
+
+  dx = ff - tf;
+  dy = fr - tr;
+  if (abs(dx) == 2) {
+    if (abs(dy) == 1 && gs->board[(ff+tf)/2][fr] == NOPIECE)
+      return 1;
+  }
+  if (abs(dy) == 2) {
+    if (abs(dx) == 1 && gs->board[ff][(fr+tr)/2] == NOPIECE)
+      return 1;
+  }
+  return 0;
+}
+
+static int legal_honorablehorse_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)
+{
+  int dx, dy;
+
+  dx = ff - tf;
+  dy = fr - tr;
+  if (dy == gs->onMove == WHITE ? 2 : -2) {
+    if (abs(dx) == 1)
+      return 1;
+  }
+  return 0;
+}
+
 static int legal_bishop_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)
 {
   int dx, dy, x, y;
@@ -255,11 +300,82 @@ static int legal_rook_move(struct game_state_t * gs, int ff, int fr, int tf, int
   }
 }
 
+static int legal_cannon_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)
+{
+  int i, cnt=0;
+  int start, stop;
+
+  if (ff == tf) {
+    if (fr < tr) {
+      start = fr + 1;
+      stop = tr - 1;
+    } else {
+      start = tr + 1;
+      stop = fr - 1;
+    }
+    for (i = start; i <= stop; i++) {
+      if (gs->board[ff][i] != NOPIECE) cnt++;
+    }
+    return (cnt == 0 && gs->board[tf][tr] == NOPIECE) ||
+          (cnt == 1 && gs->board[tf][tr] != NOPIECE);
+  } else if (fr == tr) {
+    if (ff < tf) {
+      start = ff + 1;
+      stop = tf - 1;
+    } else {
+      start = tf + 1;
+      stop = ff - 1;
+    }
+    for (i = start; i <= stop; i++) {
+      if (gs->board[i][fr] != NOPIECE) cnt++;
+    }
+    return (cnt == 0 && gs->board[tf][tr] == NOPIECE) ||
+          (cnt == 1 && gs->board[tf][tr] != NOPIECE);
+  } else {
+    return 0;
+  }
+}
+
+static int legal_lance_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)
+{
+  int i;
+  int start, stop;
+
+  if (ff == tf) {
+    if (abs(fr - tr) == 1)
+      return 1;
+    if (fr < tr) {
+      if(gs->onMove != WHITE) return 0;
+      start = fr + 1;
+      stop = tr - 1;
+    } else {
+      if(gs->onMove == WHITE) return 0;
+      start = tr + 1;
+      stop = fr - 1;
+    }
+    for (i = start; i <= stop; i++) {
+      if (gs->board[ff][i] != NOPIECE)
+       return 0;
+    }
+    return 1;
+  }
+}
+
 static int legal_queen_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)
 {
   return legal_rook_move(gs, ff, fr, tf, tr) || legal_bishop_move(gs, ff, fr, tf, tr);
 }
 
+static int legal_cardinal_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)\r
+{\r
+  return legal_knight_move(gs, ff, fr, tf, tr) || legal_bishop_move(gs, ff, fr, tf, tr);\r
+}\r
+\r
+static int legal_marshall_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)\r
+{\r
+  return legal_rook_move(gs, ff, fr, tf, tr) || legal_knight_move(gs, ff, fr, tf, tr);\r
+}\r
+\r
 /* Ckeck, if square (kf,kr) is attacked by enemy piece.
  * Used in castling from/through check testing.
  */
@@ -268,9 +384,10 @@ static int legal_queen_move(struct game_state_t * gs, int ff, int fr, int tf, in
 static int is_square_attacked (struct game_state_t *gs, int kf, int kr)
 {
   struct game_state_t fakeMove;
+  int oldk = gs->onMove == WHITE ? gs->wkmoved : gs->bkmoved;
 
   fakeMove = *gs;
-  fakeMove.board[4][kr] = NOPIECE;
+  fakeMove.board[oldk][kr] = NOPIECE; // [HGM] castle: this routine is called only when King has not moved\r
   fakeMove.board[kf][kr] = KING | fakeMove.onMove;
   fakeMove.onMove = CToggle (fakeMove.onMove);
   if (in_check(&fakeMove)) return 1;
@@ -284,7 +401,7 @@ static int is_square_attacked(struct game_state_t * gs, int kf, int kr)
   gs->onMove = CToggle(gs->onMove);
 
   for (InitPieceLoop(gs->board, &f, &r, gs->onMove);
-       NextPieceLoop(gs->board, &f, &r, gs->onMove);) {
+       NextPieceLoop(gs->board, &f, &r, gs->onMove, gs->files, gs->ranks);) {
     if (legal_move(gs, f, r, kf, kr)) {
       gs->onMove = CToggle(gs->onMove);
       return 1;
@@ -295,46 +412,201 @@ static int is_square_attacked(struct game_state_t * gs, int kf, int kr)
 }
 */
 
+static int legal_man_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)\r
+{\r
+  if (abs(ff - tf) > 1)\r
+    return 0;\r
+  if (abs(fr - tr) > 1)\r
+    return 0;\r
+  return 1;\r
+}\r
+\r
+static int legal_wazir_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)\r
+{\r
+  if(gs->palace && (tr > gs->palace && tr < gs->ranks - gs->palace ||
+     tf < (gs->files - gs->palace)/2 || tf >= (gs->files + gs->palace)/2))
+    return 0;\r
+  if (abs(ff - tf) == 1 && fr == tr)\r
+    return 1;\r
+  if (abs(fr - tr) == 1 && ff == tf)\r
+    return 1;\r
+  return 0;\r
+}\r
+\r
+static int legal_dababba_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)\r
+{\r
+  if (abs(ff - tf) == 2 && fr == tr)\r
+    return 1;\r
+  if (abs(fr - tr) == 2 && ff == tf)\r
+    return 1;\r
+  return 0;\r
+}\r
+\r
+static int legal_ferz_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)\r
+{\r
+  if (abs(ff - tf) != 1)\r
+    return 0;\r
+  if (abs(fr - tr) != 1)\r
+    return 0;\r
+  return 1;\r
+}\r
+
+static int legal_mandarin_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)\r
+{\r
+  if(gs->palace && (tr > gs->palace && tr < gs->ranks - gs->palace ||
+     tf < (gs->files - gs->palace)/2 || tf >= (gs->files + gs->palace)/2))
+    return 0;\r
+  if (abs(ff - tf) != 1)\r
+    return 0;\r
+  if (abs(fr - tr) != 1)\r
+    return 0;\r
+  return 1;\r
+}\r
+\r
+static int legal_alfil_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)\r
+{
+  if (abs(ff - tf) != 2)\r
+    return 0;\r
+  if (abs(fr - tr) != 2)\r
+    return 0;\r
+  return 1;\r
+}\r
+\r
+static int legal_elephant_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)\r
+{\r
+  if (abs(ff - tf) != 2)\r
+    return 0;\r
+  if (abs(fr - tr) != 2)\r
+    return 0;
+  if(gs->board[(ff+tf)/2][(fr+tr)/2] != NOPIECE) return 0; // blocked
+  if((tr >= gs->ranks/2) != (fr >= gs->ranks/2)) return 0; // do not cross river\r
+  return 1;\r
+}\r
+\r
+static int legal_gold_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)\r
+{\r
+  return legal_wazir_move(gs, ff, fr, tf, tr) || (abs(ff-tf) == 1 && tr == fr + (gs->onMove==WHITE ? 1 : -1));\r
+}\r
+\r
+static int legal_silver_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)\r
+{\r
+  return legal_ferz_move(gs, ff, fr, tf, tr) || (tf == ff && tr == fr + (gs->onMove==WHITE ? 1 : -1) );\r
+}\r
+\r
+static int legal_woody_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)\r
+{\r
+  return legal_wazir_move(gs, ff, fr, tf, tr) || legal_dababba_move(gs, ff, fr, tf, tr);\r
+}\r
+\r
+static int legal_squirrel_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)\r
+{\r
+  return legal_alfil_move(gs, ff, fr, tf, tr) || legal_dababba_move(gs, ff, fr, tf, tr) 
+                                                       || legal_knight_move(gs, ff, fr, tf, tr);\r
+}\r
+\r
+static int legal_mastodon_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)\r
+{\r
+  return legal_man_move(gs, ff, fr, tf, tr) || legal_alfil_move(gs, ff, fr, tf, tr)
+                                                       || legal_dababba_move(gs, ff, fr, tf, tr);\r
+}\r
+\r
+static int legal_centaur_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)\r
+{\r
+  return legal_man_move(gs, ff, fr, tf, tr) || legal_knight_move(gs, ff, fr, tf, tr);\r
+}\r
+\r
+static int legal_amazon_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)\r
+{\r
+  return legal_queen_move(gs, ff, fr, tf, tr) || legal_knight_move(gs, ff, fr, tf, tr);\r
+}\r
+\r
+static int legal_dragonking_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)\r
+{\r
+  return legal_rook_move(gs, ff, fr, tf, tr) || legal_ferz_move(gs, ff, fr, tf, tr);\r
+}\r
+\r
+static int legal_dragonhorse_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)\r
+{\r
+  return legal_bishop_move(gs, ff, fr, tf, tr) || legal_wazir_move(gs, ff, fr, tf, tr);\r
+}\r
+\r
+static int legal_modernelephant_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)\r
+{\r
+  return legal_ferz_move(gs, ff, fr, tf, tr) || legal_alfil_move(gs, ff, fr, tf, tr);\r
+}\r
+\r
+static int legal_priestess_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)\r
+{\r
+  return legal_knight_move(gs, ff, fr, tf, tr) || legal_ferz_move(gs, ff, fr, tf, tr)
+                                               || legal_alfil_move(gs, ff, fr, tf, tr);\r
+}\r
+\r
+static int legal_minister_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)\r
+{\r
+  return legal_knight_move(gs, ff, fr, tf, tr) || legal_wazir_move(gs, ff, fr, tf, tr)
+                                               || legal_dababba_move(gs, ff, fr, tf, tr);\r
+}\r
+\r
 static int legal_king_move(struct game_state_t * gs, int ff, int fr, int tf, int tr)
 {
-  if (gs->onMove == WHITE) {
-    /* King side castling */
-    if ((fr == 0) && (tr == 0) && (ff == 4) && (tf == 6) && !gs->wkmoved
-       && (!gs->wkrmoved) && (gs->board[5][0] == NOPIECE) &&
-       (gs->board[6][0] == NOPIECE) && (gs->board[7][0] == W_ROOK) &&
-       (!is_square_attacked(gs, 4, 0)) && (!is_square_attacked(gs, 5, 0))) {
-      return 1;
-    }
-    /* Queen side castling */
-    if ((fr == 0) && (tr == 0) && (ff == 4) && (tf == 2) && !gs->wkmoved
-       && (!gs->wqrmoved) && (gs->board[3][0] == NOPIECE) &&
-       (gs->board[2][0] == NOPIECE) && (gs->board[1][0] == NOPIECE) &&
-       (gs->board[0][0] == W_ROOK) &&
-       (!is_square_attacked(gs, 4, 0)) && (!is_square_attacked(gs, 3, 0))) {
-      return 1;
-    }
-  } else {                     /* Black */
-    /* King side castling */
-    if ((fr == 7) && (tr == 7) && (ff == 4) && (tf == 6) && !gs->bkmoved
-       && (!gs->bkrmoved) && (gs->board[5][7] == NOPIECE) &&
-       (gs->board[6][7] == NOPIECE) && (gs->board[7][7] == B_ROOK) &&
-       (!is_square_attacked(gs, 4, 7)) && (!is_square_attacked(gs, 5, 7))) {
-      return 1;
-    }
-    /* Queen side castling */
-    if ((fr == 7) && (tr == 7) && (ff == 4) && (tf == 2) && (!gs->bkmoved)
-       && (!gs->bqrmoved) && (gs->board[3][7] == NOPIECE) &&
-       (gs->board[2][7] == NOPIECE) && (gs->board[1][7] == NOPIECE) &&
-       (gs->board[0][7] == B_ROOK) &&
-       (!is_square_attacked(gs, 4, 7)) && (!is_square_attacked(gs, 3, 7))) {
+  int result;
+
+  // [HGM] castle: test first if valid as regular King move; result = 1 or 0
+  if(gs->royalKnight)\r
+    result = legal_knight_move(gs, ff, fr, tf, tr);\r
+  else if(gs->palace) {
+    result = legal_wazir_move(gs, ff, fr, tf, tr);
+    if(!result && ff == tf && piecetype(gs->board[tf][tr]) == KING) { // XQ regicide
+      int i, d = (tr>fr ? 1 : -1);
+      for(i=fr+d; i!=tr; i+=d) 
+       if(gs->board[ff][i] != NOPIECE) return 0; // line of sight blocked
       return 1;
     }
+  } else\r
+    result = legal_man_move(gs, ff, fr, tf, tr);
+
+  if(result) return 1;\r
+  // [HGM] castle: orthodox legal castlings given as King move return 2
+
+  if (gs->onMove == WHITE) {\r
+    /* King side castling */\r
+    if ((fr == 0) && (tr == 0) && (ff == gs->files/2) && (tf == gs->files-2) && (gs->wkmoved >= 0)\r
+       && (gs->wkrmoved >= 0) && (gs->board[gs->files-3][0] == NOPIECE) &&\r
+       (gs->board[gs->files-2][0] == NOPIECE) && (gs->board[gs->files-1][0] == W_ROOK) &&\r
+       (gs->board[gs->files/2+1][0] == NOPIECE) && (!is_square_attacked(gs, gs->files/2+1, 0)) &&\r
+       (!is_square_attacked(gs, gs->files/2, 0)) && (!is_square_attacked(gs, gs->files-3, 0))) {\r
+      return 2;\r
+    }\r
+    /* Queen side castling */\r
+    if ((fr == 0) && (tr == 0) && (ff == gs->files/2) && (tf == 2) && (gs->wkmoved >= 0)\r
+       && (gs->wqrmoved >= 0) && (gs->board[3][0] == NOPIECE) &&\r
+       (gs->board[2][0] == NOPIECE) && (gs->board[1][0] == NOPIECE) &&\r
+       (gs->board[0][0] == W_ROOK) &&\r
+       (gs->board[gs->files/2-1][0] == NOPIECE) && (!is_square_attacked(gs, gs->files/2-1, 0)) &&\r
+       (!is_square_attacked(gs, gs->files/2, 0)) && (!is_square_attacked(gs, 3, 0))) {\r
+      return 2;\r
+    }\r
+  } else {                     /* Black */\r
+    /* King side castling */\r
+    if ((fr == gs->ranks-1) && (tr == gs->ranks-1) && (ff == gs->files/2) && (tf == gs->files-2) && (gs->bkmoved >= 0)\r
+       && (gs->bkrmoved >= 0) && (gs->board[gs->files-3][7] == NOPIECE) &&\r
+       (gs->board[gs->files-2][gs->ranks-1] == NOPIECE) && (gs->board[gs->files-1][gs->ranks-1] == B_ROOK) &&\r
+       (gs->board[gs->files/2+1][gs->ranks-1] == NOPIECE) && (!is_square_attacked(gs, gs->files/2+1, gs->ranks-1)) &&\r
+       (!is_square_attacked(gs, gs->files/2, gs->ranks-1)) && (!is_square_attacked(gs, gs->files-3, gs->ranks-1))) {\r
+      return 2;\r
+    }\r
+    /* Queen side castling */\r
+    if ((fr == gs->ranks-1) && (tr == gs->ranks-1) && (ff == gs->files/2) && (tf == 2) && (gs->bkmoved >= 0)\r
+       && (gs->bqrmoved >= 0) && (gs->board[3][gs->ranks-1] == NOPIECE) &&\r
+       (gs->board[2][gs->ranks-1] == NOPIECE) && (gs->board[1][gs->ranks-1] == NOPIECE) &&\r
+       (gs->board[0][gs->ranks-1] == B_ROOK) &&\r
+       (gs->board[gs->files/2-1][gs->ranks-1] == NOPIECE) && (!is_square_attacked(gs, gs->files/2-1, gs->ranks-1)) &&\r
+       (!is_square_attacked(gs, gs->files/2, gs->ranks-1)) && (!is_square_attacked(gs, 3, gs->ranks-1))) {\r
+      return 2;\r
+    }\r
   }
-  if (abs(ff - tf) > 1)
-    return 0;
-  if (abs(fr - tr) > 1)
-    return 0;
-  return 1;
+\r
+  return 0; // neither regular King move nor castling
 }
 
 static void add_pos(int tof, int tor, int *posf, int *posr, int *numpos)
@@ -348,206 +620,371 @@ static void possible_pawn_moves(struct game_state_t * gs,
                                  int onf, int onr,
                                  int *posf, int *posr, int *numpos)
 {
-  if (gs->onMove == WHITE) {
-    if (gs->board[onf][onr + 1] == NOPIECE) {
-      add_pos(onf, onr + 1, posf, posr, numpos);
-      if ((onr == 1) && (gs->board[onf][onr + 2] == NOPIECE))
-       add_pos(onf, onr + 2, posf, posr, numpos);
-    }
-    if ((onf > 0) && (gs->board[onf - 1][onr + 1] != NOPIECE) &&
-       (iscolor(gs->board[onf - 1][onr + 1], BLACK)))
-      add_pos(onf - 1, onr + 1, posf, posr, numpos);
-    if ((onf < 7) && (gs->board[onf + 1][onr + 1] != NOPIECE) &&
-       (iscolor(gs->board[onf + 1][onr + 1], BLACK)))
+  if (gs->onMove == WHITE) {\r
+    if (gs->board[onf][onr + 1] == NOPIECE || gs->palace) {\r
+      add_pos(onf, onr + 1, posf, posr, numpos);\r
+      if ((onr <= gs->pawnDblStep) && (gs->board[onf][onr + 2] == NOPIECE))\r
+       add_pos(onf, onr + 2, posf, posr, numpos);\r
+    }\r
+    if (onf > 0) {
+      if (gs->board[onf - 1][onr + 1] != NOPIECE &&\r
+         iscolor(gs->board[onf - 1][onr + 1], BLACK))\r
+        add_pos(onf - 1, onr + 1, posf, posr, numpos);
+      if(gs->palace && onr >= gs->ranks/2 && (gs->board[onf-1][onr] || iscolor(gs->board[onf-1][onr], BLACK)))
+        add_pos(onf - 1, onr, posf, posr, numpos); // XQ promoted pawn
+    }\r
+    if (onf < gs->files-1) {
+      if (gs->board[onf + 1][onr + 1] != NOPIECE &&\r
+         iscolor(gs->board[onf + 1][onr + 1], BLACK))\r
+       add_pos(onf + 1, onr + 1, posf, posr, numpos);
+      if(gs->palace && onr >= gs->ranks/2 && (gs->board[onf+1][onr] || iscolor(gs->board[onf+1][onr], BLACK)))
+        add_pos(onf + 1, onr, posf, posr, numpos); // XQ promoted pawn
+    }\r
+    if (gs->ep_possible[0][onf] == -1)\r
+      add_pos(onf - 1, onr + 1, posf, posr, numpos);\r
+    if (gs->ep_possible[0][onf] == 1)\r
       add_pos(onf + 1, onr + 1, posf, posr, numpos);
-    if (gs->ep_possible[0][onf] == -1)
-      add_pos(onf - 1, onr + 1, posf, posr, numpos);
-    if (gs->ep_possible[0][onf] == 1)
-      add_pos(onf + 1, onr + 1, posf, posr, numpos);
-  } else {
-    if (gs->board[onf][onr - 1] == NOPIECE) {
-      add_pos(onf, onr - 1, posf, posr, numpos);
-      if ((onr == 6) && (gs->board[onf][onr - 2] == NOPIECE))
-       add_pos(onf, onr - 2, posf, posr, numpos);
-    }
-    if ((onf > 0) && (gs->board[onf - 1][onr - 1] != NOPIECE) &&
-       (iscolor(gs->board[onf - 1][onr - 1], WHITE)))
-      add_pos(onf - 1, onr - 1, posf, posr, numpos);
-/* loon: changed what looks like a typo, here's the original line:
-      add_pos(onf - 1, onr + 1, posf, posr, numpos);
-*/
-    if ((onf < 7) && (gs->board[onf + 1][onr - 1] != NOPIECE) &&
-       (iscolor(gs->board[onf + 1][onr - 1], WHITE)))
-      add_pos(onf + 1, onr - 1, posf, posr, numpos);
-    if (gs->ep_possible[1][onf] == -1)
-      add_pos(onf - 1, onr - 1, posf, posr, numpos);
-    if (gs->ep_possible[1][onf] == 1)
-      add_pos(onf + 1, onr - 1, posf, posr, numpos);
-  }
+  } else {\r
+    if (gs->board[onf][onr - 1] == NOPIECE || gs->palace) {\r
+      add_pos(onf, onr - 1, posf, posr, numpos);\r
+      if ((onr >= gs->ranks - gs->pawnDblStep - 1) && (gs->board[onf][onr - 2] == NOPIECE))\r
+       add_pos(onf, onr - 2, posf, posr, numpos);\r
+    }\r
+    if (onf > 0) {
+      if (gs->board[onf - 1][onr - 1] != NOPIECE &&\r
+         iscolor(gs->board[onf - 1][onr - 1], WHITE))\r
+       add_pos(onf - 1, onr - 1, posf, posr, numpos);
+      if(gs->palace && onr < gs->ranks/2 && !iscolor(gs->board[onf-1][onr], BLACK))
+        add_pos(onf - 1, onr, posf, posr, numpos); // XQ promoted pawn
+    }\r
+    if (onf < gs->files-1) {
+      if (gs->board[onf + 1][onr - 1] != NOPIECE &&\r
+         iscolor(gs->board[onf + 1][onr - 1], WHITE))\r
+       add_pos(onf + 1, onr - 1, posf, posr, numpos);
+      if(gs->palace && onr < gs->ranks/2 && !iscolor(gs->board[onf+1][onr], BLACK))
+        add_pos(onf + 1, onr, posf, posr, numpos); // XQ promoted pawn
+    }\r
+    if (gs->ep_possible[1][onf] == -1)\r
+      add_pos(onf - 1, onr - 1, posf, posr, numpos);\r
+    if (gs->ep_possible[1][onf] == 1)\r
+      add_pos(onf + 1, onr - 1, posf, posr, numpos);\r
+  }\r
 }
 
 static void possible_knight_moves(struct game_state_t * gs,
                                    int onf, int onr,
                                    int *posf, int *posr, int *numpos)
 {
-  static int knightJumps[8][2] = {{-1, 2}, {1, 2}, {2, -1}, {2, 1},
-  {-1, -2}, {1, -2}, {-2, 1}, {-2, -1}};
-  int f, r;
-  int j;
+  static int knightJumps[8][2] = {{-1, 2}, {1, 2}, {2, -1}, {2, 1},\r
+  {-1, -2}, {1, -2}, {-2, 1}, {-2, -1}};\r
+  int f, r;\r
+  int j;\r
+\r
+  for (j = 0; j < 8; j++) {\r
+    f = knightJumps[j][0] + onf;\r
+    r = knightJumps[j][1] + onr;\r
+    if ((f < 0) || (f >= gs->files))\r
+      continue;\r
+    if ((r < 0) || (r >= gs->ranks))\r
+      continue;\r
+    if ((gs->board[f][r] == NOPIECE) ||\r
+       (iscolor(gs->board[f][r], CToggle(gs->onMove))))\r
+      add_pos(f, r, posf, posr, numpos);\r
+  }\r
+}
 
-  for (j = 0; j < 8; j++) {
-    f = knightJumps[j][0] + onf;
-    r = knightJumps[j][1] + onr;
-    if ((f < 0) || (f > 7))
-      continue;
-    if ((r < 0) || (r > 7))
-      continue;
-    if ((gs->board[f][r] == NOPIECE) ||
-       (iscolor(gs->board[f][r], CToggle(gs->onMove))))
-      add_pos(f, r, posf, posr, numpos);
-  }
+static void possible_horse_moves(struct game_state_t * gs,
+                                   int onf, int onr,
+                                   int *posf, int *posr, int *numpos)
+{
+  static int knightJumps[8][4] = {{-1, 2, 0, 1}, {1, 2, 0, 1}, {2, -1, 1, 0}, {2, 1, 1, 0},\r
+  {-1, -2, 0, -1}, {1, -2, 0, -1}, {-2, 1, -1, 0}, {-2, -1, -1, 0}};\r
+  int f, r;\r
+  int j;\r
+\r
+  for (j = 0; j < 8; j++) {\r
+    f = knightJumps[j][0] + onf;\r
+    r = knightJumps[j][1] + onr;\r
+    if ((f < 0) || (f >= gs->files))\r
+      continue;\r
+    if ((r < 0) || (r >= gs->ranks))\r
+      continue;\r
+    if ((gs->board[knightJumps[j][2] + onf][knightJumps[j][3] + onr] == NOPIECE) && 
+       ((gs->board[f][r] == NOPIECE) || (iscolor(gs->board[f][r], CToggle(gs->onMove)))))\r
+      add_pos(f, r, posf, posr, numpos);\r
+  }\r
 }
 
 static void possible_bishop_moves(struct game_state_t * gs,
                                    int onf, int onr,
                                    int *posf, int *posr, int *numpos)
 {
-  int f, r;
-
-  /* Up Left */
-  f = onf;
-  r = onr;
-  for (;;) {
-    f--;
-    r++;
-    if ((f < 0) || (f > 7))
-      break;
-    if ((r < 0) || (r > 7))
-      break;
-    if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove)))
-      break;
-    add_pos(f, r, posf, posr, numpos);
-    if (gs->board[f][r] != NOPIECE)
-      break;
-  }
-  /* Up Right */
-  f = onf;
-  r = onr;
-  for (;;) {
-    f++;
-    r++;
-    if ((f < 0) || (f > 7))
-      break;
-    if ((r < 0) || (r > 7))
-      break;
-    if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove)))
-      break;
-    add_pos(f, r, posf, posr, numpos);
-    if (gs->board[f][r] != NOPIECE)
-      break;
-  }
-  /* Down Left */
-  f = onf;
-  r = onr;
-  for (;;) {
-    f--;
-    r--;
-    if ((f < 0) || (f > 7))
-      break;
-    if ((r < 0) || (r > 7))
-      break;
-    if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove)))
-      break;
-    add_pos(f, r, posf, posr, numpos);
-    if (gs->board[f][r] != NOPIECE)
-      break;
-  }
-  /* Down Right */
-  f = onf;
-  r = onr;
-  for (;;) {
-    f++;
-    r--;
-    if ((f < 0) || (f > 7))
-      break;
-    if ((r < 0) || (r > 7))
-      break;
-    if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove)))
-      break;
-    add_pos(f, r, posf, posr, numpos);
-    if (gs->board[f][r] != NOPIECE)
-      break;
-  }
+  int f, r;\r
+\r
+  /* Up Left */\r
+  f = onf;\r
+  r = onr;\r
+  for (;;) {\r
+    f--;\r
+    r++;\r
+    if ((f < 0) || (f >= gs->files))\r
+      break;\r
+    if ((r < 0) || (r >= gs->ranks))\r
+      break;\r
+    if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove)))\r
+      break;\r
+    add_pos(f, r, posf, posr, numpos);\r
+    if (gs->board[f][r] != NOPIECE)\r
+      break;\r
+  }\r
+  /* Up Right */\r
+  f = onf;\r
+  r = onr;\r
+  for (;;) {\r
+    f++;\r
+    r++;\r
+    if ((f < 0) || (f >= gs->files))\r
+      break;\r
+    if ((r < 0) || (r >= gs->ranks))\r
+      break;\r
+    if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove)))\r
+      break;\r
+    add_pos(f, r, posf, posr, numpos);\r
+    if (gs->board[f][r] != NOPIECE)\r
+      break;\r
+  }\r
+  /* Down Left */\r
+  f = onf;\r
+  r = onr;\r
+  for (;;) {\r
+    f--;\r
+    r--;\r
+    if ((f < 0) || (f >= gs->files))\r
+      break;\r
+    if ((r < 0) || (r >= gs->ranks))\r
+      break;\r
+    if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove)))\r
+      break;\r
+    add_pos(f, r, posf, posr, numpos);\r
+    if (gs->board[f][r] != NOPIECE)\r
+      break;\r
+  }\r
+  /* Down Right */\r
+  f = onf;\r
+  r = onr;\r
+  for (;;) {\r
+    f++;\r
+    r--;\r
+    if ((f < 0) || (f >= gs->files))\r
+      break;\r
+    if ((r < 0) || (r >= gs->ranks))\r
+      break;\r
+    if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove)))\r
+      break;\r
+    add_pos(f, r, posf, posr, numpos);\r
+    if (gs->board[f][r] != NOPIECE)\r
+      break;\r
+  }\r
 }
 
 static void possible_rook_moves(struct game_state_t * gs,
                                  int onf, int onr,
                                  int *posf, int *posr, int *numpos)
 {
-  int f, r;
+  int f, r;\r
+\r
+  /* Left */\r
+  f = onf;\r
+  r = onr;\r
+  for (;;) {\r
+    f--;\r
+    if ((f < 0) || (f >= gs->files))\r
+      break;\r
+    if ((r < 0) || (r >= gs->ranks))\r
+      break;\r
+    if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove)))\r
+      break;\r
+    add_pos(f, r, posf, posr, numpos);\r
+    if (gs->board[f][r] != NOPIECE)\r
+      break;\r
+  }\r
+  /* Right */\r
+  f = onf;\r
+  r = onr;\r
+  for (;;) {\r
+    f++;\r
+    if ((f < 0) || (f >= gs->files))\r
+      break;\r
+    if ((r < 0) || (r >= gs->ranks))\r
+      break;\r
+    if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove)))\r
+      break;\r
+    add_pos(f, r, posf, posr, numpos);\r
+    if (gs->board[f][r] != NOPIECE)\r
+      break;\r
+  }\r
+  /* Up */\r
+  f = onf;\r
+  r = onr;\r
+  for (;;) {\r
+    r++;\r
+    if ((f < 0) || (f >= gs->files))\r
+      break;\r
+    if ((r < 0) || (r >= gs->ranks))\r
+      break;\r
+    if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove)))\r
+      break;\r
+    add_pos(f, r, posf, posr, numpos);\r
+    if (gs->board[f][r] != NOPIECE)\r
+      break;\r
+  }\r
+  /* Down */\r
+  f = onf;\r
+  r = onr;\r
+  for (;;) {\r
+    r--;\r
+    if ((f < 0) || (f >= gs->files))\r
+      break;\r
+    if ((r < 0) || (r >= gs->ranks))\r
+      break;\r
+    if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove)))\r
+      break;\r
+    add_pos(f, r, posf, posr, numpos);\r
+    if (gs->board[f][r] != NOPIECE)\r
+      break;\r
+  }\r
+}
 
-  /* Left */
-  f = onf;
-  r = onr;
-  for (;;) {
-    f--;
-    if ((f < 0) || (f > 7))
-      break;
-    if ((r < 0) || (r > 7))
-      break;
-    if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove)))
-      break;
-    add_pos(f, r, posf, posr, numpos);
-    if (gs->board[f][r] != NOPIECE)
-      break;
-  }
-  /* Right */
-  f = onf;
-  r = onr;
-  for (;;) {
-    f++;
-    if ((f < 0) || (f > 7))
-      break;
-    if ((r < 0) || (r > 7))
-      break;
-    if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove)))
-      break;
-    add_pos(f, r, posf, posr, numpos);
-    if (gs->board[f][r] != NOPIECE)
-      break;
-  }
-  /* Up */
-  f = onf;
-  r = onr;
-  for (;;) {
-    r++;
-    if ((f < 0) || (f > 7))
-      break;
-    if ((r < 0) || (r > 7))
-      break;
-    if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove)))
-      break;
-    add_pos(f, r, posf, posr, numpos);
-    if (gs->board[f][r] != NOPIECE)
-      break;
-  }
-  /* Down */
-  f = onf;
-  r = onr;
-  for (;;) {
-    r--;
-    if ((f < 0) || (f > 7))
-      break;
-    if ((r < 0) || (r > 7))
-      break;
-    if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove)))
-      break;
-    add_pos(f, r, posf, posr, numpos);
-    if (gs->board[f][r] != NOPIECE)
-      break;
-  }
+static void possible_cannon_moves(struct game_state_t * gs,
+                                 int onf, int onr,
+                                 int *posf, int *posr, int *numpos)
+{
+  int f, r, i;\r
+\r
+  /* Left */\r
+  f = onf;\r
+  r = onr;\r
+  for (i=0;;) {\r
+    f--;\r
+    if ((f < 0) || (f >= gs->files))\r
+      break;\r
+    if ((r < 0) || (r >= gs->ranks))\r
+      break;\r
+    if ((gs->board[f][r] != NOPIECE) && i++ == 0) continue;
+    if(i == 0)
+       add_pos(f, r, posf, posr, numpos); // no hop: non-capt
+    else if(i == 2 && !iscolor(gs->board[f][r], gs->onMove)) 
+       add_pos(f, r, posf, posr, numpos); // hop: capt\r
+    if (gs->board[f][r] != NOPIECE)\r
+      break;\r
+  }\r
+  /* Right */\r
+  f = onf;\r
+  r = onr;\r
+  for (i=0;;) {\r
+    f++;\r
+    if ((f < 0) || (f >= gs->files))\r
+      break;\r
+    if ((r < 0) || (r >= gs->ranks))\r
+      break;\r
+    if ((gs->board[f][r] != NOPIECE) && i++ == 0) continue;
+    if(i == 0)
+       add_pos(f, r, posf, posr, numpos); // no hop: non-capt
+    else if(i == 2 && !iscolor(gs->board[f][r], gs->onMove)) 
+       add_pos(f, r, posf, posr, numpos); // hop: capt\r
+    if (gs->board[f][r] != NOPIECE)\r
+      break;\r
+  }\r
+  /* Up */\r
+  f = onf;\r
+  r = onr;\r
+  for (i=0;;) {\r
+    r++;\r
+    if ((f < 0) || (f >= gs->files))\r
+      break;\r
+    if ((r < 0) || (r >= gs->ranks))\r
+      break;\r
+    if ((gs->board[f][r] != NOPIECE) && i++ == 0) continue;
+    if(i == 0)
+       add_pos(f, r, posf, posr, numpos); // no hop: non-capt
+    else if(i == 2 && !iscolor(gs->board[f][r], gs->onMove)) 
+       add_pos(f, r, posf, posr, numpos); // hop: capt\r
+    if (gs->board[f][r] != NOPIECE)\r
+      break;\r
+  }\r
+  /* Down */\r
+  f = onf;\r
+  r = onr;\r
+  for (i=0;;) {\r
+    r--;\r
+    if ((f < 0) || (f >= gs->files))\r
+      break;\r
+    if ((r < 0) || (r >= gs->ranks))\r
+      break;\r
+    if ((gs->board[f][r] != NOPIECE) && i++ == 0) continue;
+    if(i == 0)
+       add_pos(f, r, posf, posr, numpos); // no hop: non-capt
+    else if(i == 2 && !iscolor(gs->board[f][r], gs->onMove)) 
+       add_pos(f, r, posf, posr, numpos); // hop: capt\r
+    if (gs->board[f][r] != NOPIECE)\r
+      break;\r
+  }\r
 }
 
+static void possible_lance_moves(struct game_state_t * gs,
+                                 int onf, int onr,
+                                 int *posf, int *posr, int *numpos)
+{
+  int f, r;\r
+\r
+  /* Up */\r
+  f = onf;\r
+  r = onr;\r
+  for (;gs->onMove == WHITE;) {\r
+    r++;\r
+    if ((f < 0) || (f >= gs->files))\r
+      break;\r
+    if ((r < 0) || (r >= gs->ranks))\r
+      break;\r
+    if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove)))\r
+      break;\r
+    add_pos(f, r, posf, posr, numpos);\r
+    if (gs->board[f][r] != NOPIECE)\r
+      break;\r
+  }\r
+  /* Down */\r
+  f = onf;\r
+  r = onr;\r
+  for (;gs->onMove == BLACK;) {\r
+    r--;\r
+    if ((f < 0) || (f >= gs->files))\r
+      break;\r
+    if ((r < 0) || (r >= gs->ranks))\r
+      break;\r
+    if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove)))\r
+      break;\r
+    add_pos(f, r, posf, posr, numpos);\r
+    if (gs->board[f][r] != NOPIECE)\r
+      break;\r
+  }\r
+}
+
+static void possible_cardinal_moves(struct game_state_t * gs,\r
+                                  int onf, int onr,\r
+                                  int *posf, int *posr, int *numpos)\r
+{\r
+  possible_knight_moves(gs, onf, onr, posf, posr, numpos);\r
+  possible_bishop_moves(gs, onf, onr, posf, posr, numpos);\r
+}\r
+\r
+static void possible_marshall_moves(struct game_state_t * gs,\r
+                                  int onf, int onr,\r
+                                  int *posf, int *posr, int *numpos)\r
+{\r
+  possible_rook_moves(gs, onf, onr, posf, posr, numpos);\r
+  possible_knight_moves(gs, onf, onr, posf, posr, numpos);\r
+}\r
+\r
 static void possible_queen_moves(struct game_state_t * gs,
                                   int onf, int onr,
                                   int *posf, int *posr, int *numpos)
@@ -556,28 +993,295 @@ static void possible_queen_moves(struct game_state_t * gs,
   possible_bishop_moves(gs, onf, onr, posf, posr, numpos);
 }
 
+static void possible_alfil_moves(struct game_state_t * gs,\r
+                                 int onf, int onr,\r
+                                 int *posf, int *posr, int *numpos)\r
+{\r
+  static int kingJumps[4][2] = {{-1, -1}, {1, -1}, {-1, 1}, {1, 1}};\r
+  int f, r;\r
+  int j;\r
+\r
+  for (j = 0; j < 4; j++) {\r
+    f = 2*kingJumps[j][0] + onf;\r
+    r = 2*kingJumps[j][1] + onr;\r
+    if ((f < 0) || (f >= gs->files))\r
+      continue;\r
+    if ((r < 0) || (r >= gs->ranks))\r
+      continue;\r
+    if ((gs->board[f][r] == NOPIECE) ||\r
+       (iscolor(gs->board[f][r], CToggle(gs->onMove))))\r
+      add_pos(f, r, posf, posr, numpos);\r
+  }\r
+}\r
+\r
+static void possible_ferz_moves(struct game_state_t * gs,\r
+                                 int onf, int onr,\r
+                                 int *posf, int *posr, int *numpos)\r
+{\r
+  static int kingJumps[4][2] = {{-1, -1}, {1, -1}, {-1, 1}, {1, 1}};\r
+  int f, r;\r
+  int j;\r
+\r
+  for (j = 0; j < 4; j++) {\r
+    f = kingJumps[j][0] + onf;\r
+    r = kingJumps[j][1] + onr;\r
+    if ((f < 0) || (f >= gs->files))\r
+      continue;\r
+    if ((r < 0) || (r >= gs->ranks))\r
+      continue;
+    if ((gs->board[f][r] == NOPIECE) ||\r
+       (iscolor(gs->board[f][r], CToggle(gs->onMove))))\r
+      add_pos(f, r, posf, posr, numpos);\r
+  }\r
+}\r
+\r
+static void possible_mandarin_moves(struct game_state_t * gs,\r
+                                 int onf, int onr,\r
+                                 int *posf, int *posr, int *numpos)\r
+{\r
+  static int kingJumps[4][2] = {{-1, -1}, {1, -1}, {-1, 1}, {1, 1}};\r
+  int f, r;\r
+  int j;\r
+\r
+  for (j = 0; j < 4; j++) {\r
+    f = kingJumps[j][0] + onf;\r
+    r = kingJumps[j][1] + onr;\r
+    if ((f < 0) || (f >= gs->files))\r
+      continue;\r
+    if ((r < 0) || (r >= gs->ranks))\r
+      continue;
+    if(gs->palace && (r >= gs->palace && r < gs->ranks - gs->palace ||
+       f < (gs->files - gs->palace)/2 || f >= (gs->files + gs->palace)/2))
+      continue;\r
+    if ((gs->board[f][r] == NOPIECE) ||\r
+       (iscolor(gs->board[f][r], CToggle(gs->onMove))))\r
+      add_pos(f, r, posf, posr, numpos);\r
+  }\r
+}\r
+\r
+static void possible_wazir_moves(struct game_state_t * gs,\r
+                                 int onf, int onr,\r
+                                 int *posf, int *posr, int *numpos)\r
+{\r
+  static int kingJumps[4][2] = {{0, -1}, {0, 1}, {-1, 0}, {1, 0}};\r
+  int f, r;\r
+  int j;\r
+\r
+  for (j = 0; j < 4; j++) {\r
+    f = kingJumps[j][0] + onf;\r
+    r = kingJumps[j][1] + onr;\r
+    if ((f < 0) || (f >= gs->files))\r
+      continue;\r
+    if ((r < 0) || (r >= gs->ranks))\r
+      continue;\r
+    if(gs->palace && (r >= gs->palace && r < gs->ranks - gs->palace ||
+       f < (gs->files - gs->palace)/2 || f >= (gs->files + gs->palace)/2))
+      continue;\r
+    if ((gs->board[f][r] == NOPIECE) ||\r
+       (iscolor(gs->board[f][r], CToggle(gs->onMove))))\r
+      add_pos(f, r, posf, posr, numpos);\r
+  }\r
+}\r
+\r
+static void possible_dababba_moves(struct game_state_t * gs,\r
+                                 int onf, int onr,\r
+                                 int *posf, int *posr, int *numpos)\r
+{\r
+  static int kingJumps[4][2] = {{0, -1}, {0, 1}, {-1, 0}, {1, 0}};\r
+  int f, r;\r
+  int j;\r
+\r
+  for (j = 0; j < 4; j++) {\r
+    f = 2*kingJumps[j][0] + onf;\r
+    r = 2*kingJumps[j][1] + onr;\r
+    if ((f < 0) || (f >= gs->files))\r
+      continue;\r
+    if ((r < 0) || (r >= gs->ranks))\r
+      continue;\r
+    if ((gs->board[f][r] == NOPIECE) ||\r
+       (iscolor(gs->board[f][r], CToggle(gs->onMove))))\r
+      add_pos(f, r, posf, posr, numpos);\r
+  }\r
+}\r
+\r
+static void possible_man_moves(struct game_state_t * gs,\r
+                                  int onf, int onr,
+                                  int *posf, int *posr, int *numpos)
+{
+  possible_wazir_moves(gs, onf, onr, posf, posr, numpos);
+  possible_ferz_moves(gs, onf, onr, posf, posr, numpos);
+}
+
+static void possible_dragonking_moves(struct game_state_t * gs,\r
+                                  int onf, int onr,
+                                  int *posf, int *posr, int *numpos)
+{
+  possible_rook_moves(gs, onf, onr, posf, posr, numpos);
+  possible_ferz_moves(gs, onf, onr, posf, posr, numpos);
+}
+
+static void possible_dragonhorse_moves(struct game_state_t * gs,\r
+                                  int onf, int onr,
+                                  int *posf, int *posr, int *numpos)
+{
+  possible_wazir_moves(gs, onf, onr, posf, posr, numpos);
+  possible_bishop_moves(gs, onf, onr, posf, posr, numpos);
+}
+
+static void possible_centaur_moves(struct game_state_t * gs,\r
+                                  int onf, int onr,
+                                  int *posf, int *posr, int *numpos)
+{
+  possible_man_moves(gs, onf, onr, posf, posr, numpos);
+  possible_knight_moves(gs, onf, onr, posf, posr, numpos);
+}
+
+static void possible_woody_moves(struct game_state_t * gs,\r
+                                  int onf, int onr,
+                                  int *posf, int *posr, int *numpos)
+{
+  possible_wazir_moves(gs, onf, onr, posf, posr, numpos);
+  possible_dababba_moves(gs, onf, onr, posf, posr, numpos);
+}
+
+static void possible_squirrel_moves(struct game_state_t * gs,\r
+                                  int onf, int onr,
+                                  int *posf, int *posr, int *numpos)
+{
+  possible_alfil_moves(gs, onf, onr, posf, posr, numpos);
+  possible_dababba_moves(gs, onf, onr, posf, posr, numpos);
+  possible_knight_moves(gs, onf, onr, posf, posr, numpos);
+}
+
+static void possible_mastodon_moves(struct game_state_t * gs,\r
+                                  int onf, int onr,
+                                  int *posf, int *posr, int *numpos)
+{
+  possible_man_moves(gs, onf, onr, posf, posr, numpos);
+  possible_alfil_moves(gs, onf, onr, posf, posr, numpos);
+  possible_dababba_moves(gs, onf, onr, posf, posr, numpos);
+}
+
+static void possible_amazon_moves(struct game_state_t * gs,\r
+                                  int onf, int onr,
+                                  int *posf, int *posr, int *numpos)
+{
+  possible_queen_moves(gs, onf, onr, posf, posr, numpos);
+  possible_knight_moves(gs, onf, onr, posf, posr, numpos);
+}
+
+static void possible_modernelephant_moves(struct game_state_t * gs,\r
+                                  int onf, int onr,
+                                  int *posf, int *posr, int *numpos)
+{
+  possible_ferz_moves(gs, onf, onr, posf, posr, numpos);
+  possible_alfil_moves(gs, onf, onr, posf, posr, numpos);
+}
+
+static void possible_priestess_moves(struct game_state_t * gs,\r
+                                  int onf, int onr,
+                                  int *posf, int *posr, int *numpos)
+{
+  possible_ferz_moves(gs, onf, onr, posf, posr, numpos);
+  possible_alfil_moves(gs, onf, onr, posf, posr, numpos);
+  possible_knight_moves(gs, onf, onr, posf, posr, numpos);
+}
+
+static void possible_minister_moves(struct game_state_t * gs,\r
+                                  int onf, int onr,
+                                  int *posf, int *posr, int *numpos)
+{
+  possible_wazir_moves(gs, onf, onr, posf, posr, numpos);
+  possible_dababba_moves(gs, onf, onr, posf, posr, numpos);
+  possible_knight_moves(gs, onf, onr, posf, posr, numpos);
+}
+
+static void possible_gold_moves(struct game_state_t * gs,\r
+                                  int onf, int onr,
+                                  int *posf, int *posr, int *numpos)
+{
+  possible_wazir_moves(gs, onf, onr, posf, posr, numpos);
+  if(gs->onMove == WHITE) {
+    if(onr < gs->ranks-1)
+      if(onf > 0 && !iscolor(gs->board[onf-1][onr+1], WHITE))
+       add_pos(onf-1, onr+1, posf, posr, numpos);\r
+      if(onf < gs->files-1 && !iscolor(gs->board[onf+1][onr+1], WHITE))
+       add_pos(onf+1, onr+1, posf, posr, numpos);\r
+  } else {
+    if(onr > 0)
+      if(onf > 0 && !iscolor(gs->board[onf-1][onr-1], BLACK))
+       add_pos(onf-1, onr-1, posf, posr, numpos);\r
+      if(onf < gs->files-1 && !iscolor(gs->board[onf+1][onr-1], BLACK))
+       add_pos(onf+1, onr-1, posf, posr, numpos);\r
+  }
+}
+
+static void possible_silver_moves(struct game_state_t * gs,\r
+                                  int onf, int onr,
+                                  int *posf, int *posr, int *numpos)
+{
+  possible_ferz_moves(gs, onf, onr, posf, posr, numpos);
+  if(gs->onMove == WHITE) {
+    if(onr < gs->ranks-1 && !iscolor(gs->board[onf][onr+1], WHITE))
+      add_pos(onf, onr+1, posf, posr, numpos);\r
+  } else {
+    if(onr > 0 && !iscolor(gs->board[onf][onr-1], BLACK))
+      add_pos(onf, onr-1, posf, posr, numpos);\r
+  }
+}
+
+static void possible_honorablehorse_moves(struct game_state_t * gs,\r
+                                 int onf, int onr,\r
+                                 int *posf, int *posr, int *numpos)\r
+{\r
+  int f, r = onr + (gs->onMove == WHITE ? 2 : -2);\r
+
+  if(r < 0 || r >= gs->ranks) return;\r
+  if(onf > 0) {
+    if ((gs->board[onf-1][r] == NOPIECE) ||\r
+       (iscolor(gs->board[onf-1][r], CToggle(gs->onMove))))\r
+      add_pos(onf - 1, r, posf, posr, numpos);\r
+  }\r
+  if(onf < gs->files - 1) {
+    if ((gs->board[onf+1][r] == NOPIECE) ||\r
+       (iscolor(gs->board[onf+1][r], CToggle(gs->onMove))))\r
+      add_pos(onf + 1, r, posf, posr, numpos);\r
+  }\r
+}\r
+\r
 static void possible_king_moves(struct game_state_t * gs,
                                  int onf, int onr,
                                  int *posf, int *posr, int *numpos)
 {
-  static int kingJumps[8][2] = {{-1, -1}, {0, -1}, {1, -1}, {-1, 1},
-  {0, 1}, {1, 1}, {-1, 0}, {1, 0}};
-  int f, r;
-  int j;
-
-  for (j = 0; j < 8; j++) {
-    f = kingJumps[j][0] + onf;
-    r = kingJumps[j][1] + onr;
-    if ((f < 0) || (f > 7))
-      continue;
-    if ((r < 0) || (r > 7))
-      continue;
-    if ((gs->board[f][r] == NOPIECE) ||
-       (iscolor(gs->board[f][r], CToggle(gs->onMove))))
-      add_pos(f, r, posf, posr, numpos);
-  }
+  if(gs->royalKnight)\r
+    possible_knight_moves(gs, onf, onr, posf, posr, numpos);\r
+  else if(gs->palace)
+    possible_wazir_moves(gs, onf, onr, posf, posr, numpos);
+  else\r
+    possible_man_moves(gs, onf, onr, posf, posr, numpos);\r
 }
 
+static void possible_elephant_moves(struct game_state_t * gs,
+                                  int onf, int onr,
+                                  int *posf, int *posr, int *numpos)
+{\r
+  static int kingJumps[4][2] = {{-1, -1}, {1, -1}, {-1, 1}, {1, 1}};\r
+  int f, r;\r
+  int j;\r
+\r
+  for (j = 0; j < 4; j++) {\r
+    f = 2*kingJumps[j][0] + onf;\r
+    r = 2*kingJumps[j][1] + onr;\r
+    if ((f < 0) || (f >= gs->files))\r
+      continue;\r
+    if ((r < 0) || (r >= gs->ranks))\r
+      continue;\r
+    if ((gs->board[(f+onf)/2][(r+onr)/2] == NOPIECE) && ((gs->board[f][r] == NOPIECE) ||\r
+       (iscolor(gs->board[f][r], CToggle(gs->onMove)))))\r
+      add_pos(f, r, posf, posr, numpos);\r
+  }\r
+}\r
+
 /* Doesn't check for check */
 int legal_move(struct game_state_t * gs,
               int fFile, int fRank,
@@ -588,15 +1292,57 @@ int legal_move(struct game_state_t * gs,
 
   if (fFile == ALG_DROP) {
     move_piece = fRank;
+    if(!gs->drops) return 0; // [HGM] variants: no drops in this variant
     if (move_piece == KING)
       return 0;
     if (gs->holding[gs->onMove==WHITE ? 0 : 1][move_piece-1] == 0)
       return 0;
     if (gs->board[tFile][tRank] != NOPIECE)
       return 0;
-    if (move_piece == PAWN && (tRank == 0 || tRank == 7))
+    if (move_piece == PAWN && (tRank == 0 || tRank == gs->ranks-1))
       return 0;
     return 1;
+  } else if(fFile == ALG_CASTLE) {
+       // [HGM] castle: this code can handle any type of free castling
+       // it does not check if Rook and King from squares correspond to the rights, as the
+       // user never enters such squares, but they are copied from the rights on entering o-o-o
+       int backRank, kRook, qRook, fKing, leftEmpty, rightEmpty, leftCheck, rightCheck, f;
+       if(!gs->castlingStyle) return 0;   // no castling in this variant
+       if(gs->onMove == WHITE) {
+               if(gs->wkmoved < 0) return 0; // King moved
+               fKing = gs->wkmoved;
+               backRank = 0;
+               kRook = gs->wkrmoved;
+               qRook = gs->wqrmoved;
+       } else {
+               if(gs->bkmoved < 0) return 0; // King moved
+               fKing = gs->bkmoved;
+               backRank = gs->ranks-1;
+               kRook = gs->bkrmoved;
+               qRook = gs->bqrmoved;
+       }
+       if((tRank > tFile ? qRook : kRook) < 0) return 0; // Rook moved
+       // here we verified rights do exist, so from squares (fRank and fKing) must be valid
+       if(gs->board[fRank][backRank] != (ROOK | gs->onMove) ) return 0; // only with own Rook
+       if(gs->board[fKing][backRank] != (KING | gs->onMove) ) return 0; // only with own King
+
+       // by now we know that K and R are in correct position, and still have rights
+       if(tRank > tFile) { // R ends right of K: q-side
+               leftEmpty  = fRank < tFile ? fRank+1 : tFile+1;
+               rightEmpty = tRank < fKing ? fKing-1 : tRank-1;
+       } else { // k-side
+               leftEmpty  = tRank < fKing ? tRank+1 : fKing+1;
+               rightEmpty = fRank < tFile ? fRank-1 : tFile-1;
+       }
+       for(f=leftEmpty; f<=rightEmpty; f++) // check if other pieces block castling
+               if(f != fRank && f != fKing && gs->board[f][backRank] != NOPIECE) return 0;
+
+       leftCheck  = fKing < tFile ? fKing : tFile+1;
+       rightCheck = fKing < tFile ? tFile-1 : fKing;
+       for(f=leftCheck; f<=rightCheck; f++) // check if King passes attacked square or was in check
+               if(is_square_attacked(gs, f, backRank)) return 0;
+
+       return 1; // passed all tests
   } else {
     move_piece = piecetype(gs->board[fFile][fRank]);
   }
@@ -622,9 +1368,86 @@ int legal_move(struct game_state_t * gs,
   case ROOK:
     legal = legal_rook_move(gs, fFile, fRank, tFile, tRank);
     break;
+  case CARDINAL:\r
+  case PRINCESS:\r
+    legal = legal_cardinal_move(gs, fFile, fRank, tFile, tRank);\r
+    break;\r
+  case MARSHALL:\r
+  case EMPRESS:\r
+    legal = legal_marshall_move(gs, fFile, fRank, tFile, tRank);\r
+    break;\r
+  case MAN:\r
+  case MAN2:\r
+    legal = legal_man_move(gs, fFile, fRank, tFile, tRank);\r
+    break;\r
   case QUEEN:
     legal = legal_queen_move(gs, fFile, fRank, tFile, tRank);
     break;
+  case ELEPHANT:
+    legal = legal_elephant_move(gs, fFile, fRank, tFile, tRank);
+    break;
+  case AMAZON:
+    legal = legal_amazon_move(gs, fFile, fRank, tFile, tRank);
+    break;
+  case WOODY:
+    legal = legal_woody_move(gs, fFile, fRank, tFile, tRank);
+    break;
+  case SQUIRREL:
+    legal = legal_squirrel_move(gs, fFile, fRank, tFile, tRank);
+    break;
+  case MASTODON:
+    legal = legal_mastodon_move(gs, fFile, fRank, tFile, tRank);
+    break;
+  case CENTAUR:
+    legal = legal_centaur_move(gs, fFile, fRank, tFile, tRank);
+    break;
+  case HORSE:
+    legal = legal_horse_move(gs, fFile, fRank, tFile, tRank);
+    break;
+  case FERZ:
+  case FERZ2:
+    legal = legal_ferz_move(gs, fFile, fRank, tFile, tRank);
+    break;
+  case MANDARIN:
+    legal = legal_mandarin_move(gs, fFile, fRank, tFile, tRank);
+    break;
+  case WAZIR:
+    legal = legal_wazir_move(gs, fFile, fRank, tFile, tRank);
+    break;
+  case ALFIL:
+  case ALFIL2:
+    legal = legal_alfil_move(gs, fFile, fRank, tFile, tRank);
+    break;
+  case MODERNELEPHANT:
+    legal = legal_modernelephant_move(gs, fFile, fRank, tFile, tRank);
+    break;
+  case PRIESTESS:
+    legal = legal_priestess_move(gs, fFile, fRank, tFile, tRank);
+    break;
+  case MINISTER:
+    legal = legal_minister_move(gs, fFile, fRank, tFile, tRank);
+    break;
+  case SILVER:
+    legal = legal_silver_move(gs, fFile, fRank, tFile, tRank);
+    break;
+  case GOLD:
+    legal = legal_gold_move(gs, fFile, fRank, tFile, tRank);
+    break;
+  case LANCE:
+    legal = legal_lance_move(gs, fFile, fRank, tFile, tRank);
+    break;
+  case CANNON:
+    legal = legal_cannon_move(gs, fFile, fRank, tFile, tRank);
+    break;
+  case DRAGONHORSE:
+    legal = legal_dragonhorse_move(gs, fFile, fRank, tFile, tRank);
+    break;
+  case DRAGONKING:
+    legal = legal_dragonking_move(gs, fFile, fRank, tFile, tRank);
+    break;
+  case HONORABLEHORSE:
+    legal = legal_honorablehorse_move(gs, fFile, fRank, tFile, tRank);
+    break;
   case KING:
     legal = legal_king_move(gs, fFile, fRank, tFile, tRank);
     break;
@@ -641,57 +1464,69 @@ int legal_move(struct game_state_t * gs,
  * the move is legal. Returns MOVE_ILLEGAL if move leaves you in check */
 static int move_calculate(struct game_state_t * gs, struct move_t * mt, int promote)
 {
-  struct game_state_t fakeMove;
-
-  mt->pieceCaptured = gs->board[mt->toFile][mt->toRank];
-  mt->enPassant = 0;           /* Don't know yet, let execute move take care
-                                  of it */
-  if (mt->fromFile == ALG_DROP) {
-    mt->piecePromotionTo = NOPIECE;
-    sprintf(mt->moveString, "%s/%c%c-%c%d",
-           wpstring[mt->fromRank],
-               DROP_CHAR, DROP_CHAR,
-           mt->toFile + 'a', mt->toRank + 1);
+  struct game_state_t fakeMove;\r
+\r
+  mt->pieceCaptured = gs->board[mt->toFile][mt->toRank];\r
+  mt->enPassant = 0;           /* Don't know yet, let execute move take care\r
+                                  of it */\r
+  if (mt->fromFile == ALG_DROP) {\r
+    mt->piecePromotionTo = NOPIECE;\r
+    sprintf(mt->moveString, "%s/%c%c-%c%d",\r
+           wpstring[mt->fromRank],\r
+               DROP_CHAR, DROP_CHAR,\r
+           mt->toFile + 'a', mt->toRank + 1 - (gs->ranks>9));\r
+  } else if(mt->fromFile == ALG_CASTLE) { 
+       // [HGM] castle: generalized castling, fr and tr give from and to file of Rook.
+           sprintf(mt->moveString, mt->toRank > mt->toFile ? "o-o-o" : "o-o");
   } else {
-  if ((piecetype(gs->board[mt->fromFile][mt->fromRank]) == PAWN) &&
-      ((mt->toRank == 0) || (mt->toRank == 7))) {
-    mt->piecePromotionTo = promote |
-      (colorval(gs->board[mt->fromFile][mt->fromRank]));
-  } else {
-    mt->piecePromotionTo = NOPIECE;
+  if ((piecetype(gs->board[mt->fromFile][mt->fromRank]) == PAWN) && 
+       !gs->palace && // [HGM] XQ: no promotions in xiangqi\r
+      ((mt->toRank == 0) || (mt->toRank == gs->ranks-1))) {
+    if(!gs->pawnDblStep && promote == PRINCESS) promote = MAN2;
+    if(!gs->pawnDblStep && promote != FERZ2 && promote != MAN2) promote = FERZ; // [HGM] kludge to recognize shatranj
+    mt->piecePromotionTo = promote |\r
+      (colorval(gs->board[mt->fromFile][mt->fromRank]));\r
+  } else {\r
+    mt->piecePromotionTo = NOPIECE;\r
+  }\r
+  if ((piecetype(gs->board[mt->fromFile][mt->fromRank]) == PAWN) &&\r
+   ((mt->fromRank - mt->toRank == 2) || (mt->toRank - mt->fromRank == 2))) {\r
+    mt->doublePawn = mt->fromFile;\r
+  } else {\r
+    mt->doublePawn = -1;\r
   }
-  if ((piecetype(gs->board[mt->fromFile][mt->fromRank]) == PAWN) &&
-   ((mt->fromRank - mt->toRank == 2) || (mt->toRank - mt->fromRank == 2))) {
-    mt->doublePawn = mt->fromFile;
-  } else {
-    mt->doublePawn = -1;
-  }
-  if ((piecetype(gs->board[mt->fromFile][mt->fromRank]) == KING) &&
-      (mt->fromFile == 4) && (mt->toFile == 2)) {
-    sprintf(mt->moveString, "o-o-o");
-  } else if ((piecetype(gs->board[mt->fromFile][mt->fromRank]) == KING) &&
-            (mt->fromFile == 4) && (mt->toFile == 6)) {
+#if 0
+  if ((piecetype(gs->board[mt->fromFile][mt->fromRank]) == KING) &&\r
+      (mt->fromFile == gs->files/2) && (mt->toFile == 2) &&
+       mt->fromRank == mt->toRank) {\r
+    sprintf(mt->moveString, "o-o-o");\r
+  } else if ((piecetype(gs->board[mt->fromFile][mt->fromRank]) == KING) &&\r
+            (mt->fromFile == gs->files/2) && (mt->toFile == gs->files-2) &&
+               mt->fromRank == mt->toRank) {\r
     sprintf(mt->moveString, "o-o");
   } else {
-    sprintf(mt->moveString, "%s/%c%d-%c%d",
-           wpstring[piecetype(gs->board[mt->fromFile][mt->fromRank])],
-           mt->fromFile + 'a', mt->fromRank + 1,
-           mt->toFile + 'a', mt->toRank + 1);
-  }
-  }
-  /* Replace this with an algabraic de-parser */
-
-  sprintf(mt->algString, alg_unparse(gs, mt));
-  fakeMove = *gs;
-  /* Calculates enPassant also */
-  execute_move(&fakeMove, mt, 0);
-
-  /* Does making this move leave ME in check? */
-  if (in_check(&fakeMove))
-    return MOVE_ILLEGAL;
-  /* IanO: bughouse variants: drop cannot be check/checkmate */
-
-  return MOVE_OK;
+#else
+  {
+#endif\r
+    sprintf(mt->moveString, "%s/%c%d-%c%d",\r
+           wpstring[piecetype(gs->board[mt->fromFile][mt->fromRank])],\r
+           mt->fromFile + 'a', mt->fromRank + 1 - (gs->ranks>9),\r
+           mt->toFile + 'a', mt->toRank + 1 - (gs->ranks>9));\r
+  }\r
+  }\r
+  /* Replace this with an algabraic de-parser */\r
+\r
+  sprintf(mt->algString, alg_unparse(gs, mt));\r
+  fakeMove = *gs;\r
+  /* Calculates enPassant also */\r
+  execute_move(&fakeMove, mt, 0);\r
+\r
+  /* Does making this move leave ME in check? */\r
+  if (in_check(&fakeMove))\r
+    return MOVE_ILLEGAL;\r
+  /* IanO: bughouse variants: drop cannot be check/checkmate */\r
+\r
+  return MOVE_OK;\r
 }
 
 int legal_andcheck_move(struct game_state_t * gs,
@@ -717,36 +1552,36 @@ int legal_andcheck_move(struct game_state_t * gs,
  */
 int in_check(struct game_state_t * gs)
 {
-  int f, r;
-  int kf = -1, kr = -1;
-
-  /* Find the king */
-  if (gs->onMove == WHITE) {
-    for (f = 0; f < 8 && kf < 0; f++)
-      for (r = 0; r < 8 && kf < 0; r++)
-       if (gs->board[f][r] == B_KING) {
-         kf = f;
-         kr = r;
-       }
-  } else {
-    for (f = 0; f < 8 && kf < 0; f++)
-      for (r = 0; r < 8 && kf < 0; r++)
-       if (gs->board[f][r] == W_KING) {
-         kf = f;
-         kr = r;
-       }
-  }
-  if (kf < 0) {
-    d_printf( "CHESSD: Error game with no king!\n");
-    return 0;
-  }
-  for (InitPieceLoop(gs->board, &f, &r, gs->onMove);
-       NextPieceLoop(gs->board, &f, &r, gs->onMove);) {
-    if (legal_move(gs, f, r, kf, kr)) {        /* In Check? */
-      return 1;
-    }
-  }
-  return 0;
+  int f, r;\r
+  int kf = -1, kr = -1;\r
+\r
+  /* Find the king */\r
+  if (gs->onMove == WHITE) {\r
+    for (f = 0; f < gs->files && kf < 0; f++)\r
+      for (r = 0; r < gs->ranks && kf < 0; r++)\r
+       if (gs->board[f][r] == B_KING) {\r
+         kf = f;\r
+         kr = r;\r
+       }\r
+  } else {\r
+    for (f = 0; f < gs->files && kf < 0; f++)\r
+      for (r = 0; r < gs->ranks && kf < 0; r++)\r
+       if (gs->board[f][r] == W_KING) {\r
+         kf = f;\r
+         kr = r;\r
+       }\r
+  }\r
+  if (kf < 0) {\r
+    d_printf( "CHESSD: Error game with no king!\n");\r
+    return 0;\r
+  }\r
+  for (InitPieceLoop(gs->board, &f, &r, gs->onMove);\r
+       NextPieceLoop(gs->board, &f, &r, gs->onMove, gs->files, gs->ranks);) {\r
+    if (legal_move(gs, f, r, kf, kr)) {        /* In Check? */\r
+      return 1;\r
+    }\r
+  }\r
+  return 0;\r
 }
 
 int has_legal_move(struct game_state_t * gs)
@@ -758,7 +1593,7 @@ int has_legal_move(struct game_state_t * gs)
   int numpossible = 0;
 
   for (InitPieceLoop(gs->board, &f, &r, gs->onMove);
-       NextPieceLoop(gs->board, &f, &r, gs->onMove);) {
+       NextPieceLoop(gs->board, &f, &r, gs->onMove, gs->files, gs->ranks);) {
     switch (piecetype(gs->board[f][r])) {
     case PAWN:
       possible_pawn_moves(gs, f, r, possiblef, possibler, &numpossible);
@@ -772,9 +1607,86 @@ int has_legal_move(struct game_state_t * gs)
     case ROOK:
       possible_rook_moves(gs, f, r, possiblef, possibler, &numpossible);
       break;
+    case CARDINAL:\r
+    case PRINCESS:\r
+      possible_cardinal_moves(gs, f, r, possiblef, possibler, &numpossible);\r
+      break;\r
+    case MARSHALL:\r
+    case EMPRESS:\r
+      possible_marshall_moves(gs, f, r, possiblef, possibler, &numpossible);\r
+      break;\r
+    case MAN:\r
+    case MAN2:\r
+      possible_man_moves(gs, f, r, possiblef, possibler, &numpossible);\r
+      break;\r
     case QUEEN:
       possible_queen_moves(gs, f, r, possiblef, possibler, &numpossible);
       break;
+    case ELEPHANT:
+      possible_elephant_moves(gs, f, r, possiblef, possibler, &numpossible);
+      break;
+    case AMAZON:
+      possible_amazon_moves(gs, f, r, possiblef, possibler, &numpossible);
+      break;
+    case WOODY:
+      possible_woody_moves(gs, f, r, possiblef, possibler, &numpossible);
+      break;
+    case SQUIRREL:
+      possible_squirrel_moves(gs, f, r, possiblef, possibler, &numpossible);
+      break;
+    case MASTODON:
+      possible_mastodon_moves(gs, f, r, possiblef, possibler, &numpossible);
+      break;
+    case CENTAUR:
+      possible_centaur_moves(gs, f, r, possiblef, possibler, &numpossible);
+      break;
+    case HORSE:
+      possible_horse_moves(gs, f, r, possiblef, possibler, &numpossible);
+      break;
+    case FERZ:
+    case FERZ2:
+      possible_ferz_moves(gs, f, r, possiblef, possibler, &numpossible);
+      break;
+    case MANDARIN:
+      possible_mandarin_moves(gs, f, r, possiblef, possibler, &numpossible);
+      break;
+    case WAZIR:
+      possible_wazir_moves(gs, f, r, possiblef, possibler, &numpossible);
+      break;
+    case ALFIL:
+    case ALFIL2:
+      possible_alfil_moves(gs, f, r, possiblef, possibler, &numpossible);
+      break;
+    case MODERNELEPHANT:
+      possible_modernelephant_moves(gs, f, r, possiblef, possibler, &numpossible);
+      break;
+    case PRIESTESS:
+      possible_priestess_moves(gs, f, r, possiblef, possibler, &numpossible);
+      break;
+    case MINISTER:
+      possible_minister_moves(gs, f, r, possiblef, possibler, &numpossible);
+      break;
+    case SILVER:
+      possible_silver_moves(gs, f, r, possiblef, possibler, &numpossible);
+      break;
+    case GOLD:
+      possible_gold_moves(gs, f, r, possiblef, possibler, &numpossible);
+      break;
+    case CANNON:
+      possible_cannon_moves(gs, f, r, possiblef, possibler, &numpossible);
+      break;
+    case LANCE:
+      possible_lance_moves(gs, f, r, possiblef, possibler, &numpossible);
+      break;
+    case DRAGONHORSE:
+      possible_dragonhorse_moves(gs, f, r, possiblef, possibler, &numpossible);
+      break;
+    case DRAGONKING:
+      possible_dragonking_moves(gs, f, r, possiblef, possibler, &numpossible);
+      break;
+    case HONORABLEHORSE:
+      possible_honorablehorse_moves(gs, f, r, possiblef, possibler, &numpossible);
+      break;
     case KING:
       kf = f;
       kr = r;
@@ -790,21 +1702,31 @@ int has_legal_move(struct game_state_t * gs)
       }
   }
 
-  /* IanO:  if we got here, then kf and kr must be set */
-  if (gs->gameNum >=0 && game_globals.garray[gs->gameNum].link >= 0) {
-    /* bughouse: potential drops as check interpositions */
-    gs->holding[gs->onMove==WHITE ? 0 : 1][QUEEN - 1]++;
-    for (f=kf-1; f<=kf+1; f++) for (r=kr-1; r<=kr+1; r++) {
-      if (f>=0 && f<8 && r>=0 && r<8 && gs->board[f][r] == NOPIECE) {
-       /* try a drop next to the king */
-       if (legal_andcheck_move(gs, ALG_DROP, QUEEN, f, r)) {
+  /* IanO:  if we got here, then kf and kr must be set */\r
+  if (gs->gameNum >=0 && game_globals.garray[gs->gameNum].link >= 0
+       || gs->holdings) { // [HGM] zh: also in 2-player games with drops\r
+    /* bughouse: potential drops as check interpositions */\r
+    gs->holding[gs->onMove==WHITE ? 0 : 1][QUEEN - 1]++;\r
+    for (f=kf-1; f<=kf+1; f++) for (r=kr-1; r<=kr+1; r++) {\r
+      if (f>=0 && f<gs->files && r>=0 && r<gs->ranks && gs->board[f][r] == NOPIECE) {\r
+       /* try a drop next to the king */\r
+       if (legal_andcheck_move(gs, ALG_DROP, QUEEN, f, r)) {\r
          gs->holding[gs->onMove==WHITE ? 0 : 1][QUEEN - 1]--;
-         return 1;
-       }
-      }
-    }
-    gs->holding[gs->onMove==WHITE ? 0 : 1][QUEEN - 1]--;
-  }
+         // OK, so we have an interposing drop. But do we have something to drop?
+         if(game_globals.garray[gs->gameNum].link < 0) {
+               // we have no partner, so we must have something to drop now
+               for(i=QUEEN; i>=PAWN; i--)
+                       if(gs->holding[gs->onMove==WHITE ? 0 : 1][i-1]) break;
+               if(i > PAWN) return 1; // we have a non-Pawn to drop
+               // We have a Pawn, but check if it legal to drop it
+               if(i == PAWN && r != 0 && r != gs->ranks-1) return 1; // [HGM] todo: for Shogi there are extra conditions on Pawn drops!
+         }\r
+         return 1;\r
+       }\r
+      }\r
+    }\r
+    gs->holding[gs->onMove==WHITE ? 0 : 1][QUEEN - 1]--;\r
+  }\r
 
   return 0;
 }
@@ -812,67 +1734,97 @@ int has_legal_move(struct game_state_t * gs)
 /* This will end up being a very complicated function */
 int parse_move(char *mstr, struct game_state_t * gs, struct move_t * mt, int promote)
 {
-  int type = is_move(mstr);
-  int result;
-
-  mt->piecePromotionTo = NOPIECE;
-  mt->color = gs->onMove;
-  switch (type) {
-  case MS_NOTMOVE:
-    return MOVE_ILLEGAL;
-    break;
-  case MS_COMP:
-    mt->fromFile = mstr[0] - 'a';
-    mt->fromRank = mstr[1] - '1';
-    mt->toFile = mstr[2] - 'a';
-    mt->toRank = mstr[3] - '1';
-    break;
-  case MS_COMPDASH:
-    mt->fromFile = mstr[0] - 'a';
-    mt->fromRank = mstr[1] - '1';
-    mt->toFile = mstr[3] - 'a';
-    mt->toRank = mstr[4] - '1';
-    break;
-  case MS_KCASTLE:
-    mt->fromFile = 4;
-    mt->toFile = 6;
-    if (gs->onMove == WHITE) {
-      mt->fromRank = 0;
-      mt->toRank = 0;
-    } else {
-      mt->fromRank = 7;
-      mt->toRank = 7;
-    }
+  int type = is_move(mstr);\r
+  int result;\r
+\r
+  mt->piecePromotionTo = NOPIECE;\r
+  mt->color = gs->onMove;\r
+  switch (type) {\r
+  case MS_NOTMOVE:\r
+    return MOVE_ILLEGAL;\r
+    break;\r
+  case MS_COMP:\r
+    mt->fromFile = mstr[0] - 'a';\r
+    mt->fromRank = mstr[1] - '1' + (gs->ranks>9);\r
+    mt->toFile = mstr[2] - 'a';\r
+    mt->toRank = mstr[3] - '1' + (gs->ranks>9);\r
+    break;\r
+  case MS_COMPDASH:\r
+    mt->fromFile = mstr[0] - 'a';\r
+    mt->fromRank = mstr[1] - '1' + (gs->ranks>9);\r
+    mt->toFile = mstr[3] - 'a';\r
+    mt->toRank = mstr[4] - '1' + (gs->ranks>9);\r
+    break;\r
+  case MS_KCASTLE:\r
+#if 0
+    mt->fromFile = gs->files/2;\r
+    mt->toFile = gs->files-2;\r
+    if (gs->onMove == WHITE) {\r
+      mt->fromRank = 0;\r
+      mt->toRank = 0;\r
+    } else {\r
+      mt->fromRank = gs->ranks-1;\r
+      mt->toRank = gs->ranks-1;\r
+    }\r
     break;
+#endif
+    // [HGM] castle: for now always assume Fischer-type castling (of which normal castling is a special case).
+    mt->fromFile = ALG_CASTLE;\r
+    mt->toFile = gs->files-2;\r
+    mt->fromRank = gs->onMove == WHITE ? gs->wkrmoved : gs->bkrmoved;\r
+    mt->toRank = mt->toFile-1; // R next to K\r
+    break;    \r
   case MS_QCASTLE:
-    mt->fromFile = 4;
-    mt->toFile = 2;
-    if (gs->onMove == WHITE) {
-      mt->fromRank = 0;
-      mt->toRank = 0;
-    } else {
-      mt->fromRank = 7;
-      mt->toRank = 7;
-    }
-    break;
-  case MS_ALG:
-    /* Fills in the mt structure */
-    if ((result = alg_parse_move(mstr, gs, mt)) != MOVE_OK)
-      return result;
-    break;
-  default:
-    return MOVE_ILLEGAL;
+#if 0\r
+    mt->fromFile = gs->files/2;\r
+    mt->toFile = 2;\r
+    if (gs->onMove == WHITE) {\r
+      mt->fromRank = 0;\r
+      mt->toRank = 0;\r
+    } else {\r
+      mt->fromRank = gs->ranks-1;\r
+      mt->toRank = gs->ranks-1;\r
+    }\r
     break;
+#endif\r
+    mt->fromFile = ALG_CASTLE;\r
+    mt->toFile = 2;\r
+    mt->fromRank = gs->onMove == WHITE ? gs->wqrmoved : gs->bqrmoved;\r
+    mt->toRank = mt->toFile+1;
+    break;\r
+  case MS_ALG:\r
+    /* Fills in the mt structure */\r
+    if ((result = alg_parse_move(mstr, gs, mt)) != MOVE_OK)\r
+      return result;\r
+    break;\r
+  default:\r
+    return MOVE_ILLEGAL;\r
+    break;\r
   }
-  if (!legal_move(gs, mt->fromFile, mt->fromRank, mt->toFile, mt->toRank)) {
-    return MOVE_ILLEGAL;
-  }
-
-  if (mt->piecePromotionTo != NOPIECE) {
-         promote = piecetype(mt->piecePromotionTo);
-  }
-
-  return move_calculate(gs, mt, promote);
+  if((mt->fromRank >= gs->ranks || mt->fromRank < 0 || mt->fromFile >= gs->files) &&
+     mt->fromFile != ALG_DROP && mt->fromFile != ALG_CASTLE\r
+     || mt->toRank < 0 || mt->toRank >= gs->ranks || mt->toFile >= gs->files)\r
+    return MOVE_ILLEGAL; // [HGM] make sure move stays on board
+\r
+  if (!(result = legal_move(gs, mt->fromFile, mt->fromRank, mt->toFile, mt->toRank)))
+    return MOVE_ILLEGAL;\r
+
+  if(result == 2) { // [HGM] castle: orthodox castling was given as King move; convert it to new format
+       if(mt->fromFile - mt->toFile > 1) { // Q-side
+               mt->fromRank = 0; 
+               mt->toRank   = mt->toFile+1;
+       } else if(mt->toFile - mt->fromFile > 1) { // K-side
+               mt->fromRank = gs->files-1;
+               mt->toRank   = mt->toFile-1;
+       }
+       mt->fromFile = ALG_CASTLE;
+    }\r
+\r
+  if (mt->piecePromotionTo != NOPIECE) {\r
+         promote = piecetype(mt->piecePromotionTo);\r
+  }\r
+\r
+  return move_calculate(gs, mt, promote);\r
 }
 
 /* Returns MOVE_OK, MOVE_NOMATERIAL, MOVE_CHECKMATE, or MOVE_STALEMATE */
@@ -881,7 +1833,7 @@ int execute_move(struct game_state_t * gs, struct move_t * mt, int check_game_st
 {
   int movedPiece;
   int tookPiece;
-  int i, j, foobar;
+  int i, j, foobar, wCnt, bCnt, king, rook;
 
   if (mt->fromFile == ALG_DROP) {
     movedPiece = mt->fromRank;
@@ -890,6 +1842,23 @@ int execute_move(struct game_state_t * gs, struct move_t * mt, int check_game_st
     gs->board[mt->toFile][mt->toRank] = movedPiece | gs->onMove;
     if (gs->gameNum >= 0)
       gs->lastIrreversable = game_globals.garray[gs->gameNum].numHalfMoves;
+  } else if(mt->fromFile == ALG_CASTLE) {
+    int backRank, fKing;
+    // [HGM] castle: perform castling
+    if(gs->onMove == WHITE) {
+       backRank = 0;
+       fKing = gs->wkmoved;
+       gs->wkmoved = -gs->wkmoved-2;
+    } else {
+       backRank = gs->ranks-1;
+       fKing = gs->bkmoved;
+       gs->bkmoved = -gs->bkmoved-2;
+    }
+    // move Rook & King, in a way that is resistant to ending where they started (for FRC!)
+    rook = gs->board[mt->fromRank][backRank];    // first remember\r
+    king = gs->board[fKing][backRank];\r
+    gs->board[mt->fromRank][backRank] = NOPIECE; // then erase\r    gs->board[fKing][backRank] = NOPIECE;\r    gs->board[mt->toRank][backRank] = rook;      // then put back
+    gs->board[mt->toFile][backRank] = king;
   } else {
   movedPiece = gs->board[mt->fromFile][mt->fromRank];
   tookPiece = gs->board[mt->toFile][mt->toRank];
@@ -897,16 +1866,18 @@ int execute_move(struct game_state_t * gs, struct move_t * mt, int check_game_st
     gs->board[mt->toFile][mt->toRank] = gs->board[mt->fromFile][mt->fromRank];
   } else {
     gs->board[mt->toFile][mt->toRank] = mt->piecePromotionTo | gs->onMove;
+    if(gs->promoType == 2) gs->holding[gs->onMove][mt->piecePromotionTo-1]--;
   }
   gs->board[mt->fromFile][mt->fromRank] = NOPIECE;
   /* Check if irreversable */
-  if ((piecetype(movedPiece) == PAWN) || (tookPiece != NOPIECE)) {
+  if ((piecetype(movedPiece) == PAWN) && (mt->fromRank != mt->toRank) // [HGM] XQ: sideway Pawn move reversible!
+                       || (tookPiece != NOPIECE)) {
     if (gs->gameNum >= 0)
       gs->lastIrreversable = game_globals.garray[gs->gameNum].numHalfMoves;
   }
   /* Check if this move is en-passant */
   if ((piecetype(movedPiece) == PAWN) && (mt->fromFile != mt->toFile) &&
-      (tookPiece == NOPIECE)) {
+      (tookPiece == NOPIECE) && !gs->palace) { // [HGM] XQ: no e.p. in sideway xiangqi moves
     if (gs->onMove == WHITE) {
       mt->pieceCaptured = B_PAWN;
     } else {
@@ -919,11 +1890,11 @@ int execute_move(struct game_state_t * gs, struct move_t * mt, int check_game_st
     }
     gs->board[mt->toFile][mt->fromRank] = NOPIECE;
   }
-  /* Check en-passant flags for next moves */
-  for (i = 0; i < 8; i++) {
-    gs->ep_possible[0][i] = 0;
-    gs->ep_possible[1][i] = 0;
-  }
+  /* Check en-passant flags for next moves */\r
+  for (i = 0; i < gs->files; i++) {\r
+    gs->ep_possible[0][i] = 0;\r
+    gs->ep_possible[1][i] = 0;\r
+  }\r
 /* Added by Sparky 3/16/95
 
    From soso@Viktoria.drp.fmph.uniba.sk Thu Mar 16 13:08:51 1995
@@ -940,94 +1911,105 @@ int execute_move(struct game_state_t * gs, struct move_t * mt, int check_game_st
         if ((mt->toFile+1 < 7 ) ....  should be : (mt->toFile < 7 ) }
 */
 
-  if ((piecetype(movedPiece) == PAWN) &&
-   ((mt->fromRank == mt->toRank + 2) || (mt->fromRank + 2 == mt->toRank))) {
-    /* Should turn on enpassent flag if possible */
-    if (gs->onMove == WHITE) {
-      if ((mt->toFile < 7) && gs->board[mt->toFile + 1][3] == B_PAWN) {
-       gs->ep_possible[1][mt->toFile + 1] = -1;
-      }
-      if ((mt->toFile - 1 >= 0) && gs->board[mt->toFile - 1][3] == B_PAWN) {
-       gs->ep_possible[1][mt->toFile - 1] = 1;
-      }
-    } else {
-      if ((mt->toFile < 7) && gs->board[mt->toFile + 1][4] == W_PAWN) {
-       gs->ep_possible[0][mt->toFile + 1] = -1;
-      }
-      if ((mt->toFile - 1 >= 0) && gs->board[mt->toFile - 1][4] == W_PAWN) {
-       gs->ep_possible[0][mt->toFile - 1] = 1;
-      }
-    }
-  }
-  if ((piecetype(movedPiece) == ROOK) && (mt->fromFile == 0)) {
-    if ((mt->fromRank == 0) && (gs->onMove == WHITE))
-      gs->wqrmoved = 1;
-    if ((mt->fromRank == 7) && (gs->onMove == BLACK))
-      gs->bqrmoved = 1;
-  }
-  if ((piecetype(movedPiece) == ROOK) && (mt->fromFile == 7)) {
-    if ((mt->fromRank == 0) && (gs->onMove == WHITE))
-      gs->wkrmoved = 1;
-    if ((mt->fromRank == 7) && (gs->onMove == BLACK))
-      gs->bkrmoved = 1;
-  }
-  if (piecetype(movedPiece) == KING) {
-    if (gs->onMove == WHITE)
-      gs->wkmoved = 1;
-    else
-      gs->bkmoved = 1;
-  }
-  if ((piecetype(movedPiece) == KING) &&
-      ((mt->fromFile == 4) && ((mt->toFile == 6)))) {  /* Check for KS castling */
-    gs->board[5][mt->toRank] = gs->board[7][mt->toRank];
-    gs->board[7][mt->toRank] = NOPIECE;
+  if ((piecetype(movedPiece) == PAWN) &&\r
+   ((mt->fromRank == mt->toRank + 2) || (mt->fromRank + 2 == mt->toRank))) {\r
+    /* Should turn on enpassent flag if possible */\r
+    if (gs->onMove == WHITE) {\r
+      if ((mt->toFile < gs->files-1) && gs->board[mt->toFile + 1][mt->toRank] == B_PAWN) {\r
+       gs->ep_possible[1][mt->toFile + 1] = -1;\r
+      }\r
+      if ((mt->toFile - 1 >= 0) && gs->board[mt->toFile - 1][mt->toRank] == B_PAWN) {\r
+       gs->ep_possible[1][mt->toFile - 1] = 1;\r
+      }\r
+    } else {\r
+      if ((mt->toFile < gs->files-1) && gs->board[mt->toFile + 1][mt->toRank] == W_PAWN) {\r
+       gs->ep_possible[0][mt->toFile + 1] = -1;\r
+      }\r
+      if ((mt->toFile - 1 >= 0) && gs->board[mt->toFile - 1][mt->toRank] == W_PAWN) {\r
+       gs->ep_possible[0][mt->toFile - 1] = 1;\r
+      }\r
+    }\r
+  }\r
+  if ((piecetype(movedPiece) == ROOK) && (mt->fromRank == 0) && (gs->onMove == WHITE)) {\r
+    if (mt->fromFile == gs->wqrmoved) // [HGM] castle: flip w.r.t. -1 to remember original\r
+      gs->wqrmoved = -gs->wqrmoved-2;\r
+    if (mt->fromFile == gs->wkrmoved)\r
+      gs->wkrmoved = -gs->wkrmoved-2;\r
+  }\r
+  if ((piecetype(movedPiece) == ROOK) && (mt->fromRank == gs->ranks-1) && (gs->onMove == BLACK)) {\r
+    if (mt->fromFile == gs->bqrmoved)\r
+      gs->bqrmoved = -gs->bqrmoved-2;\r
+    if (mt->fromFile == gs->bkrmoved)\r
+      gs->bkrmoved = -gs->bkrmoved-2;\r
+  }\r
+  if (piecetype(movedPiece) == KING) {\r
+    if ((gs->onMove == WHITE) && (mt->fromFile == gs->wkmoved))\r
+      gs->wkmoved = -gs->wkmoved-2;\r
+    if ((gs->onMove == BLACK) && (mt->fromFile == gs->bkmoved))\r
+      gs->bkmoved = -gs->bkmoved-2;\r
   }
-  if ((piecetype(movedPiece) == KING) &&
-      ((mt->fromFile == 4) && ((mt->toFile == 2)))) {  /* Check for QS castling */
-    gs->board[3][mt->toRank] = gs->board[0][mt->toRank];
-    gs->board[0][mt->toRank] = NOPIECE;
+#if 0\r
+  if ((piecetype(movedPiece) == KING) &&\r
+      ((mt->fromFile == gs->files/2) && (mt->toFile == gs->files-2)) &&
+       mt->fromRank == mt->toRank) {   /* Check for KS castling */\r
+    gs->board[gs->files-3][mt->toRank] = gs->board[gs->files-1][mt->toRank];\r
+    gs->board[gs->files-1][mt->toRank] = NOPIECE;\r
+  }\r
+  if ((piecetype(movedPiece) == KING) &&\r
+      ((mt->fromFile == gs->files/2) && (mt->toFile == 2)) &&
+       mt->fromRank == mt->toRank) {   /* Check for QS castling */\r
+    gs->board[3][mt->toRank] = gs->board[0][mt->toRank];\r
+    gs->board[0][mt->toRank] = NOPIECE;\r
   }
-  }
-  if (gs->onMove == BLACK)
-    gs->moveNum++;
-
-  if (check_game_status) {
-    /* Does this move result in check? */
-    if (in_check(gs)) {
-      /* Check for checkmate */
-      gs->onMove = CToggle(gs->onMove);
-      if (!has_legal_move(gs))
-       return MOVE_CHECKMATE;
-    } else {
-      /* Check for stalemate */
-      gs->onMove = CToggle(gs->onMove);
-      if (!has_legal_move(gs))
-       return MOVE_STALEMATE;
-/* loon: check for insufficient mating material, first try */
-      foobar = 0;
-      for (i=0; i<8; i++) {
-        for (j=0; j<8; j++) {
-          switch(piecetype(gs->board[i][j])) {
-            case KNIGHT:
-            case BISHOP:
-              foobar++;
-              break;
-            case KING:
-           case NOPIECE:
-             break;
-            default:
-              foobar = 2;
-              break;
+#endif\r
+  }\r
+  if (gs->onMove == BLACK)\r
+    gs->moveNum++;\r
+\r
+  if (check_game_status) {\r
+    /* Does this move result in check? */\r
+    if (in_check(gs)) {\r
+      /* Check for checkmate */\r
+      gs->onMove = CToggle(gs->onMove);\r
+      if (!has_legal_move(gs))\r
+       return MOVE_CHECKMATE;\r
+    } else {\r
+      /* Check for stalemate */\r
+      gs->onMove = CToggle(gs->onMove);\r
+      if (!has_legal_move(gs))\r
+       return gs->stalemate ? MOVE_STALEMATE : MOVE_CHECKMATE; // [HGM] in XQ and shatranj stalemate loses\r
+    }\r
+/* loon: check for insufficient mating material, first try */\r
+      foobar = wCnt = bCnt = 0;\r
+      for (i=0; i<gs->files; i++) {\r
+        for (j=0; j<gs->ranks; j++) {
+         int p = gs->board[i][j];\r
+          switch(piecetype(p)) {\r
+            case KNIGHT:\r
+            case BISHOP:\r
+              foobar++;\r
+              break;\r
+            case KING:\r
+           case NOPIECE:\r
+             break;\r
+            default:\r
+              foobar = 2;\r
+              break;\r
           }
-        }
+         if(p != NOPIECE && iscolor(p, WHITE)) wCnt++;
+         if(iscolor(p, BLACK)) bCnt++;\r
+        }\r
       }
-      if (foobar < 2)
-        return MOVE_NOMATERIAL;
-    }
-  } else {
-    gs->onMove = CToggle(gs->onMove);
-  }
-  return MOVE_OK;
+      if(gs->bareKingLoses) { // [HGM] with bare-King-loses rule only KK is insuff. material
+       if(gs->onMove == BLACK && wCnt == 1 && bCnt > 1) return MOVE_BARE;
+       if(gs->onMove == WHITE && bCnt == 1 && wCnt > 1) return MOVE_BARE;
+       if(bCnt == 1 && wCnt == 1) return MOVE_NOMATERIAL;
+      } else if (foobar < 2)\r
+        return MOVE_NOMATERIAL;\r
+  } else {\r
+    gs->onMove = CToggle(gs->onMove);\r
+  }\r
+  return MOVE_OK;\r
 }
 
 int backup_move(int g, int mode)
@@ -1046,6 +2028,31 @@ int backup_move(int g, int mode)
   if (m->toFile < 0) {
     return MOVE_ILLEGAL;
   }
+  if(m->fromFile == ALG_CASTLE) {
+    // [HGM] castling in new format. Derive K and R moves
+    int rank, kingFromFile;
+    if(m->color == WHITE) {
+      rank = 0;
+      kingFromFile = -gs->wkmoved-2;
+      if(kingFromFile<0) kingFromFile = -kingFromFile-2; // safety catch; should never happen?
+      gs->wkmoved = kingFromFile;
+      if(m->toRank > m->toFile) gs->wqrmoved = m->fromRank;
+      else gs->wkrmoved = m->fromRank;
+    } else {
+      rank = gs->ranks-1;
+      kingFromFile = -gs->bkmoved-2;
+      if(kingFromFile<0) kingFromFile = -kingFromFile-2; // safety catch; should never happen?
+      gs->bkmoved = kingFromFile;
+      if(m->toRank > m->toFile) gs->bqrmoved = m->fromRank;
+      else gs->bkrmoved = m->fromRank;
+    }
+    // remove first, as one might come back to a square the other left
+    gs->board[m->toFile  ][rank] = NOPIECE; // King toSqr
+    gs->board[m->toRank  ][rank] = NOPIECE; // Rook toSqr
+    gs->board[m->fromRank][rank] = ROOK | m->color; // Rook fromSqr
+    gs->board[kingFromFile][rank] = KING | m->color; // King fromSquare
+    goto cleanupMove;
+  }
   gs->board[m->fromFile][m->fromRank] = gs->board[m->toFile][m->toRank];
   if (m->piecePromotionTo != NOPIECE) {
     gs->board[m->fromFile][m->fromRank] = PAWN |
@@ -1058,48 +2065,49 @@ int backup_move(int g, int mode)
   *******************/
   if (piecetype(gs->board[m->fromFile][m->fromRank]) == ROOK) {
     if (m->color == WHITE) {
-      if ((m->fromFile == 0) && (m->fromRank == 0)) {
-       for (i = 2; i < game_globals.garray[g].numHalfMoves - 1; i += 2) {
-         m1 = (mode==REL_GAME) ? &game_globals.garray[g].moveList[i] : &game_globals.garray[g].examMoveList[i];
-         if ((m1->fromFile == 0) && (m1->fromRank == 0))
-           break;
-       }
-       if (i == game_globals.garray[g].numHalfMoves - 1)
-         gs->wqrmoved = 0;
-      }
-      if ((m->fromFile == 7) && (m->fromRank == 0)) {
+      if ((m->fromFile == -gs->wqrmoved-2) && (m->fromRank == 0)) {
        for (i = 2; i < game_globals.garray[g].numHalfMoves - 1; i += 2) {
          m1 = (mode==REL_GAME) ? &game_globals.garray[g].moveList[i] : &game_globals.garray[g].examMoveList[i];
-         if ((m1->fromFile == 7) && (m1->fromRank == 0))
-           break;
-       }
-       if (i == game_globals.garray[g].numHalfMoves - 1)
-         gs->wkrmoved = 0;
-      }
-    } else {
-      if ((m->fromFile == 0) && (m->fromRank == 7)) {
-       for (i = 3; i < game_globals.garray[g].numHalfMoves - 1; i += 2) {
-         m1 = (mode==REL_GAME) ? &game_globals.garray[g].moveList[i] : &game_globals.garray[g].examMoveList[i];
-         if ((m1->fromFile == 0) && (m1->fromRank == 0))
+         if ((m1->fromFile == -gs->wqrmoved-2) && (m1->fromRank == 0))
            break;
        }
        if (i == game_globals.garray[g].numHalfMoves - 1)
-         gs->bqrmoved = 0;
+         gs->wqrmoved = m->fromFile;
       }
-      if ((m->fromFile == 7) && (m->fromRank == 7)) {
-       for (i = 3; i < game_globals.garray[g].numHalfMoves - 1; i += 2) {
-         m1 = (mode==REL_GAME) ? &game_globals.garray[g].moveList[i] : &game_globals.garray[g].examMoveList[i];
-         if ((m1->fromFile == 7) && (m1->fromRank == 0))
-           break;
-       }
-       if (i == game_globals.garray[g].numHalfMoves - 1)
-         gs->bkrmoved = 0;
-      }
-    }
-  }
+      if ((m->fromFile == -gs->wkrmoved-2) && (m->fromRank == 0)) {\r
+       for (i = 2; i < game_globals.garray[g].numHalfMoves - 1; i += 2) {\r
+         m1 = (mode==REL_GAME) ? &game_globals.garray[g].moveList[i] : &game_globals.garray[g].examMoveList[i];\r
+         if ((m1->fromFile == -gs->wkrmoved-2) && (m1->fromRank == 0))\r
+           break;\r
+       }\r
+       if (i == game_globals.garray[g].numHalfMoves - 1)\r
+         gs->wkrmoved = m->fromFile;\r
+      }\r
+    } else {\r
+      if ((m->fromFile == -gs->bqrmoved-2) && (m->fromRank == gs->ranks-1)) {\r
+       for (i = 3; i < game_globals.garray[g].numHalfMoves - 1; i += 2) {\r
+         m1 = (mode==REL_GAME) ? &game_globals.garray[g].moveList[i] : &game_globals.garray[g].examMoveList[i];\r
+         if ((m1->fromFile == -gs->bkrmoved-2) && (m1->fromRank == gs->ranks-1))\r
+           break;\r
+       }\r
+       if (i == game_globals.garray[g].numHalfMoves - 1)\r
+         gs->bqrmoved = m->fromFile;\r
+      }\r
+      if ((m->fromFile == -gs->bkrmoved-2) && (m->fromRank == gs->ranks-1)) {\r
+       for (i = 3; i < game_globals.garray[g].numHalfMoves - 1; i += 2) {\r
+         m1 = (mode==REL_GAME) ? &game_globals.garray[g].moveList[i] : &game_globals.garray[g].examMoveList[i];\r
+         if ((m1->fromFile == -gs->wkrmoved-2) && (m1->fromRank == gs->ranks-1))\r
+           break;\r
+       }\r
+       if (i == game_globals.garray[g].numHalfMoves - 1)\r
+         gs->bkrmoved = m->fromFile;\r
+      }\r
+    }\r
+  }\r
   if (piecetype(gs->board[m->fromFile][m->fromRank]) == KING) {
     gs->board[m->toFile][m->toRank] = m->pieceCaptured;
-
+#if 0
+    /* [HGM] castlings are already intercepted due to new format; this code wrecks knightmate! */
     if (m->toFile - m->fromFile == 2) {
       gs->board[7][m->fromRank] = ROOK |
        colorval(gs->board[m->fromFile][m->fromRank]);
@@ -1136,35 +2144,36 @@ int backup_move(int g, int mode)
       }
       goto cleanupMove;
     }
+#endif
     /******************
        When takeback a _first_ move of king (not the castling),
        the ?kmoved variable must be cleared . To check, if the move is first,
        we should scan moveList.
     *******************/
 
-    if (m->color == WHITE) {
-
-      if ((m->fromFile == 4) && (m->fromRank == 0)) {
-       for (i = 2; i < game_globals.garray[g].numHalfMoves - 1; i += 2) {
-         m1 = (mode==REL_GAME) ? &game_globals.garray[g].moveList[i] : &game_globals.garray[g].examMoveList[i];
-         if ((m1->fromFile == 4) && (m1->fromRank == 0))
-           break;
-       }
-       if (i == game_globals.garray[g].numHalfMoves - 1)
-         gs->wkmoved = 0;
-      }
-    } else {
-      if ((m->fromFile == 4) && (m->fromRank == 7)) {
-       for (i = 3; i < game_globals.garray[g].numHalfMoves - 1; i += 2) {
-         m1 = (mode==REL_GAME) ? &game_globals.garray[g].moveList[i] : &game_globals.garray[g].examMoveList[i];
-         if ((m1->fromFile == 4) && (m1->fromRank == 7))
-           break;
-       }
-       if (i == game_globals.garray[g].numHalfMoves - 1)
-         gs->bkmoved = 0;
-      }
-    }
-  }
+    if (m->color == WHITE) {\r
+\r
+      if ((m->fromFile == -gs->wkmoved-2) && (m->fromRank == 0)) {\r
+       for (i = 2; i < game_globals.garray[g].numHalfMoves - 1; i += 2) {\r
+         m1 = (mode==REL_GAME) ? &game_globals.garray[g].moveList[i] : &game_globals.garray[g].examMoveList[i];\r
+         if ((m1->fromFile == gs->wkmoved-2) && (m1->fromRank == 0))\r
+           break;\r
+       }\r
+       if (i == game_globals.garray[g].numHalfMoves - 1)\r
+         gs->wkmoved = m->fromFile;\r
+      }\r
+    } else {\r
+      if ((m->fromFile == -gs->bkmoved-2) && (m->fromRank == gs->ranks-1)) {\r
+       for (i = 3; i < game_globals.garray[g].numHalfMoves - 1; i += 2) {\r
+         m1 = (mode==REL_GAME) ? &game_globals.garray[g].moveList[i] : &game_globals.garray[g].examMoveList[i];\r
+         if ((m1->fromFile == -gs->bkmoved-2) && (m1->fromRank == gs->ranks-1))\r
+           break;\r
+       }\r
+       if (i == game_globals.garray[g].numHalfMoves - 1)\r
+         gs->bkmoved = m->fromFile;\r
+      }\r
+    }\r
+  }\r
   if (m->enPassant) {          /* Do enPassant */
     gs->board[m->toFile][m->fromRank] = PAWN |
       (colorval(gs->board[m->fromFile][m->fromRank]) == WHITE ? BLACK : WHITE);
@@ -1243,28 +2252,28 @@ cleanupMove:
      array.  (patch from Soso, added by Sparky 3/17/95)
   ********/
 
-  if (game_globals.garray[g].numHalfMoves > 0) {
-    m1 = (mode==REL_GAME) ? &game_globals.garray[g].moveList[game_globals.garray[g].numHalfMoves - 1] : 
-                            &game_globals.garray[g].examMoveList[game_globals.garray[g].numHalfMoves - 1];
-    if (piecetype(gs->board[m1->toFile][m1->toRank]) == PAWN) {
-      if ((m1->toRank - m1->fromRank) == 2) {
-       if ((m1->toFile < 7) && gs->board[m1->toFile + 1][3] == B_PAWN) {
-         gs->ep_possible[1][m1->toFile + 1] = -1;
-       }
-       if ((m1->toFile - 1 >= 0) && gs->board[m1->toFile - 1][3] == B_PAWN) {
-         gs->ep_possible[1][m1->toFile - 1] = 1;
-       }
-      }
-      if ((m1->toRank - m1->fromRank) == -2) {
-       if ((m1->toFile < 7) && gs->board[m1->toFile + 1][4] == W_PAWN) {
-         gs->ep_possible[0][m1->toFile + 1] = -1;
-       }
-       if ((m1->toFile - 1 >= 0) && gs->board[m1->toFile - 1][4] == W_PAWN) {
-         gs->ep_possible[0][m1->toFile - 1] = 1;
-       }
-      }
-    }
-  }
+  if (game_globals.garray[g].numHalfMoves > 0) {\r
+    m1 = (mode==REL_GAME) ? &game_globals.garray[g].moveList[game_globals.garray[g].numHalfMoves - 1] : \r
+                            &game_globals.garray[g].examMoveList[game_globals.garray[g].numHalfMoves - 1];\r
+    if (piecetype(gs->board[m1->toFile][m1->toRank]) == PAWN) {\r
+      if ((m1->toRank - m1->fromRank) == 2) {\r
+       if ((m1->toFile < gs->files-1) && gs->board[m1->toFile + 1][m1->toRank] == B_PAWN) {\r
+         gs->ep_possible[1][m1->toFile + 1] = -1;\r
+       }\r
+       if ((m1->toFile - 1 >= 0) && gs->board[m1->toFile - 1][m1->toRank] == B_PAWN) {\r
+         gs->ep_possible[1][m1->toFile - 1] = 1;\r
+       }\r
+      }\r
+      if ((m1->toRank - m1->fromRank) == -2) {\r
+       if ((m1->toFile < gs->files-1) && gs->board[m1->toFile + 1][m1->toRank] == W_PAWN) {\r
+         gs->ep_possible[0][m1->toFile + 1] = -1;\r
+       }\r
+       if ((m1->toFile - 1 >= 0) && gs->board[m1->toFile - 1][m1->toRank] == W_PAWN) {\r
+         gs->ep_possible[0][m1->toFile - 1] = 1;\r
+       }\r
+      }\r
+    }\r
+  }\r
   /************** and here's the end **************/
   return MOVE_OK;
 }
old mode 100644 (file)
new mode 100755 (executable)
index 8033261..bc06086
@@ -1,41 +1,42 @@
-/*
-   Copyright (c) 1993 Richard V. Nash.
-   Copyright (c) 2000 Dan Papasian
-   Copyright (C) Andrew Tridgell 2002
-   
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
-   (at your option) any later version.
-   
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-   
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef _MOVECHECK_H
-#define _MOVECHECK_H
-
-#define MOVE_OK 0
-#define MOVE_ILLEGAL 1
-#define MOVE_STALEMATE 2
-#define MOVE_CHECKMATE 3
-#define MOVE_AMBIGUOUS 4
-#define MOVE_NOMATERIAL 5
-
-#define MS_NOTMOVE 0
-#define MS_COMP 1
-#define MS_COMPDASH 2
-#define MS_ALG 3
-#define MS_KCASTLE 4
-#define MS_QCASTLE 5
-
-#define isrank(c) (((c) <= '8') && ((c) >= '1'))
-#define isfile(c) (((c) >= 'a') && ((c) <= 'h'))
-
-#endif /* _MOVECHECK_H */
+/*\r
+   Copyright (c) 1993 Richard V. Nash.\r
+   Copyright (c) 2000 Dan Papasian\r
+   Copyright (C) Andrew Tridgell 2002\r
+   \r
+   This program is free software; you can redistribute it and/or modify\r
+   it under the terms of the GNU General Public License as published by\r
+   the Free Software Foundation; either version 2 of the License, or\r
+   (at your option) any later version.\r
+   \r
+   This program is distributed in the hope that it will be useful,\r
+   but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+   GNU General Public License for more details.\r
+   \r
+   You should have received a copy of the GNU General Public License\r
+   along with this program; if not, write to the Free Software\r
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\r
+*/\r
+\r
+#ifndef _MOVECHECK_H\r
+#define _MOVECHECK_H\r
+\r
+#define MOVE_OK 0\r
+#define MOVE_ILLEGAL 1\r
+#define MOVE_STALEMATE 2\r
+#define MOVE_CHECKMATE 3\r
+#define MOVE_AMBIGUOUS 4\r
+#define MOVE_NOMATERIAL 5\r
+#define MOVE_BARE 6\r
+\r
+#define MS_NOTMOVE 0\r
+#define MS_COMP 1\r
+#define MS_COMPDASH 2\r
+#define MS_ALG 3\r
+#define MS_KCASTLE 4\r
+#define MS_QCASTLE 5\r
+\r
+#define isrank(c) (((c) <= '9') && ((c) >= '0'))\r
+#define isfile(c) (((c) >= 'a') && ((c) <= 'l'))\r
+\r
+#endif /* _MOVECHECK_H */\r
index 952a6de..3a7a990 100644 (file)
@@ -422,7 +422,7 @@ int com_moves(int p, param_list param)
       g = pp->game;
     } else if (pp->num_observe) {
       for (g = 0; g < pp->num_observe; g++) {
-       pprintf(p, "%s\n", movesToString(pp->observe_list[g], 0));
+       pprintf_noformat(p, "%s\n", movesToString(pp->observe_list[g], 0));
       }
       return COM_OK;
     } else {
@@ -444,7 +444,7 @@ int com_moves(int p, param_list param)
     pprintf(p, "Sorry, that is a private game.\n");
     return COM_OK;
   }
-  pprintf(p, "%s\n", movesToString(g, 0));     /* pgn may break interfaces? */
+  pprintf_noformat(p, "%s\n", movesToString(g, 0));    /* pgn may break interfaces? */
   return COM_OK;
 }
 
@@ -455,8 +455,13 @@ int com_mailmoves(int p, param_list param)
   int p1;
   char subj[81];
 
-  if (!CheckPFlag(p, PFLAG_REG)) {
-    pprintf (p,"Unregistered players cannot use mailmoves.\n");
+  if (param[1].type == TYPE_NULL) {
+    if (!CheckPFlag(p, PFLAG_REG)) {
+      pprintf (p,"Unregistered players must specify their e-mail address.\n");
+      return COM_OK;
+    }
+  } else if(!safestring(param[1].val.string)) {
+    pprintf (p,"Bad e-mail address.\n");
     return COM_OK;
   }
 
@@ -481,7 +486,9 @@ int com_mailmoves(int p, param_list param)
     return COM_OK;
   }
   sprintf(subj, "FICS game report %s vs %s", game_globals.garray[g].white_name, game_globals.garray[g].black_name);
-  if (mail_string_to_user(p, subj,
+  if (param[1].type == TYPE_NULL ? mail_string_to_user(p, subj,
+                          movesToString(g, CheckPFlag(p, PFLAG_PGN))) :
+               mail_string_to_address(param[1].val.string, subj,
                           movesToString(g, CheckPFlag(p, PFLAG_PGN)))) {
     pprintf(p, "Moves NOT mailed, perhaps your address is incorrect.\n");
   } else {
@@ -627,6 +634,7 @@ void ExamineScratch(int p,  param_list param,int setup)
     pprintf(p, "Loading from catagory: %s, board: %s.\n", category, board);
   }
 
+  game_globals.garray[g].FENstartPos[0] = 0; // [HGM] new shuffle game
   if (setup) {
     board_clear(&game_globals.garray[g].game_state);
     game_globals.garray[g].status = GAME_SETUP;
@@ -667,6 +675,7 @@ static int ExamineStored(FILE * fp, int p, char type)
   gg = &game_globals.garray[g];
   category[0] = '\0';
   board[0] = '\0';
+  game_globals.garray[g].FENstartPos[0] = 0; // [HGM] make new shuffle for now
   if (board_init(g,&gg->game_state, category, board)) {
     pprintf(p, "PROBLEM LOADING BOARD. Examine Aborted.\n");
     d_printf( "CHESSD: PROBLEM LOADING BOARD %s %s. Examine Aborted.\n",
@@ -683,6 +692,18 @@ static int ExamineStored(FILE * fp, int p, char type)
       game_remove(g);
       return -1;
     }
+
+    // [HGM] OK, we retreived the game info, which includes variant name as "category/board"
+    // So now we set up the board again, this time for the proper variant (and proper shuffle)
+    sscanf(gg->variant, "%s/%s", category, board);
+    if(category[0] && !board[0]) strcpy(board, "0");
+    if (board_init(g,&gg->game_state, category, board)) {
+      pprintf(p, "PROBLEM LOADING BOARD. Examine Aborted.\n");
+      d_printf( "CHESSD: PROBLEM LOADING BOARD %s %s. Examine Aborted.\n",
+              category, board);
+      game_remove(g);
+      return -1;
+    }
   } else if (ReadGameAttrs(fp, g) < 0) {
     pprintf(p, "Gamefile is corrupt; please notify an admin.\n");
     game_remove(g);
@@ -702,7 +723,6 @@ static int ExamineStored(FILE * fp, int p, char type)
 
   pp->side = WHITE;    /* oh well... */
   pp->game = g;
-
   send_boards(g);
   if (CheckPFlag(p, PFLAG_OPEN)) /* was open */
     announce_notavail(p);
@@ -1043,9 +1063,14 @@ static void stored_mail_moves(int p, int mail, param_list param)
   char fileName2[MAX_FILENAME_SIZE];
   FILE* fpGame;
   
- if (mail && !CheckPFlag(p, PFLAG_REG)) {
-    pprintf (p,"Unregistered players cannot use mailstored.\n");
-    return;
+  if (param[2].type == TYPE_NULL) {
+    if (!CheckPFlag(p, PFLAG_REG)) {
+      pprintf (p,"Unregistered players must specify their e-mail address.\n");
+      return COM_OK;
+    }
+  } else if(!safestring(param[2].val.string)) {
+    pprintf (p,"Bad e-mail address.\n");
+    return COM_OK;
   }
 
   if (!FindPlayer(p, param[0].val.word, &wp, &wconnected))
@@ -1125,13 +1150,15 @@ static void stored_mail_moves(int p, int mail, param_list param)
           } else {
             sprintf(subj, "FICS adjourned game %s vs %s", game_globals.garray[g].white_name, game_globals.garray[g].black_name);
           }
-        if (mail_string_to_user(p, subj,
+        if (param[2].type == TYPE_NULL ? mail_string_to_user(p, subj,
+                                movesToString(g, CheckPFlag(p, PFLAG_PGN))) :
+                        mail_string_to_address(param[2].val.string, subj,
                                 movesToString(g, CheckPFlag(p, PFLAG_PGN))))
          pprintf(p, "Moves NOT mailed, perhaps your address is incorrect.\n");
         else
          pprintf(p, "Moves mailed.\n");
       } else {
-        pprintf(p, "%s\n", movesToString(g, 0));
+        pprintf_noformat(p, "%s\n", movesToString(g, 0));
       } /* Do smoves */
     }
   }
index 4138c63..eb37655 100644 (file)
@@ -45,8 +45,8 @@ static int validate_position (int p,struct game_state_t *b)
  int white_k = 0;
  int black_k = 0;
 
-  for (f = 0; (f < 8); f++) {
-    for (r = 0; (r < 8); r++) {
+  for (f = 0; (f < b->files); f++) {
+    for (r = 0; (r < b->ranks); r++) {
       if (b->board[f][r] == W_KING) {
          white_k += 1;
          if (white_k == 2) {
@@ -62,7 +62,7 @@ static int validate_position (int p,struct game_state_t *b)
          }
       }
       if (((b->board[f][r] == W_PAWN) || (b->board[f][r] == B_PAWN)) &&
-         ((r == 0) || (r == 7))) {
+         ((r == 0) || (r == b->ranks-1))) {
          pprintf (p,"Pawns cannot be placed on the first or eighth rank.\n");
          return 0;
       }
@@ -151,17 +151,23 @@ int com_setup (int p,param_list param)
        pprintf(p,"The position is not valid - staying in setup mode.\n");
      return COM_OK;
    } else { /* try to load a category of board */
-     if (param[1].type != TYPE_NULL) { 
-       if (!board_init (pp->game,&(game_globals.garray[pp->game].game_state),param[0].val.word,param[1].val.word)) {
+     char *board = param[1].val.word;
+     if (param[1].type == TYPE_NULL) board = "0";
+     game_globals.garray[pp->game].FENstartPos[0] = 0; // [HGM] new shuffle
+       if (!board_init (pp->game,&(game_globals.garray[pp->game].game_state),param[0].val.word,board)) {
          game_globals.garray[pp->game].game_state.gameNum = gamenum;
+        if(!strcmp(board,"0"))
+           sprintf(game_globals.garray[pp->game].variant, "%s",param[0].val.word);
+         else
+           sprintf(game_globals.garray[pp->game].variant, "%s/%s",param[0].val.word,board);
          send_board_to(pp->game, p);
-         pprintf (p,"Board set up as %s %s.\n",param[0].val.word,param[1].val.word);
+         pprintf (p,"Board set up as %s %s.\n",param[0].val.word,board);
        } else {
-         pprintf (p,"Board %s %s is unavailable.\n",param[0].val.word,param[1].val.word);
+         pprintf (p,"Board %s %s is unavailable.\n",param[0].val.word,board);
          game_globals.garray[pp->game].game_state.gameNum = gamenum;
        }
        return COM_OK;
-     }
+     
    }
  }
  pprintf (p, "You have supplied an incorrect parameter to setup.\n");
@@ -302,7 +308,7 @@ int attempt_drop(int p,int g,char* dropstr)
 /*check wp@e3 */
 
  } else if (dropstr[0] == 'w') {
-   piece = CharToPiece(dropstr[1]) & 0x07;
+   piece = CharToPiece(dropstr[1], game_globals.garray[g].game_state.variant) & 0x7F;
    color = WHITE;
    getsquare(dropstr+3,&f,&r);
 
@@ -310,7 +316,7 @@ int attempt_drop(int p,int g,char* dropstr)
 
  } else  if (len == 5) { /* check length to avoid b@e2 and bb@e2 being confused */
    if (dropstr[0] == 'b') {
-     piece = CharToPiece(dropstr[1]) | BLACK;
+     piece = CharToPiece(dropstr[1], game_globals.garray[g].game_state.variant) | BLACK;
      getsquare(dropstr+3,&f,&r);
    }
 
@@ -320,7 +326,7 @@ int attempt_drop(int p,int g,char* dropstr)
    if (!((dropstr[1] == '@') || (dropstr[1] == '*')))
      return 0;
    else {
-     piece = CharToPiece(dropstr[0]);
+     piece = CharToPiece(dropstr[0], game_globals.garray[g].game_state.variant);
      getsquare(dropstr+2,&f,&r);
      }
  }
index 1016fc5..34283b5 100644 (file)
@@ -472,6 +472,19 @@ int com_kibitz(int p, param_list param)
     g = pp->game;
   else
     g = pp->observe_list[0];
+  if(pp->game == g) { // [HGM] capture engine kibitz of player
+    float score; int depth;
+    if(sscanf(param[0].val.string, "!!! %f/%d", &score, &depth) == 2) {
+      struct game *gg = &game_globals.garray[g];
+      if(gg->numHalfMoves && gg->status == GAME_ACTIVE) {
+       int n = gg->numHalfMoves-1;
+       if(n && (gg->game_state.onMove == WHITE && gg->black != p ||
+                gg->game_state.onMove == BLACK && gg->white != p   )) n--;
+       gg->moveList[n].score = score;
+       gg->moveList[n].depth = depth;
+      }
+    }
+  }
   for (p1 = 0; p1 < player_globals.p_num; p1++) {
     if ((p1 == p) || (player_globals.parray[p1].status != PLAYER_PROMPT))
       continue;
index d6245ca..d4c1da7 100644 (file)
@@ -21,7 +21,7 @@
 
 #include "includes.h"
 
-static int safestring(char *str);
+int safestring(char *str);
 
 char *eatword(char *str)
 {
@@ -362,7 +362,7 @@ static int safechar(int c)
        return (isprint(c) && !strchr(">!&*?/<|`$;", c));
 }
 
-static int safestring(char *str)
+int safestring(char *str)
 {
        int i;
 
index 487b420..0278f3e 100644 (file)
@@ -793,7 +793,7 @@ static int set_formula(int p, char *var, char *val)
 #endif
 }
 
-static var_list variables[] = {
+var_list variables[] = {
   {"ads", set_ads},
   {"availinfo", set_availinfo},
   {"availmax", set_availmax},